/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Cyclos 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.services.preferences; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.Iterator; import java.util.List; import java.util.Set; import nl.strohalm.cyclos.access.MemberPermission; import nl.strohalm.cyclos.access.Module; import nl.strohalm.cyclos.dao.members.AdminNotificationPreferenceDAO; import nl.strohalm.cyclos.dao.members.NotificationPreferenceDAO; import nl.strohalm.cyclos.dao.members.brokerings.DefaultBrokerCommissionDAO; import nl.strohalm.cyclos.entities.Relationship; import nl.strohalm.cyclos.entities.access.Channel; import nl.strohalm.cyclos.entities.accounts.Account; import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException; import nl.strohalm.cyclos.entities.groups.Group; import nl.strohalm.cyclos.entities.groups.MemberGroup; import nl.strohalm.cyclos.entities.members.Administrator; import nl.strohalm.cyclos.entities.members.Element; import nl.strohalm.cyclos.entities.members.Member; import nl.strohalm.cyclos.entities.members.Reference.Nature; import nl.strohalm.cyclos.entities.members.brokerings.DefaultBrokerCommission; import nl.strohalm.cyclos.entities.members.messages.Message; import nl.strohalm.cyclos.entities.members.messages.Message.Type; import nl.strohalm.cyclos.entities.members.preferences.AdminNotificationPreference; import nl.strohalm.cyclos.entities.members.preferences.AdminNotificationPreferenceQuery; import nl.strohalm.cyclos.entities.members.preferences.NotificationPreference; import nl.strohalm.cyclos.entities.sms.MemberSmsStatus; import nl.strohalm.cyclos.services.accounts.AccountServiceLocal; import nl.strohalm.cyclos.services.accounts.guarantees.GuaranteeServiceLocal; import nl.strohalm.cyclos.services.accounts.guarantees.GuaranteeTypeServiceLocal; import nl.strohalm.cyclos.services.elements.MemberServiceLocal; import nl.strohalm.cyclos.services.elements.ReferenceServiceLocal; import nl.strohalm.cyclos.services.fetch.FetchServiceLocal; import nl.strohalm.cyclos.services.permissions.PermissionServiceLocal; import nl.strohalm.cyclos.utils.RelationshipHelper; import nl.strohalm.cyclos.utils.TransactionHelper; import nl.strohalm.cyclos.utils.Transactional; import nl.strohalm.cyclos.utils.access.LoggedUser; import org.springframework.transaction.TransactionStatus; /** * Service implementation for broker default commissions and notification preferences * @author jeancarlo * @author Jefferson Magno */ public class PreferenceServiceImpl implements PreferenceServiceLocal { private TransactionHelper transactionHelper; private AdminNotificationPreferenceDAO adminNotificationPreferenceDao; private DefaultBrokerCommissionDAO defaultBrokerCommissionDao; private FetchServiceLocal fetchService; private NotificationPreferenceDAO notificationPreferenceDao; private AccountServiceLocal accountService; private MemberServiceLocal memberService; private ReferenceServiceLocal referenceService; private GuaranteeServiceLocal guaranteeService; private GuaranteeTypeServiceLocal guaranteeTypeService; private PermissionServiceLocal permissionService; @Override public MemberSmsStatus getMemberSmsStatus(final Member member) { return memberService.getSmsStatus(member, false); } @Override public List<Administrator> listAdminsForNotification(final AdminNotificationPreferenceQuery query) { return adminNotificationPreferenceDao.searchAdmins(query); } @Override public List<Type> listNotificationTypes(final Member member) { final List<Message.Type> types = new ArrayList<Message.Type>(Arrays.asList(Message.Type.values())); final Iterator<Message.Type> iterator = types.iterator(); while (iterator.hasNext()) { final Message.Type type = iterator.next(); // Check if the type should be removed if (!useType(type, member)) { iterator.remove(); continue; } } return types; } @Override public AdminNotificationPreference load(final Administrator admin, final Relationship... fetch) { return adminNotificationPreferenceDao.load(admin, fetch); } @Override public Collection<NotificationPreference> load(final Member member) { return notificationPreferenceDao.load(member); } public List<DefaultBrokerCommission> load(final Member broker, final Relationship... fetch) { return defaultBrokerCommissionDao.load(broker, fetch); } @Override public NotificationPreference load(final Member member, final Type type) { final Collection<NotificationPreference> preferences = load(member); for (final NotificationPreference preference : preferences) { if (preference.getType() == type) { return preference; } } return null; } @Override public Set<MessageChannel> receivedChannels(final Member member, final Type type) { try { final NotificationPreference preference = notificationPreferenceDao.load(member, type); final EnumSet<MessageChannel> channels = EnumSet.noneOf(MessageChannel.class); if (preference.isEmail()) { channels.add(MessageChannel.EMAIL); } if (preference.isMessage()) { channels.add(MessageChannel.MESSAGE); } if (preference.isSms()) { channels.add(MessageChannel.SMS); } return channels; } catch (final EntityNotFoundException e) { return Collections.emptySet(); } } @Override public boolean receivesMessage(final Member member, final Message.Type type) { try { final NotificationPreference preference = notificationPreferenceDao.load(member, type); return preference.isEmail() || preference.isMessage() || preference.isSms(); } catch (final EntityNotFoundException e) { return false; } } @Override public AdminNotificationPreference save(final AdminNotificationPreference preference) { final Administrator loggedAdmin = LoggedUser.element(); preference.setAdmin(loggedAdmin); try { final AdminNotificationPreference current = load(loggedAdmin); preference.setId(current.getId()); return adminNotificationPreferenceDao.update(preference); } catch (final EntityNotFoundException e) { return adminNotificationPreferenceDao.insert(preference); } } @Override public void save(Member member, final Collection<NotificationPreference> prefs) { member = fetchService.fetch(member, RelationshipHelper.nested(Element.Relationships.GROUP, MemberGroup.Relationships.SMS_MESSAGES)); final Collection<Type> smsMessages = member.getMemberGroup().getSmsMessages(); for (final NotificationPreference preference : prefs) { // If SMS is not enabled for this message type (group setting), disable it if (preference.isSms() && !smsMessages.contains(preference.getType())) { preference.setSms(false); } preference.setMember(member); save(preference); } } @Override public MemberSmsStatus saveSmsStatusPreferences(final Member member, final boolean isAcceptFreeMailing, final boolean isAcceptPaidMailing, final boolean isAllowChargingSms, final boolean hasNotificationsBySms) { return transactionHelper.runInNewTransaction(new Transactional<MemberSmsStatus>() { @Override public MemberSmsStatus afterCommit(final MemberSmsStatus result) { return fetchService.fetch(result); } @Override public MemberSmsStatus doInTransaction(final TransactionStatus status) { final MemberSmsStatus memberSmsStatus = memberService.getSmsStatus(member, true); memberSmsStatus.setAcceptFreeMailing(isAcceptFreeMailing); memberSmsStatus.setAcceptPaidMailing(isAcceptPaidMailing); memberSmsStatus.setAllowChargingSms(isAllowChargingSms); memberService.ensureAllowChargingSms(memberSmsStatus, hasNotificationsBySms); return memberService.updateSmsStatus(memberSmsStatus); } }); } public void setAccountServiceLocal(final AccountServiceLocal accountService) { this.accountService = accountService; } public void setAdminNotificationPreferenceDao(final AdminNotificationPreferenceDAO adminNotificationPreferenceDao) { this.adminNotificationPreferenceDao = adminNotificationPreferenceDao; } public void setDefaultBrokerCommissionDao(final DefaultBrokerCommissionDAO brokerPreferenceDao) { defaultBrokerCommissionDao = brokerPreferenceDao; } public void setFetchServiceLocal(final FetchServiceLocal fetchService) { this.fetchService = fetchService; } public void setGuaranteeServiceLocal(final GuaranteeServiceLocal guaranteeService) { this.guaranteeService = guaranteeService; } public void setGuaranteeTypeServiceLocal(final GuaranteeTypeServiceLocal guaranteeTypeService) { this.guaranteeTypeService = guaranteeTypeService; } public void setMemberServiceLocal(final MemberServiceLocal memberService) { this.memberService = memberService; } public void setNotificationPreferenceDao(final NotificationPreferenceDAO notificationPreferenceDAO) { notificationPreferenceDao = notificationPreferenceDAO; } public void setPermissionServiceLocal(final PermissionServiceLocal permissionService) { this.permissionService = permissionService; } public void setReferenceServiceLocal(final ReferenceServiceLocal referenceService) { this.referenceService = referenceService; } public void setTransactionHelper(final TransactionHelper transactionHelper) { this.transactionHelper = transactionHelper; } private NotificationPreference save(NotificationPreference notificationPreference) { if (notificationPreference.isTransient()) { notificationPreference = notificationPreferenceDao.insert(notificationPreference); } else { notificationPreference = notificationPreferenceDao.update(notificationPreference); } return notificationPreference; } /** * Checks if a given type will be used for the member */ private boolean useType(final Message.Type type, final Member member) { final MemberGroup group = member.getMemberGroup(); boolean useType; switch (type) { case ACCOUNT: final List<? extends Account> accounts = accountService.getAccounts(member); useType = !accounts.isEmpty(); break; case AD_EXPIRATION: useType = permissionService.hasPermission(group, MemberPermission.ADS_PUBLISH); break; case AD_INTEREST: useType = permissionService.hasPermission(group, MemberPermission.PREFERENCES_MANAGE_AD_INTERESTS); break; case BROKERING: useType = member.getGroup().getNature() == Group.Nature.BROKER || member.getBroker() != null; break; case FROM_MEMBER: useType = permissionService.hasPermission(group, MemberPermission.PROFILE_VIEW); break; case INVOICE: useType = permissionService.hasPermission(group, MemberPermission.INVOICES_VIEW); break; case LOAN: useType = permissionService.hasPermission(group, MemberPermission.LOANS_VIEW); break; case PAYMENT: useType = permissionService.hasPermission(group, Module.MEMBER_PAYMENTS); break; case EXTERNAL_PAYMENT: useType = false; // External payment notifications will be enabled when the member has access to non-builtin channels for (final Channel channel : group.getChannels()) { if (Channel.listBuiltin().contains(channel.getInternalName())) { useType = true; break; } } break; case REFERENCE: useType = permissionService.hasPermission(group, MemberPermission.REFERENCES_VIEW); break; case TRANSACTION_FEEDBACK: final Collection<Nature> referenceNatures = referenceService.getNaturesByGroup(member.getMemberGroup()); useType = referenceNatures.contains(Nature.TRANSACTION); break; case CERTIFICATION: useType = guaranteeService.isBuyer() || permissionService.hasPermission(group, MemberPermission.GUARANTEES_ISSUE_CERTIFICATIONS); break; case GUARANTEE: // every member could have a guarantee, only check if there are some GT defined useType = guaranteeTypeService.areEnabledGuaranteeTypes(); break; case PAYMENT_OBLIGATION: useType = guaranteeService.isBuyer() || guaranteeService.isSeller(); break; default: useType = true; break; } return useType; } }