/* 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.controls.groups.permissions; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import nl.strohalm.cyclos.access.AdminAdminPermission; import nl.strohalm.cyclos.access.AdminMemberPermission; import nl.strohalm.cyclos.access.AdminSystemPermission; import nl.strohalm.cyclos.access.BrokerPermission; import nl.strohalm.cyclos.access.MemberPermission; import nl.strohalm.cyclos.access.Module; import nl.strohalm.cyclos.access.ModuleType; import nl.strohalm.cyclos.access.Permission; import nl.strohalm.cyclos.controls.ActionContext; import nl.strohalm.cyclos.controls.BaseFormAction; import nl.strohalm.cyclos.controls.groups.ListGroupsAction; import nl.strohalm.cyclos.entities.access.Channel; import nl.strohalm.cyclos.entities.accounts.AccountType; import nl.strohalm.cyclos.entities.accounts.SystemAccountType; import nl.strohalm.cyclos.entities.accounts.guarantees.GuaranteeType; import nl.strohalm.cyclos.entities.accounts.transactions.TransferType; import nl.strohalm.cyclos.entities.customization.documents.Document; import nl.strohalm.cyclos.entities.groups.AdminGroup; import nl.strohalm.cyclos.entities.groups.BrokerGroup; import nl.strohalm.cyclos.entities.groups.Group; import nl.strohalm.cyclos.entities.groups.MemberGroup; import nl.strohalm.cyclos.entities.members.messages.MessageCategory; import nl.strohalm.cyclos.entities.members.records.MemberRecordType; import nl.strohalm.cyclos.services.groups.AdminGroupPermissionsDTO; import nl.strohalm.cyclos.services.groups.BrokerGroupPermissionsDTO; import nl.strohalm.cyclos.services.groups.GroupPermissionsDTO; import nl.strohalm.cyclos.services.groups.MemberGroupPermissionsDTO; import nl.strohalm.cyclos.utils.ActionHelper; import nl.strohalm.cyclos.utils.access.PermissionCatalogHandler; import nl.strohalm.cyclos.utils.binding.BeanBinder; import nl.strohalm.cyclos.utils.binding.DataBinder; import nl.strohalm.cyclos.utils.binding.PropertyBinder; import nl.strohalm.cyclos.utils.binding.SimpleCollectionBinder; import nl.strohalm.cyclos.utils.conversion.PermissionConverter; import nl.strohalm.cyclos.utils.conversion.ReferenceConverter; import nl.strohalm.cyclos.utils.validation.ValidationException; import org.apache.struts.action.ActionForward; /** * Action used to edit a group's permissions * @author luis */ public class EditGroupPermissionsAction extends BaseFormAction { enum AdminAdminProperty implements PermissionCollectionProperty { createAdminRecordTypes(MemberRecordType.class), deleteAdminRecordTypes(MemberRecordType.class), modifyAdminRecordTypes(MemberRecordType.class), viewAdminRecordTypes(MemberRecordType.class); /** * The class of the collection element */ private Class<?> elementClass; private AdminAdminProperty(final Class<?> elementClass) { this.elementClass = elementClass; } @Override public String cssClassName() { return null; } @Override public String onChangeListener() { return null; } } enum AdminMemberProperty implements PermissionCollectionProperty { grantLoanTTs(TransferType.class), memberChargebackTTs(TransferType.class), systemToMemberTTs(TransferType.class), asMemberToMemberTTs(TransferType.class), asMemberToSelfTTs(TransferType.class), asMemberToSystemTTs(TransferType.class), createMemberRecordTypes(MemberRecordType.class), deleteMemberRecordTypes(MemberRecordType.class), modifyMemberRecordTypes(MemberRecordType.class), viewMemberRecordTypes(MemberRecordType.class), conversionSimulationTTs(TransferType.class), managesGroups(MemberGroup.class, "managedGroupsChanged()"); private String onChangeListener; private Class<?> elementClass; private AdminMemberProperty(final Class<?> elementClass) { this(elementClass, null); } private AdminMemberProperty(final Class<?> elementClass, final String onChangeListener) { this.onChangeListener = onChangeListener; this.elementClass = elementClass; } @Override public String cssClassName() { return null; } @Override public String onChangeListener() { return onChangeListener; } } enum AdminSystemProperty implements PermissionCollectionProperty { viewInformationOf(SystemAccountType.class, "systemAccountTypesChanged()"), systemChargebackTTs(TransferType.class), systemToSystemTTs(TransferType.class), viewConnectedAdminsOf(AdminGroup.class); private String onChangeListener; /** * The class of the collection element */ private Class<?> elementClass; private AdminSystemProperty(final Class<?> elementClass) { this(elementClass, null); } private AdminSystemProperty(final Class<?> elementClass, final String onChangeListener) { this.onChangeListener = onChangeListener; this.elementClass = elementClass; } @Override public String cssClassName() { return null; } @Override public String onChangeListener() { return onChangeListener; } } enum BrokerProperty implements PermissionCollectionProperty { brokerConversionSimulationTTs(TransferType.class), brokerDocuments(Document.class), asMemberToMemberTTs(TransferType.class), asMemberToSelfTTs(TransferType.class), asMemberToSystemTTs(TransferType.class), brokerCreateMemberRecordTypes(MemberRecordType.class), brokerDeleteMemberRecordTypes(MemberRecordType.class), brokerModifyMemberRecordTypes(MemberRecordType.class), brokerMemberRecordTypes(MemberRecordType.class), brokerCanViewInformationOf(AccountType.class); private Class<?> elementClass; private BrokerProperty(final Class<?> elementClass) { this.elementClass = elementClass; } @Override public String cssClassName() { return null; } @Override public String onChangeListener() { return null; } } enum CommonProperty implements PermissionCollectionProperty { documents(Document.class), guaranteeTypes(GuaranteeType.class), messageCategories(MessageCategory.class); /** * The class of the collection element */ private Class<?> elementClass; private CommonProperty(final Class<?> elementClass) { this.elementClass = elementClass; } @Override public String cssClassName() { return null; } @Override public String onChangeListener() { return null; } } enum MemberProperty implements PermissionCollectionProperty { canViewAdsOfGroups(Group.class), canBuyWithPaymentObligationsFromGroups(Group.class, null, "showHideIssuersPermissions()"), canIssueCertificationToGroups(Group.class, null, "showHideBuyersAndSellersPermissions()"), chargebackTTs(TransferType.class), memberToMemberTTs(TransferType.class), selfPaymentTTs(TransferType.class), memberToSystemTTs(TransferType.class), requestPaymentByChannels(Channel.class), canViewProfileOfGroups(Group.class, null, "canViewProfileOfGroupsChanged()"), canViewInformationOf(AccountType.class), conversionSimulationTTs(TransferType.class); private String cssClassName; private String onChangeListener; /** * The class of the collection element */ private Class<?> elementClass; private MemberProperty(final Class<?> elementClass) { this(elementClass, null, null); } private MemberProperty(final Class<?> elementClass, final String cssClassName, final String onChangeListener) { this.cssClassName = cssClassName; this.onChangeListener = onChangeListener; this.elementClass = elementClass; } @Override public String cssClassName() { return cssClassName; } @Override public String onChangeListener() { return onChangeListener; } } public static Map<ModuleType, List<Module>> resolveModules(final ActionContext context, final Group group) { final List<ModuleType> moduleTypes = ModuleType.getModuleTypes(group.getNature()); // Get the modules, sorted according to the translation final Map<ModuleType, List<Module>> modulesByType = new LinkedHashMap<ModuleType, List<Module>>(); for (final ModuleType moduleType : moduleTypes) { final List<Module> modules = moduleType.getModules(); Collections.sort(modules, new Comparator<Module>() { @Override public int compare(final Module o1, final Module o2) { final String label1 = context.message("permission." + o1.getValue()); final String label2 = context.message("permission." + o2.getValue()); return label1.compareTo(label2); } }); modulesByType.put(moduleType, modules); } return modulesByType; } private DataBinder<AdminGroupPermissionsDTO> adminDataBinder; private DataBinder<MemberGroupPermissionsDTO<MemberGroup>> memberDataBinder; private DataBinder<BrokerGroupPermissionsDTO> brokerDataBinder; public DataBinder<AdminGroupPermissionsDTO> getAdminDataBinder() { if (adminDataBinder == null) { final BeanBinder<AdminGroupPermissionsDTO> binder = BeanBinder.instance(AdminGroupPermissionsDTO.class); initBasic(binder); for (final AdminSystemProperty property : AdminSystemProperty.values()) { binder.registerBinder(property.name(), SimpleCollectionBinder.instance(property.elementClass, property.name())); } for (final AdminMemberProperty property : AdminMemberProperty.values()) { binder.registerBinder(property.name(), SimpleCollectionBinder.instance(property.elementClass, property.name())); } for (final AdminAdminProperty property : AdminAdminProperty.values()) { binder.registerBinder(property.name(), SimpleCollectionBinder.instance(property.elementClass, property.name())); } adminDataBinder = binder; } return adminDataBinder; } public DataBinder<BrokerGroupPermissionsDTO> getBrokerDataBinder() { if (brokerDataBinder == null) { final BeanBinder<BrokerGroupPermissionsDTO> binder = BeanBinder.instance(BrokerGroupPermissionsDTO.class); initBasic(binder); initMember(binder); for (final BrokerProperty property : BrokerProperty.values()) { binder.registerBinder(property.name(), SimpleCollectionBinder.instance(property.elementClass, property.name())); } brokerDataBinder = binder; } return brokerDataBinder; } @SuppressWarnings({ "unchecked", "rawtypes" }) public DataBinder<MemberGroupPermissionsDTO<MemberGroup>> getMemberDataBinder() { if (memberDataBinder == null) { final BeanBinder<MemberGroupPermissionsDTO<MemberGroup>> binder = (BeanBinder) BeanBinder.instance(MemberGroupPermissionsDTO.class); initBasic(binder); initMember(binder); memberDataBinder = binder; } return memberDataBinder; } @Override protected ActionForward handleSubmit(final ActionContext context) throws Exception { final EditGroupPermissionsForm form = context.getForm(); final long id = form.getGroupId(); if (id <= 0L) { throw new ValidationException(); } final Group group = groupService.load(id); GroupPermissionsDTO<?> permissions; if (group instanceof AdminGroup) { permissions = getAdminDataBinder().readFromString(form.getPermission()); } else if (group instanceof BrokerGroup) { permissions = getBrokerDataBinder().readFromString(form.getPermission()); } else if (group instanceof MemberGroup) { permissions = getMemberDataBinder().readFromString(form.getPermission()); } else { throw new ValidationException(); } groupService.setPermissions(permissions); context.sendMessage("permission.modified"); return ActionHelper.redirectWithParam(context.getRequest(), context.getSuccessForward(), "groupId", id); } @Override protected void prepareForm(final ActionContext context) throws Exception { final HttpServletRequest request = context.getRequest(); final EditGroupPermissionsForm form = context.getForm(); boolean editable = false; final long groupId = form.getGroupId(); if (groupId <= 0) { throw new ValidationException(); } final Group group = groupService.load(groupId); final PermissionCatalogHandler permissionCatalogHandler = permissionService.getPermissionCatalogHandler(group); request.setAttribute("group", group); request.setAttribute("modulesByType", resolveModules(context, group)); // Put in the request the name of permission used to manage a type of group final Map<Group.Nature, Permission> permissionByNature = ListGroupsAction.getManageGroupPermissionByNatureMap(); AdminGroup adminGroup = context.getGroup(); adminGroup = groupService.load(adminGroup.getId(), AdminGroup.Relationships.MANAGES_GROUPS); request.setAttribute("managesGroups", adminGroup.getManagesGroups()); if (permissionService.hasPermission(permissionByNature.get(group.getNature())) && (Group.Nature.ADMIN.equals(group.getNature()) || adminGroup.getManagesGroups().contains(group))) { editable = true; } request.setAttribute("editable", editable); request.setAttribute("multiValuesPermissions", createMultiValuesPermissionsMap(permissionCatalogHandler, group)); } private void addToMap(final Map<Permission, MultiValuesPermissionVO> map, final Permission permission, final PermissionCollectionProperty property, final PermissionCatalogHandler permissionCatalogHandler) { if (map.containsKey(permission)) { throw new IllegalArgumentException("Permission already added to the multivalues permissions map: " + permission); } map.put(permission, new MultiValuesPermissionVO(property, permissionCatalogHandler.currentValues(permission), permissionCatalogHandler.possibleValues(permission))); } /** * Creates a map containing all permissions which UI control is a multi drop down or a selection list * @param group * @return */ private Map<Permission, MultiValuesPermissionVO> createMultiValuesPermissionsMap(final PermissionCatalogHandler permissionCatalogHandler, final Group group) { final Map<Permission, MultiValuesPermissionVO> map = new HashMap<Permission, MultiValuesPermissionVO>(); switch (group.getNature()) { case ADMIN: addToMap(map, AdminSystemPermission.ACCOUNTS_INFORMATION, AdminSystemProperty.viewInformationOf, permissionCatalogHandler); addToMap(map, AdminSystemPermission.PAYMENTS_CHARGEBACK, AdminSystemProperty.systemChargebackTTs, permissionCatalogHandler); addToMap(map, AdminSystemPermission.PAYMENTS_PAYMENT, AdminSystemProperty.systemToSystemTTs, permissionCatalogHandler); addToMap(map, AdminSystemPermission.STATUS_VIEW_CONNECTED_ADMINS, AdminSystemProperty.viewConnectedAdminsOf, permissionCatalogHandler); addToMap(map, AdminAdminPermission.RECORDS_CREATE, AdminAdminProperty.createAdminRecordTypes, permissionCatalogHandler); addToMap(map, AdminAdminPermission.RECORDS_DELETE, AdminAdminProperty.deleteAdminRecordTypes, permissionCatalogHandler); addToMap(map, AdminAdminPermission.RECORDS_MODIFY, AdminAdminProperty.modifyAdminRecordTypes, permissionCatalogHandler); addToMap(map, AdminAdminPermission.RECORDS_VIEW, AdminAdminProperty.viewAdminRecordTypes, permissionCatalogHandler); addToMap(map, AdminMemberPermission.MEMBERS_VIEW, AdminMemberProperty.managesGroups, permissionCatalogHandler); addToMap(map, AdminMemberPermission.DOCUMENTS_DETAILS, CommonProperty.documents, permissionCatalogHandler); addToMap(map, AdminMemberPermission.GUARANTEES_REGISTER_GUARANTEES, CommonProperty.guaranteeTypes, permissionCatalogHandler); addToMap(map, AdminMemberPermission.LOANS_GRANT, AdminMemberProperty.grantLoanTTs, permissionCatalogHandler); addToMap(map, AdminMemberPermission.MESSAGES_VIEW, CommonProperty.messageCategories, permissionCatalogHandler); addToMap(map, AdminMemberPermission.PAYMENTS_CHARGEBACK, AdminMemberProperty.memberChargebackTTs, permissionCatalogHandler); addToMap(map, AdminMemberPermission.PAYMENTS_PAYMENT, AdminMemberProperty.systemToMemberTTs, permissionCatalogHandler); addToMap(map, AdminMemberPermission.PAYMENTS_PAYMENT_AS_MEMBER_TO_MEMBER, AdminMemberProperty.asMemberToMemberTTs, permissionCatalogHandler); addToMap(map, AdminMemberPermission.PAYMENTS_PAYMENT_AS_MEMBER_TO_SELF, AdminMemberProperty.asMemberToSelfTTs, permissionCatalogHandler); addToMap(map, AdminMemberPermission.PAYMENTS_PAYMENT_AS_MEMBER_TO_SYSTEM, AdminMemberProperty.asMemberToSystemTTs, permissionCatalogHandler); addToMap(map, AdminMemberPermission.RECORDS_CREATE, AdminMemberProperty.createMemberRecordTypes, permissionCatalogHandler); addToMap(map, AdminMemberPermission.RECORDS_DELETE, AdminMemberProperty.deleteMemberRecordTypes, permissionCatalogHandler); addToMap(map, AdminMemberPermission.RECORDS_MODIFY, AdminMemberProperty.modifyMemberRecordTypes, permissionCatalogHandler); addToMap(map, AdminMemberPermission.RECORDS_VIEW, AdminMemberProperty.viewMemberRecordTypes, permissionCatalogHandler); break; case BROKER: addToMap(map, BrokerPermission.DOCUMENTS_VIEW, BrokerProperty.brokerDocuments, permissionCatalogHandler); addToMap(map, BrokerPermission.MEMBER_PAYMENTS_PAYMENT_AS_MEMBER_TO_MEMBER, BrokerProperty.asMemberToMemberTTs, permissionCatalogHandler); addToMap(map, BrokerPermission.MEMBER_PAYMENTS_PAYMENT_AS_MEMBER_TO_SELF, BrokerProperty.asMemberToSelfTTs, permissionCatalogHandler); addToMap(map, BrokerPermission.MEMBER_PAYMENTS_PAYMENT_AS_MEMBER_TO_SYSTEM, BrokerProperty.asMemberToSystemTTs, permissionCatalogHandler); addToMap(map, BrokerPermission.MEMBER_RECORDS_CREATE, BrokerProperty.brokerCreateMemberRecordTypes, permissionCatalogHandler); addToMap(map, BrokerPermission.MEMBER_RECORDS_DELETE, BrokerProperty.brokerDeleteMemberRecordTypes, permissionCatalogHandler); addToMap(map, BrokerPermission.MEMBER_RECORDS_MODIFY, BrokerProperty.brokerModifyMemberRecordTypes, permissionCatalogHandler); addToMap(map, BrokerPermission.MEMBER_RECORDS_VIEW, BrokerProperty.brokerMemberRecordTypes, permissionCatalogHandler); addToMap(map, BrokerPermission.REPORTS_SHOW_ACCOUNT_INFORMATION, BrokerProperty.brokerCanViewInformationOf, permissionCatalogHandler); case MEMBER: addToMap(map, MemberPermission.ADS_VIEW, MemberProperty.canViewAdsOfGroups, permissionCatalogHandler); addToMap(map, MemberPermission.DOCUMENTS_VIEW, CommonProperty.documents, permissionCatalogHandler); addToMap(map, MemberPermission.GUARANTEES_BUY_WITH_PAYMENT_OBLIGATIONS, MemberProperty.canBuyWithPaymentObligationsFromGroups, permissionCatalogHandler); addToMap(map, MemberPermission.GUARANTEES_ISSUE_CERTIFICATIONS, MemberProperty.canIssueCertificationToGroups, permissionCatalogHandler); addToMap(map, MemberPermission.GUARANTEES_ISSUE_GUARANTEES, CommonProperty.guaranteeTypes, permissionCatalogHandler); addToMap(map, MemberPermission.MESSAGES_SEND_TO_ADMINISTRATION, CommonProperty.messageCategories, permissionCatalogHandler); addToMap(map, MemberPermission.PAYMENTS_CHARGEBACK, MemberProperty.chargebackTTs, permissionCatalogHandler); addToMap(map, MemberPermission.PAYMENTS_PAYMENT_TO_MEMBER, MemberProperty.memberToMemberTTs, permissionCatalogHandler); addToMap(map, MemberPermission.PAYMENTS_PAYMENT_TO_SELF, MemberProperty.selfPaymentTTs, permissionCatalogHandler); addToMap(map, MemberPermission.PAYMENTS_PAYMENT_TO_SYSTEM, MemberProperty.memberToSystemTTs, permissionCatalogHandler); addToMap(map, MemberPermission.PAYMENTS_REQUEST, MemberProperty.requestPaymentByChannels, permissionCatalogHandler); addToMap(map, MemberPermission.PROFILE_VIEW, MemberProperty.canViewProfileOfGroups, permissionCatalogHandler); addToMap(map, MemberPermission.REPORTS_SHOW_ACCOUNT_INFORMATION, MemberProperty.canViewInformationOf, permissionCatalogHandler); break; default: throw new IllegalArgumentException("Illegal group: " + group.getNature()); } // operatorAccounts ACCOUNTS_SIMULATE_CONVERSION que hacemos con esto???? return map; } private void initBasic(final BeanBinder<? extends GroupPermissionsDTO<?>> binder) { binder.registerBinder("group", PropertyBinder.instance(Group.class, "group", ReferenceConverter.instance(Group.class))); binder.registerBinder("operations", SimpleCollectionBinder.instance(Permission.class, "operations", PermissionConverter.instance())); for (final CommonProperty property : CommonProperty.values()) { binder.registerBinder(property.name(), SimpleCollectionBinder.instance(property.elementClass, property.name())); } } private void initMember(final BeanBinder<? extends MemberGroupPermissionsDTO<?>> binder) { for (final MemberProperty property : MemberProperty.values()) { binder.registerBinder(property.name(), SimpleCollectionBinder.instance(property.elementClass, property.name())); } } }