/*
jBilling - The Enterprise Open Source Billing System
Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde
This file is part of jbilling.
jbilling is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jbilling is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with jbilling. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sapienter.jbilling.server.user;
import com.sapienter.jbilling.common.JBCrypto;
import com.sapienter.jbilling.common.PermissionConstants;
import com.sapienter.jbilling.common.PermissionIdComparator;
import com.sapienter.jbilling.common.SessionInternalError;
import com.sapienter.jbilling.common.Util;
import com.sapienter.jbilling.server.invoice.db.InvoiceDAS;
import com.sapienter.jbilling.server.item.PricingField;
import com.sapienter.jbilling.server.item.db.ItemDTO;
import com.sapienter.jbilling.server.list.ResultList;
import com.sapienter.jbilling.server.notification.INotificationSessionBean;
import com.sapienter.jbilling.server.notification.MessageDTO;
import com.sapienter.jbilling.server.notification.NotificationBL;
import com.sapienter.jbilling.server.notification.NotificationNotFoundException;
import com.sapienter.jbilling.server.order.OrderBL;
import com.sapienter.jbilling.server.order.db.OrderDTO;
import com.sapienter.jbilling.server.payment.PaymentBL;
import com.sapienter.jbilling.server.payment.blacklist.db.BlacklistDAS;
import com.sapienter.jbilling.server.payment.blacklist.db.BlacklistDTO;
import com.sapienter.jbilling.server.payment.db.PaymentDAS;
import com.sapienter.jbilling.server.pluggableTask.admin.PluggableTaskManager;
import com.sapienter.jbilling.server.process.AgeingBL;
import com.sapienter.jbilling.server.user.contact.db.ContactDAS;
import com.sapienter.jbilling.server.user.contact.db.ContactDTO;
import com.sapienter.jbilling.server.user.db.AchDAS;
import com.sapienter.jbilling.server.user.db.AchDTO;
import com.sapienter.jbilling.server.user.db.CompanyDAS;
import com.sapienter.jbilling.server.user.db.CreditCardDTO;
import com.sapienter.jbilling.server.user.db.CustomerDAS;
import com.sapienter.jbilling.server.user.db.SubscriberStatusDAS;
import com.sapienter.jbilling.server.user.db.UserDAS;
import com.sapienter.jbilling.server.user.db.UserDTO;
import com.sapienter.jbilling.server.user.db.UserStatusDAS;
import com.sapienter.jbilling.server.user.partner.PartnerBL;
import com.sapienter.jbilling.server.user.permisson.db.PermissionDTO;
import com.sapienter.jbilling.server.user.permisson.db.PermissionUserDTO;
import com.sapienter.jbilling.server.user.permisson.db.RoleDAS;
import com.sapienter.jbilling.server.user.permisson.db.RoleDTO;
import com.sapienter.jbilling.server.user.tasks.IValidatePurchaseTask;
import com.sapienter.jbilling.server.util.Constants;
import com.sapienter.jbilling.server.util.Context;
import com.sapienter.jbilling.server.util.DTOFactory;
import com.sapienter.jbilling.server.util.PreferenceBL;
import com.sapienter.jbilling.server.util.audit.EventLogger;
import com.sapienter.jbilling.server.util.db.CurrencyDAS;
import com.sapienter.jbilling.server.util.db.LanguageDAS;
import org.apache.log4j.Logger;
import org.springframework.dao.EmptyResultDataAccessException;
import javax.sql.rowset.CachedRowSet;
import javax.naming.NamingException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class UserBL extends ResultList implements UserSQL {
private final static Logger LOG = Logger.getLogger(UserBL.class);
private UserDTO user = null;
private EventLogger eLogger = null;
private Integer mainRole = null;
private UserDAS das = null;
public UserBL(Integer userId) {
init();
set(userId);
}
public UserBL() {
init();
}
public UserBL(UserDTO entity) {
user = entity;
init();
}
public UserBL(String username, Integer entityId) {
init();
user = das.findByUserName(username, entityId);
}
public void set(Integer userId) {
user = das.find(userId);
}
public void set(String userName, Integer entityId) {
user = das.findByUserName(userName, entityId);
}
public void set(UserDTO user) {
this.user = user;
}
public void setRoot(String userName) {
user = das.findRoot(userName);
}
private void init() {
eLogger = EventLogger.getInstance();
das = new UserDAS();
}
/**
* @param executorId This is the user that has ordered the update
* @param dto This is the user that will be updated
*/
public void update(Integer executorId, UserDTOEx dto)
throws SessionInternalError {
// password is the only one that might've not been set
String changedPassword = dto.getPassword();
if (changedPassword != null){
//encrypt it based on the user role
changedPassword = JBCrypto.getPasswordCrypto(getMainRole()).encrypt(changedPassword);
}
if (changedPassword != null &&
!changedPassword.equals(user.getPassword())) {
eLogger.audit(executorId, dto.getId(), Constants.TABLE_BASE_USER,
user.getUserId(), EventLogger.MODULE_USER_MAINTENANCE,
EventLogger.PASSWORD_CHANGE, null, user.getPassword(),
null);
user.setPassword(changedPassword);
}
if (dto.getUserName() != null && !user.getUserName().equals(
dto.getUserName())) {
user.setUserName(dto.getUserName());
}
if (dto.getLanguageId() != null && !user.getLanguageIdField().equals(
dto.getLanguageId())) {
user.setLanguage(new LanguageDAS().find(dto.getLanguageId()));
}
if (dto.getEntityId() != null && user.getEntity().getId() !=
dto.getEntityId()) {
user.setCompany(new CompanyDAS().find(dto.getEntityId()));
}
if (dto.getStatusId() != null && user.getStatus().getId() !=
dto.getStatusId()) {
AgeingBL age = new AgeingBL();
age.setUserStatus(executorId, user.getUserId(), dto.getStatusId(),
Calendar.getInstance().getTime());
}
updateSubscriptionStatus(dto.getSubscriptionStatusId());
if (dto.getCurrencyId() != null && !user.getCurrencyId().equals(
dto.getCurrencyId())) {
user.setCurrency(new CurrencyDAS().find(dto.getCurrencyId()));
}
if (dto.getCustomer() != null) {
if (dto.getCustomer().getInvoiceDeliveryMethod() != null) {
user.getCustomer().setInvoiceDeliveryMethod(dto.getCustomer().getInvoiceDeliveryMethod());
}
user.getCustomer().setDueDateUnitId(dto.getCustomer().getDueDateUnitId());
user.getCustomer().setDueDateValue(dto.getCustomer().getDueDateValue());
user.getCustomer().setDfFm(dto.getCustomer().getDfFm());
if (dto.getCustomer().getPartner() != null) {
user.getCustomer().setPartner(dto.getCustomer().getPartner());
} else {
user.getCustomer().setPartner(null);
}
user.getCustomer().setExcludeAging(dto.getCustomer().getExcludeAging());
user.getCustomer().setBalanceType(dto.getCustomer().getBalanceType());
user.getCustomer().setCreditLimit(dto.getCustomer().getCreditLimit());
user.getCustomer().setAutoRecharge(dto.getCustomer().getAutoRecharge());
// set the sub-account fields
user.getCustomer().setIsParent(dto.getCustomer().getIsParent());
if (dto.getCustomer().getParent() != null) {
// the API accepts the user ID of the parent instead of the customer ID
user.getCustomer().setParent(new UserDAS().find(dto.getCustomer().getParent().getId()).getCustomer());
// log invoice if child changes
Integer oldInvoiceIfChild = user.getCustomer().getInvoiceChild();
user.getCustomer().setInvoiceChild(dto.getCustomer().getInvoiceChild());
eLogger.audit(executorId,
user.getId(),
Constants.TABLE_CUSTOMER,
user.getCustomer().getId(),
EventLogger.MODULE_USER_MAINTENANCE,
EventLogger.INVOICE_IF_CHILD_CHANGE,
(oldInvoiceIfChild != null ? oldInvoiceIfChild : 0),
null, null);
}
// update the main order
if (dto.getCustomer().getCurrentOrderId() != null) {
OrderBL order = new OrderBL(dto.getCustomer().getCurrentOrderId());
order.setMainSubscription(executorId);
}
}
eLogger.audit(executorId,
user.getId(),
Constants.TABLE_BASE_USER,
user.getId(),
EventLogger.MODULE_USER_MAINTENANCE,
EventLogger.ROW_UPDATED, null, null, null);
updateRoles(dto.getRoles(), dto.getMainRoleId());
}
private void updateRoles(Set<RoleDTO> theseRoles, Integer main)
throws SessionInternalError {
if (theseRoles == null || theseRoles.isEmpty()) {
if (main != null) {
if (theseRoles == null) {
theseRoles = new HashSet<RoleDTO>();
}
theseRoles.add(new RoleDTO(main));
} else {
return; // nothing to do
}
}
user.getRoles().clear();
for (RoleDTO aRole: theseRoles) {
// make sure the role is in the session
RoleDTO dbRole = new RoleDAS().find(aRole.getId());
//dbRole.getBaseUsers().add(user);
user.getRoles().add(dbRole);
}
}
public boolean exists(String userName, Integer entityId) {
if (userName == null) {
LOG.error("exists is being call with a null username");
return true;
}
if (new UserDAS().findByUserName(userName, entityId) == null) {
return false;
} else {
return true;
}
}
public Integer create(UserDTOEx dto) throws SessionInternalError {
Integer newId;
LOG.debug("Creating user " + dto);
List<Integer> roles = new ArrayList<Integer>();
if (dto.getRoles() == null || dto.getRoles().size() == 0) {
if (dto.getMainRoleId() != null) {
roles.add(dto.getMainRoleId());
} else {
LOG.warn("Creating user without any role...");
}
} else {
for (RoleDTO role: dto.getRoles()) {
roles.add(role.getId());
}
}
Integer newUserRole = dto.getMainRoleId();
JBCrypto passwordCrypter = JBCrypto.getPasswordCrypto(newUserRole);
dto.setPassword(passwordCrypter.encrypt(dto.getPassword()));
// may be this is a partner
if (dto.getPartner() != null) {
newId = create(dto.getEntityId(), dto.getUserName(), dto.getPassword(),
dto.getLanguageId(), roles, dto.getCurrencyId(),
dto.getStatusId(), dto.getSubscriptionStatusId());
PartnerBL partner = new PartnerBL();
partner.create(dto.getPartner());
user.setPartner(partner.getEntity());
partner.getEntity().setBaseUser(user);
} else if (dto.getCustomer() != null) {
// link the partner
PartnerBL partner = null;
if (dto.getCustomer().getPartner() != null) {
partner = new PartnerBL(dto.getCustomer().
getPartner().getId());
// see that this partner is valid
if (partner.getEntity().getUser().getEntity().getId() != dto.getEntityId() ||
partner.getEntity().getUser().getDeleted() == 1) {
partner = null;
}
}
newId = create(dto.getEntityId(), dto.getUserName(),
dto.getPassword(), dto.getLanguageId(),
roles, dto.getCurrencyId(),
dto.getStatusId(), dto.getSubscriptionStatusId());
user.setCustomer(new CustomerDAS().create());
user.getCustomer().setBaseUser(user);
user.getCustomer().setReferralFeePaid(dto.getCustomer().getReferralFeePaid());
if (partner != null) {
user.getCustomer().setPartner(partner.getEntity());
}
// set the sub-account fields
user.getCustomer().setIsParent(dto.getCustomer().getIsParent());
if (dto.getCustomer().getParent() != null) {
// the API accepts the user ID of the parent instead of the customer ID
user.getCustomer().setParent(new UserDAS().find(dto.getCustomer().getParent().getId()).getCustomer());
user.getCustomer().setInvoiceChild(dto.getCustomer().getInvoiceChild());
}
// set dynamic balance fields
user.getCustomer().setBalanceType(dto.getCustomer().getBalanceType());
user.getCustomer().setCreditLimit(dto.getCustomer().getCreditLimit());
user.getCustomer().setDynamicBalance(dto.getCustomer().getDynamicBalance());
user.getCustomer().setAutoRecharge(dto.getCustomer().getAutoRecharge());
//additional customer fields
user.getCustomer().setNotes(dto.getCustomer().getNotes());
user.getCustomer().setAutoPaymentType(dto.getCustomer().getAutoPaymentType());
} else { // all the rest
newId = create(dto.getEntityId(), dto.getUserName(), dto.getPassword(),
dto.getLanguageId(), roles, dto.getCurrencyId(),
dto.getStatusId(), dto.getSubscriptionStatusId());
}
LOG.debug("created user id " + newId);
return newId;
}
private Integer create(Integer entityId, String userName, String password,
Integer languageId, List<Integer> roles, Integer currencyId,
Integer statusId, Integer subscriberStatusId)
throws SessionInternalError {
// Default the language and currency to that one of the entity
if (languageId == null) {
EntityBL entity = new EntityBL(entityId);
languageId = entity.getEntity().getLanguageId();
}
if (currencyId == null) {
EntityBL entity = new EntityBL(entityId);
currencyId = entity.getEntity().getCurrencyId();
}
// default the statuses
if (statusId == null) {
statusId = UserDTOEx.STATUS_ACTIVE;
}
if (subscriberStatusId == null) {
subscriberStatusId = UserDTOEx.SUBSCRIBER_NONSUBSCRIBED;
}
UserDTO newUser = new UserDTO();
newUser.setCompany(new CompanyDAS().find(entityId));
newUser.setUserName(userName);
newUser.setPassword(password);
newUser.setLanguage(new LanguageDAS().find(languageId));
newUser.setCurrency(new CurrencyDAS().find(currencyId));
newUser.setUserStatus(new UserStatusDAS().find(statusId));
newUser.setSubscriberStatus(new SubscriberStatusDAS().find(subscriberStatusId));
newUser.setDeleted(new Integer(0));
newUser.setCreateDatetime(Calendar.getInstance().getTime());
newUser.setFailedAttempts(0);
user = das.save(newUser);
HashSet<RoleDTO> rolesDTO = new HashSet<RoleDTO>();
for (Integer roleId: roles) {
rolesDTO.add(new RoleDAS().find(roleId));
}
updateRoles(rolesDTO, null);
eLogger.auditBySystem(entityId,
user.getId(),
Constants.TABLE_BASE_USER,
user.getId(),
EventLogger.MODULE_USER_MAINTENANCE,
EventLogger.ROW_CREATED, null, null, null);
return user.getUserId();
}
@Deprecated
public boolean validateUserNamePassword(UserDTOEx loggingUser,
UserDTOEx db) {
// the user status is not part of this check, as a customer that
// can't login to the entity's service still has to be able to
// as a customer to submit a payment or update her credit card
if (db.getDeleted() == 0 &&
loggingUser.getEntityId().equals(db.getEntityId())) {
String dbPassword = db.getPassword();
String notCryptedLoggingPassword = loggingUser.getPassword();
//using service specific for DB-user, loging one may not have its role set
JBCrypto passwordCryptoService = JBCrypto.getPasswordCrypto(db.getMainRoleId());
String comparableLoggingPassword = passwordCryptoService.encrypt(notCryptedLoggingPassword);
if (comparableLoggingPassword.equals(dbPassword)){
user = getUserEntity(db.getUserId());
return true;
}
}
return false;
}
/**
* Tries to authenticate username/password for web services call.
* The user must be an administrator and have permission 120 set.
* Returns the user's UserDTO if successful, otherwise null.
*/
@Deprecated
public UserDTO webServicesAuthenticate(String username, String password) {
// try to get root user for this username that has web
// services permission
user = das.findWebServicesRoot(username);
if (user == null) {
LOG.warn("Web services authentication: Username \"" + username +
"\" is either invalid, isn't an administrator or doesn't " +
"have web services permission granted (120).");
return null;
}
// check password
JBCrypto passwordCryptoService = JBCrypto.getPasswordCrypto(
Constants.TYPE_ROOT);
String encryptedPassword = passwordCryptoService.encrypt(
password);
if (encryptedPassword.equals(user.getPassword())) {
return user;
}
LOG.warn("Web services authentication: Invlid password \"" + password +
"\" for username \"" + username + "\"");
return null;
}
public static UserDTO getUserEntity(Integer userId) {
return new UserDAS().find(userId);
}
/**
* sent the lost password to the user
* @param entityId
* @param userId
* @param languageId
* @throws SessionInternalError
* @throws NotificationNotFoundException when no message row or message row is not activated for the specified entity
*/
public void sendLostPassword(Integer entityId, Integer userId,
Integer languageId) throws SessionInternalError,
NotificationNotFoundException {
NotificationBL notif = new NotificationBL();
MessageDTO message = notif.getForgetPasswordEmailMessage(entityId, userId, languageId);
INotificationSessionBean notificationSess =
(INotificationSessionBean) Context.getBean(
Context.Name.NOTIFICATION_SESSION);
notificationSess.notify(userId, message);
}
public UserDTO getEntity() {
return user;
}
public List<PermissionDTO> getPermissions() {
List<PermissionDTO> ret = new ArrayList<PermissionDTO>();
LOG.debug("Reading permisions for user " + user.getUserId());
for (RoleDTO role: user.getRoles()) {
// now get the permissions. They come sorted from the DB
ret.addAll(role.getPermissions());
}
// now add / remove those privileges that were granted / revoked
// to this particular user
for(PermissionUserDTO permission : user.getPermissions()) {
if (permission.isGranted()) {
// see that this guy has it
if (!ret.contains(permission.getPermission())) {
// not there, add it
//LOG.debug("adding " + thisPerm.getId());
ret.add(permission.getPermission());
}
} else {
// make sure she doesn't
if (ret.contains(permission.getPermission())) {
//LOG.debug("removing " + thisPerm.getId());
ret.remove(permission.getPermission());
}
}
}
// make sure the permissions are sorted
Collections.sort(ret, new PermissionIdComparator());
return ret;
}
/**
* Sets the permissions for this user. Permissions that differ from the user's
* role will be saved as user specific permissions that override the defaults.
*
* @param grantedPermissions a set of all permissions granted to this user
*/
public void setPermissions(Set<PermissionDTO> grantedPermissions) {
Set<PermissionDTO> rolePermissions = new HashSet<PermissionDTO>();
for (RoleDTO role : user.getRoles()) {
rolePermissions.addAll(role.getPermissions());
}
Set<PermissionUserDTO> userPermissions = new HashSet<PermissionUserDTO>();
// add granted permissions
for (PermissionDTO permission : grantedPermissions) {
if (!rolePermissions.contains(permission)) {
userPermissions.add(new PermissionUserDTO(user, permission, (short) 1));
}
}
// add revoked permissions
for (PermissionDTO permission : rolePermissions) {
if (!grantedPermissions.contains(permission)) {
userPermissions.add(new PermissionUserDTO(user, permission, (short) 0));
}
}
LOG.debug("Saving " + userPermissions.size() + " overridden permissions for user " + user.getId());
user.getPermissions().clear();
user.getPermissions().addAll(userPermissions);
this.user = das.save(user);
}
public UserWS getUserWS() throws SessionInternalError {
UserDTOEx dto = DTOFactory.getUserDTOEx(user);
UserWS retValue = new UserWS(dto);
// the contact is not included in the Ex
ContactBL bl= new ContactBL();
bl.set(dto.getUserId());
if (bl.getEntity() != null) { // this user has no contact ...
retValue.setContact(new ContactWS(bl.getDTO()));
}
// some entities rather not know the credit card numbers
if (retValue.getCreditCard() != null) {
PreferenceBL pref = new PreferenceBL();
try {
pref.set(dto.getEntityId(), Constants.PREFERENCE_HIDE_CC_NUMBERS);
} catch (EmptyResultDataAccessException e) {
// the default is good for me
}
if (pref.getInt() == 1) {
String ccNumber = retValue.getCreditCard().getNumber();
if (ccNumber != null) {
retValue.getCreditCard().setNumber("************" +
ccNumber.substring(ccNumber.length()-4));
}
}
}
return retValue;
}
public Integer getMainRole() {
if (mainRole == null) {
List roleIds = new LinkedList();
for (RoleDTO nextRoleObject : user.getRoles()){
roleIds.add(nextRoleObject.getId());
}
mainRole = selectMainRole(roleIds);
}
return mainRole;
}
private static Integer selectMainRole(Collection allRoleIds){
// the main role is the smallest of them, so they have to be ordered in the
// db in ascending order (small = important);
Integer result = null;
for (Iterator roleIds = allRoleIds.iterator(); roleIds.hasNext();){
Integer nextId = (Integer)roleIds.next();
if (result == null || nextId.compareTo(result) < 0) {
result = nextId;
}
}
return result;
}
/**
* Get the locale for this user.
*
* @return users locale
*/
public Locale getLocale() {
return getLocale(user);
}
/**
* Get a locale for the given user based on their selected language and set country.
*
* This method assumes that the user is part of the current persistence context, and that
* the LanguageDTO association can safely be lazy-loaded.
*
* @param user user
* @return users locale
*/
public static Locale getLocale(UserDTO user) {
String languageCode = user.getLanguage().getCode();
ContactDTO contact = new ContactDAS().findPrimaryContact(user.getId());
String countryCode = null;
if (contact != null)
countryCode = contact.getCountryCode();
return countryCode != null ? new Locale(languageCode, countryCode) : new Locale(languageCode);
}
public Integer getCurrencyId() {
Integer retValue;
if (user.getCurrencyId() == null) {
retValue = user.getEntity().getCurrency().getId();
} else {
retValue = user.getCurrencyId();
}
return retValue;
}
/**
* Will mark the user as deleted (deleted = 1), and do the same
* with all her orders, etc ...
* Not deleted for reporting reasong: invoices, payments
*/
public void delete(Integer executorId) {
user.setDeleted(1);
user.setUserStatus(new UserStatusDAS().find(UserDTOEx.STATUS_DELETED));
user.setLastStatusChange(Calendar.getInstance().getTime());
// credit cards
for (CreditCardDTO cc: user.getCreditCards()) {
cc.setDeleted(1);
}
// orders
for (OrderDTO order: user.getOrders()) {
order.setDeleted(1);
}
// permisions
user.getPermissions().clear();
// roles
user.getRoles().clear();
if (executorId != null) {
eLogger.audit(executorId, user.getId(), Constants.TABLE_BASE_USER,
user.getUserId(), EventLogger.MODULE_USER_MAINTENANCE,
EventLogger.ROW_DELETED, null, null, null);
}
}
public UserDTO getDto() {
return user;
}
/**
*
* @return true if the user has a credit card, or fals if it doeas not
*/
public boolean hasCreditCard() {
return !user.getCreditCards().isEmpty();
}
/**
* Verifies that both user belong to the same entity.
* @param rootUserName
* This has to be a root user
* @param callerUserId
* @return
*/
public boolean validateUserBelongs(String rootUserName,
Integer callerUserId)
throws SessionInternalError {
boolean retValue;
user = das.find(callerUserId);
set(rootUserName, user.getEntity().getId());
if (user == null) {
return false;
}
if (user.getDeleted() == 1) {
throw new SessionInternalError("the caller is set as deleted");
}
if (!getMainRole().equals(Constants.TYPE_ROOT)) {
throw new SessionInternalError("can't validate but root users");
}
retValue = true;
return retValue;
}
public void updateAch(AchDTO ach, Integer executorId)
throws NamingException, SessionInternalError {
AchBL bl = new AchBL();
if (ach.getBaseUser() == null) {
ach.setBaseUser(user);
}
// let's see if this guy already has an ach record
Set<AchDTO> rows = user.getAchs();
if (rows.size() == 0) {
bl.create(ach);
rows.add(new AchDAS().find(bl.getEntity().getId()));
} else { // its an update
bl.set(((AchDTO)rows.toArray()[0]).getId());
bl.update(executorId, ach);
}
}
public static boolean validate(UserWS userWS) {
return validate(new UserDTOEx(userWS, null));
}
/**
* Validates the user info and the credit card if present
* @param dto
* @return
*/
public static boolean validate(UserDTOEx dto) {
boolean retValue = true;
if (dto == null || dto.getUserName() == null ||
dto.getPassword() == null || dto.getLanguageId() == null ||
dto.getMainRoleId() == null || dto.getStatusId() == null) {
retValue = false;
Logger.getLogger(UserBL.class).debug("invalid " + dto);
} else if (dto.getCreditCard() != null) {
retValue = CreditCardBL.validate(dto.getCreditCard());
}
return retValue;
}
public UserWS[] convertEntitiesToWS(Collection dtos)
throws SessionInternalError {
try {
UserWS[] ret = new UserWS[dtos.size()];
int index = 0;
for (Iterator it = dtos.iterator(); it.hasNext();) {
user = (UserDTO) it.next();
ret[index] = entity2WS();
index++;
}
return ret;
} catch (Exception e) {
throw new SessionInternalError(e);
}
}
public UserWS entity2WS() {
UserWS retValue = new UserWS();
retValue.setCreateDatetime(user.getCreateDatetime());
retValue.setCurrencyId(getCurrencyId());
retValue.setDeleted(user.getDeleted());
retValue.setLanguageId(user.getLanguageIdField());
retValue.setLastLogin(user.getLastLogin());
retValue.setLastStatusChange(user.getLastStatusChange());
mainRole = null;
retValue.setMainRoleId(getMainRole());
if (user.getPartner() != null) {
retValue.setPartnerId(user.getPartner().getId());
}
retValue.setPassword(user.getPassword());
retValue.setStatusId(user.getStatus().getId());
retValue.setUserId(user.getUserId());
retValue.setUserName(user.getUserName());
// now the contact
ContactBL contact = new ContactBL();
contact.set(retValue.getUserId());
retValue.setContact(new ContactWS(contact.getDTO()));
// the credit card
Collection ccs = user.getCreditCards();
if (ccs.size() > 0) {
retValue.setCreditCard(((CreditCardDTO) ccs.toArray()[0]).getOldDTO());
}
return retValue;
}
public CachedRowSet findActiveWithOpenInvoices(Integer entityId)
throws SQLException, NamingException {
prepareStatement(UserSQL.findActiveWithOpenInvoices);
cachedResults.setInt(1, entityId);
execute();
conn.close();
return cachedResults;
}
public UserTransitionResponseWS[] getUserTransitionsById(Integer entityId,
Integer last, Date to) {
try {
UserTransitionResponseWS[] result = null;
java.sql.Date toDate = null;
String query = UserSQL.findUserTransitions;
if (last.intValue() > 0) {
query += UserSQL.findUserTransitionsByIdSuffix;
}
if (to != null) {
query += UserSQL.findUserTransitionsUpperDateSuffix;
toDate = new java.sql.Date(to.getTime());
}
int pos = 2;
LOG.info("Getting transaction list by Id. query --> " + query);
prepareStatement(query);
cachedResults.setInt(1, entityId);
if (last.intValue() > 0) {
cachedResults.setInt(pos, last);
pos++;
}
if (toDate != null) {
cachedResults.setDate(pos, toDate);
}
execute();
conn.close();
if (cachedResults == null || !cachedResults.next()) {
return null;
}
// Load the results into a linked list.
List tempList = new LinkedList();
UserTransitionResponseWS temp;
do {
temp = new UserTransitionResponseWS();
temp.setId(cachedResults.getInt(1));
temp.setToStatusId(Integer.parseInt(cachedResults.getString(2)));
temp.setTransitionDate(new Date(cachedResults.getDate(3).getTime()));
temp.setUserId(cachedResults.getInt(5));
temp.setFromStatusId(cachedResults.getInt(4));
tempList.add(temp);
} while (cachedResults.next());
// The list is now ready. Convert into an array and return.
result = new UserTransitionResponseWS[tempList.size()];
int count = 0;
for (Iterator i = tempList.iterator(); i.hasNext();) {
result[count] = (UserTransitionResponseWS) i.next();
count++;
}
return result;
} catch (SQLException e) {
throw new SessionInternalError("Getting transitions", UserBL.class, e);
}
}
public BigDecimal getBalance(Integer userId) {
return new InvoiceDAS().findTotalBalanceByUser(userId).subtract(
new PaymentDAS().findTotalBalanceByUser(userId));
}
public BigDecimal getTotalOwed(Integer userId) {
return new InvoiceDAS().findTotalAmountOwed(userId);
}
public UserTransitionResponseWS[] getUserTransitionsByDate(Integer entityId,
Date from, Date to) {
try {
UserTransitionResponseWS[] result = null;
java.sql.Date toDate = null;
String query = UserSQL.findUserTransitions;
query += UserSQL.findUserTransitionsByDateSuffix;
if (to != null) {
query += UserSQL.findUserTransitionsUpperDateSuffix;
toDate = new java.sql.Date(to.getTime());
}
LOG.info("Getting transaction list by date. query --> " + query);
prepareStatement(query);
cachedResults.setInt(1, entityId);
cachedResults.setDate(2, new java.sql.Date(from.getTime()));
if (toDate != null) {
cachedResults.setDate(3, toDate);
}
execute();
conn.close();
if (cachedResults == null || !cachedResults.next()) {
return null;
}
// Load the results into a linked list.
List tempList = new LinkedList();
UserTransitionResponseWS temp;
do {
temp = new UserTransitionResponseWS();
temp.setId(cachedResults.getInt(1));
temp.setToStatusId(Integer.parseInt(cachedResults.getString(2)));
temp.setTransitionDate(new Date(cachedResults.getDate(3).getTime()));
temp.setUserId(cachedResults.getInt(5));
temp.setFromStatusId(cachedResults.getInt(4));
tempList.add(temp);
} while (cachedResults.next());
// The list is now ready. Convert into an array and return.
result = new UserTransitionResponseWS[tempList.size()];
int count = 0;
for (Iterator i = tempList.iterator(); i.hasNext();) {
result[count] = (UserTransitionResponseWS) i.next();
count++;
}
return result;
} catch (SQLException e) {
throw new SessionInternalError("Finding transitions", UserBL.class, e);
}
}
public void updateSubscriptionStatus(Integer id) {
if (id == null || user.getSubscriberStatus().getId() == id) {
// no update ... it's already there
return;
}
eLogger.auditBySystem(user.getEntity().getId(), user.getId(),
Constants.TABLE_BASE_USER, user.getUserId(),
EventLogger.MODULE_USER_MAINTENANCE,
EventLogger.SUBSCRIPTION_STATUS_CHANGE,
user.getSubscriberStatus().getId(), id.toString(), null);
try {
user.setSubscriberStatus(new SubscriberStatusDAS().find(id));
} catch (Exception e) {
throw new SessionInternalError("Can't update a user subscription status",
UserBL.class, e);
}
// make sure this is in synch with the ageing status of the user
try {
PreferenceBL link = new PreferenceBL();
try {
link.set(user.getEntity().getId(),
Constants.PREFERENCE_LINK_AGEING_TO_SUBSCRIPTION);
} catch (EmptyResultDataAccessException e) {
// i'll use the default
}
if (link.getInt() == 1) {
AgeingBL ageing = new AgeingBL();
if (id.equals(UserDTOEx.SUBSCRIBER_ACTIVE)) {
ageing.setUserStatus(null, user.getUserId(), UserDTOEx.STATUS_ACTIVE,
Calendar.getInstance().getTime());
} else if (id.equals(UserDTOEx.SUBSCRIBER_EXPIRED) ||
id.equals(UserDTOEx.SUBSCRIBER_DISCONTINUED)) {
ageing.setUserStatus(null, user.getUserId(), UserDTOEx.STATUS_SUSPENDED,
Calendar.getInstance().getTime());
}
}
} catch (Exception e) {
throw new SessionInternalError("Can't update a user status",
UserBL.class, e);
}
LOG.debug("Subscription status updated to " + id);
}
// todo: should be moved into a scheduled task that expires passwords and sets a flag on the user
@Deprecated
public boolean isPasswordExpired() {
boolean retValue = false;
try {
int expirationDays;
PreferenceBL pref = new PreferenceBL();
try {
pref.set(user.getEntity().getId(), Constants.PREFERENCE_PASSWORD_EXPIRATION);
expirationDays = pref.getInt();
} catch (EmptyResultDataAccessException e) {
expirationDays = pref.getInt();
}
// zero means that this is not enforced
if (expirationDays == 0) {
return false;
}
prepareStatement(UserSQL.lastPasswordChange);
cachedResults.setInt(1, user.getUserId());
execute();
cachedResults.next();
Date lastChange = cachedResults.getDate(1);
// no changes? then take when the user signed-up
if (lastChange == null) {
lastChange = user.getCreateDatetime();
}
conn.close();
long days = (Calendar.getInstance().getTimeInMillis() -
lastChange.getTime()) / (1000 * 60 * 60 * 24);
if (days >= expirationDays) {
retValue = true;
}
} catch (Exception e) {
throw new SessionInternalError(e);
}
return retValue;
}
/**
* Call this method when the user has provided the wrong password
* @return
* True if the account is now locked (maximum retries) or false if it is not locked.
*/
public boolean failedLoginAttempt() {
boolean retValue = false;
int allowedRetries;
PreferenceBL pref = new PreferenceBL();
try {
pref.set(user.getEntity().getId(), Constants.PREFERENCE_FAILED_LOGINS_LOCKOUT);
allowedRetries = pref.getInt();
} catch (EmptyResultDataAccessException e) {
allowedRetries = pref.getInt();
}
// zero means not to enforce this rule
if (allowedRetries > 0) {
int total = user.getFailedAttempts();
total ++;
user.setFailedAttempts(total);
if (total >= allowedRetries) {
retValue = true;
// lock out the user
JBCrypto passwordCryptoService = JBCrypto.getPasswordCrypto(getMainRole());
String newPassword = passwordCryptoService.encrypt(Util.getSysProp("lockout_password"));
user.setPassword(newPassword);
eLogger.auditBySystem(user.getEntity().getId(), user.getId(),
Constants.TABLE_BASE_USER, user.getUserId(),
EventLogger.MODULE_USER_MAINTENANCE,
EventLogger.ACCOUNT_LOCKED, new Integer(total),
null, null);
LOG.debug("Locked account for user " + user.getUserId());
}
}
return retValue;
}
public void successLoginAttempt() {
user.setLastLogin(Calendar.getInstance().getTime());
user.setFailedAttempts(0);
}
public boolean canInvoice() {
// can't be deleted and has to be a customer
if (user.getDeleted() == 1 ||
!getMainRole().equals(Constants.TYPE_CUSTOMER)) {
return false;
}
// child accounts only get invoiced if the exlicit flag is on
if (user.getCustomer().getParent() != null &&
(user.getCustomer().getInvoiceChild() == null ||
user.getCustomer().getInvoiceChild().intValue() == 0)) {
return false;
}
return true;
}
/**
* Checks if the user has been invoiced for anything at the time given
* as a parameter.
* @return
*/
public boolean isCurrentlySubscribed(Date forDate) {
List<Integer> results = new InvoiceDAS().findIdsByUserAndPeriodDate(user.getUserId(), forDate);
boolean retValue = !results.isEmpty();
LOG.debug(" user " + user.getUserId() + " is subscribed result " + retValue);
return retValue;
}
public CachedRowSet getByStatus(Integer entityId, Integer statusId, boolean in) {
try {
if (in) {
prepareStatement(UserSQL.findInStatus);
} else {
prepareStatement(UserSQL.findNotInStatus);
}
cachedResults.setInt(1, statusId.intValue());
cachedResults.setInt(2, entityId.intValue());
execute();
conn.close();
return cachedResults;
} catch (Exception e) {
throw new SessionInternalError("Error getting user by status", UserBL.class, e);
}
}
public CachedRowSet getByCustomField(Integer entityId, Integer typeId, String content) {
try {
prepareStatement(UserSQL.findByCustomField);
cachedResults.setInt(1, typeId);
cachedResults.setInt(2, entityId);
cachedResults.setString(3, content);
execute();
conn.close();
return cachedResults;
} catch (Exception e) {
throw new SessionInternalError("Error getting user by status", UserBL.class, e);
}
}
/**
* Returns a rowset of customer IDs with a matching custom contact field. This method
* is essentially the same as {@link #getByCustomField(Integer, Integer, String)} except
* that the underlying SQL query uses "like" instead of equals allowing wildcards to be used.
*
* @param entityId entity id
* @param typeId custom contact field type id
* @param content where custom contact field content is like
* @return rowset of user IDs
*/
public CachedRowSet getByCustomFieldLike(Integer entityId, Integer typeId, String content) {
try {
prepareStatement(UserSQL.findByCustomFieldLike);
cachedResults.setInt(1, typeId);
cachedResults.setInt(2, entityId);
cachedResults.setString(3, content);
execute();
conn.close();
return cachedResults;
} catch (Exception e) {
throw new SessionInternalError("Error getting user by status", UserBL.class, e);
}
}
public CachedRowSet getByCCNumber(Integer entityId, String number) {
try {
prepareStatement(UserSQL.findByCreditCard);
cachedResults.setString(1, number);
cachedResults.setInt(2, entityId.intValue());
execute();
conn.close();
return cachedResults;
} catch (Exception e) {
throw new SessionInternalError("Error getting user by cc", UserBL.class, e);
}
}
public CreditCardDTO getCreditCard() {
if (user.getCreditCards().isEmpty()) {
return null;
} else {
return (CreditCardDTO) user.getCreditCards().toArray()[0];
}
}
public Integer getByEmail(String email) {
try {
Integer retValue = null;
prepareStatement(UserSQL.findByEmail);
// this is being use for paypal subscriptions. It only has an email
// so there is not way to limit by entity_id
cachedResults.setString(1, email);
execute();
if (cachedResults.next()) {
retValue = cachedResults.getInt(1);
}
cachedResults.close();
conn.close();
return retValue;
} catch (Exception e) {
throw new SessionInternalError("Error getting user by cc", UserBL.class, e);
}
}
/**
* Only needed due to the locking of entity beans.
* Remove when using JPA
* @param userId
* @return
* @throws SQLException
* @throws NamingException
*/
public Integer getEntityId(Integer userId) {
if (userId == null) {
userId = user.getUserId();
}
UserDTO user = das.find(userId);
return user.getCompany().getId();
}
/**
* Adds/removes blacklist entries directly related to this user.
*/
public void setUserBlacklisted(Integer executorId, Boolean isBlacklisted) {
BlacklistDAS blacklistDAS = new BlacklistDAS();
List<BlacklistDTO> blacklist = blacklistDAS.findByUserType(
user.getId(), BlacklistDTO.TYPE_USER_ID);
if (isBlacklisted) {
if (blacklist.isEmpty()) {
// add a new blacklist entry
LOG.debug("Adding blacklist record for user id: " +
user.getId());
BlacklistDTO entry = new BlacklistDTO();
entry.setCompany(user.getCompany());
entry.setCreateDate(new Date());
entry.setType(BlacklistDTO.TYPE_USER_ID);
entry.setSource(BlacklistDTO.SOURCE_CUSTOMER_SERVICE);
entry.setUser(user);
entry = blacklistDAS.save(entry);
eLogger.audit(executorId, user.getId(),
Constants.TABLE_BLACKLIST, entry.getId(),
EventLogger.MODULE_BLACKLIST,
EventLogger.BLACKLIST_USER_ID_ADDED, null, null, null);
}
} else {
if (!blacklist.isEmpty()) {
// remove any blacklist entries found
LOG.debug("Removing blacklist records for user id: " +
user.getId());
for (BlacklistDTO entry : blacklist) {
blacklistDAS.delete(entry);
eLogger.audit(executorId, user.getId(),
Constants.TABLE_BLACKLIST, entry.getId(),
EventLogger.MODULE_BLACKLIST,
EventLogger.BLACKLIST_USER_ID_REMOVED, null,
null, null);
}
}
}
}
public ValidatePurchaseWS validatePurchase(List<ItemDTO> items,
List<BigDecimal> amounts,
List<List<PricingField>> pricingFields) {
if (user.getCustomer() == null) {
return null;
}
LOG.debug("validating purchase items:" + Arrays.toString(items.toArray()) +
" amounts " + amounts + " customer " + user.getCustomer());
ValidatePurchaseWS result = new ValidatePurchaseWS();
// call plug-ins
try {
PluggableTaskManager<IValidatePurchaseTask> taskManager =
new PluggableTaskManager<IValidatePurchaseTask>(
user.getCompany().getId(),
Constants.PLUGGABLE_TASK_VALIDATE_PURCHASE);
IValidatePurchaseTask myTask = taskManager.getNextClass();
while(myTask != null) {
myTask.validate(user.getCustomer(), items, amounts, result,
pricingFields);
myTask = taskManager.getNextClass();
}
} catch (Exception e) {
// log stacktrace
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.close();
LOG.error("Validate Purchase error: " + e.getMessage() + "\n" +
sw.toString());
result.setSuccess(false);
result.setAuthorized(false);
result.setQuantity(BigDecimal.ZERO);
result.setMessage(new String[] { "Error: " + e.getMessage() } );
}
return result;
}
public Integer getLanguage() {
return user.getLanguageIdField();
}
}