/*
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.accounts.pos;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import nl.strohalm.cyclos.access.AdminMemberPermission;
import nl.strohalm.cyclos.access.BrokerPermission;
import nl.strohalm.cyclos.annotations.Inject;
import nl.strohalm.cyclos.controls.ActionContext;
import nl.strohalm.cyclos.controls.BaseFormAction;
import nl.strohalm.cyclos.entities.accounts.pos.MemberPos;
import nl.strohalm.cyclos.entities.accounts.pos.MemberPos.Status;
import nl.strohalm.cyclos.entities.accounts.pos.Pos;
import nl.strohalm.cyclos.entities.accounts.pos.Pos.Relationships;
import nl.strohalm.cyclos.entities.groups.AdminGroup;
import nl.strohalm.cyclos.entities.members.Member;
import nl.strohalm.cyclos.entities.settings.LocalSettings;
import nl.strohalm.cyclos.exceptions.PermissionDeniedException;
import nl.strohalm.cyclos.services.access.exceptions.BlockedCredentialsException;
import nl.strohalm.cyclos.services.accounts.pos.MemberPosService;
import nl.strohalm.cyclos.services.accounts.pos.PosService;
import nl.strohalm.cyclos.utils.ActionHelper;
import nl.strohalm.cyclos.utils.binding.BeanBinder;
import nl.strohalm.cyclos.utils.binding.DataBinder;
import nl.strohalm.cyclos.utils.binding.PropertyBinder;
import org.apache.struts.action.ActionForward;
/**
* @author rodrigo
*/
public class EditPosAction extends BaseFormAction {
private class PosEditionPermissions {
private boolean canAssign;
private boolean canBlock;
private boolean canChangeParameters;
private boolean canChangePin;
private boolean canDiscard;
private boolean canUnassign;
private boolean canUnblock;
private boolean canUnblockPin;
private boolean editable;
private boolean isDiscarded;
public boolean isCanAssign() {
return canAssign;
}
public boolean isCanBlock() {
return canBlock;
}
public boolean isCanChangeParameters() {
return canChangeParameters;
}
public boolean isCanChangePin() {
return canChangePin;
}
public boolean isCanDiscard() {
return canDiscard;
}
public boolean isCanUnassign() {
return canUnassign;
}
public boolean isCanUnblock() {
return canUnblock;
}
public boolean isCanUnblockPin() {
return canUnblockPin;
}
public boolean isDiscarded() {
return isDiscarded;
}
public boolean isEditable() {
return editable;
}
public void setCanAssign(final boolean canAssign) {
this.canAssign = canAssign;
}
public void setCanBlock(final boolean canBlock) {
this.canBlock = canBlock;
}
public void setCanChangeParameters(final boolean canChangeParameters) {
this.canChangeParameters = canChangeParameters;
}
public void setCanChangePin(final boolean canChangePin) {
this.canChangePin = canChangePin;
}
public void setCanDiscard(final boolean canDiscard) {
this.canDiscard = canDiscard;
}
public void setCanUnassign(final boolean canUnassign) {
this.canUnassign = canUnassign;
}
public void setCanUnblock(final boolean canUnblock) {
this.canUnblock = canUnblock;
}
public void setCanUnblockPin(final boolean canUnblockPin) {
this.canUnblockPin = canUnblockPin;
}
public void setDiscarded(final boolean isDiscarded) {
this.isDiscarded = isDiscarded;
}
public void setEditable(final boolean editable) {
this.editable = editable;
}
}
private DataBinder<Pos> writeDataBinder;
private PosService posService;
private MemberPosService memberPosService;
// Used to get data and save to database
public DataBinder<Pos> getWriteDataBinder() {
if (writeDataBinder == null) {
final LocalSettings localSettings = settingsService.getLocalSettings();
final BeanBinder<MemberPos> memberPos = BeanBinder.instance(MemberPos.class, "memberPos");
memberPos.registerBinder("id", PropertyBinder.instance(Long.class, "id"));
memberPos.registerBinder("posName", PropertyBinder.instance(String.class, "posName"));
memberPos.registerBinder("member", PropertyBinder.instance(Member.class, "member"));
memberPos.registerBinder("status", PropertyBinder.instance(MemberPos.Status.class, "status"));
memberPos.registerBinder("allowMakePayment", PropertyBinder.instance(Boolean.TYPE, "allowMakePayment"));
memberPos.registerBinder("resultPageSize", PropertyBinder.instance(Integer.class, "resultPageSize"));
memberPos.registerBinder("numberOfCopies", PropertyBinder.instance(Integer.class, "numberOfCopies"));
memberPos.registerBinder("maxSchedulingPayments", PropertyBinder.instance(Integer.class, "maxSchedulingPayments"));
memberPos.registerBinder("date", PropertyBinder.instance(Calendar.class, "date", localSettings.getDateConverter()));
final BeanBinder<Pos> binder = BeanBinder.instance(Pos.class);
binder.registerBinder("posId", PropertyBinder.instance(String.class, "posId"));
binder.registerBinder("id", PropertyBinder.instance(Long.class, "id"));
binder.registerBinder("description", PropertyBinder.instance(String.class, "description"));
binder.registerBinder("status", PropertyBinder.instance(Pos.Status.class, "status"));
binder.registerBinder("memberPos", memberPos);
writeDataBinder = binder;
}
return writeDataBinder;
}
@Inject
public void setMemberPosService(final MemberPosService memberPosService) {
this.memberPosService = memberPosService;
}
@Inject
public void setPosService(final PosService posService) {
this.posService = posService;
}
@Override
protected ActionForward handleSubmit(final ActionContext context) throws Exception {
final EditPosForm form = context.getForm();
final HttpServletRequest request = context.getRequest();
final Pos pos = getWriteDataBinder().readFromString(form.getPos());
try {
final String operation = form.getOperation();
if (operation.equals("block")) {
final MemberPos persistedMemberPos = memberPosService.load(pos.getMemberPos().getId());
memberPosService.blockMemberPos(persistedMemberPos);
context.sendMessage("pos.blocked");
} else if (operation.equals("unblock")) {
final MemberPos persistedMemberPos = memberPosService.load(pos.getMemberPos().getId());
memberPosService.unblockMemberPos(persistedMemberPos);
context.sendMessage("pos.unblocked");
} else if (operation.equals("unblockPin")) {
final MemberPos persistedMemberPos = memberPosService.load(pos.getMemberPos().getId());
memberPosService.unblockPosPin(persistedMemberPos);
context.sendMessage("pos.pinUnblocked");
} else if (operation.equals("assign")) {
final Member member = elementService.load(Long.parseLong(form.getAssignTo()));
posService.assignPos(member, pos.getId());
context.sendMessage("pos.assigned", member.getUsername());
} else if (operation.equals("changePin")) {
final MemberPos persistedMemberPos = memberPosService.load(pos.getMemberPos().getId());
memberPosService.changePin(persistedMemberPos, form.getPin());
context.sendMessage("pos.pinChanged");
} else if (operation.equals("discard")) {
posService.discardPos(pos.getId());
context.sendMessage("pos.discarded");
} else if (operation.equals("unassign")) {
posService.unassignPos(pos.getId());
context.sendMessage("pos.unassigned");
} else if (operation.equals("updatePos")) {
final Pos persistedPos = posService.load(pos.getId());
boolean persistMemberPos = false;
MemberPos memberPos = null;
if (pos.getMemberPos() != null && pos.getMemberPos().getId() != null) {
// set values that hasn't changed to avoid ValidationError on Service
final MemberPos persistedMemberPos = memberPosService.load(pos.getMemberPos().getId());
memberPos = pos.getMemberPos();
memberPos.setDate(persistedMemberPos.getDate());
memberPos.setMember(persistedMemberPos.getMember());
memberPos.setStatus(persistedMemberPos.getStatus());
memberPos.setPosPin(persistedMemberPos.getPosPin());
persistMemberPos = true;
} else {
pos.setMemberPos(null);
}
// ensure this attributes doesn't change
pos.setPosId(persistedPos.getPosId());
pos.setStatus(persistedPos.getStatus());
posService.save(pos);
if (persistMemberPos) {
memberPos.setPos(pos);
memberPosService.save(memberPos);
}
context.sendMessage("pos.updated");
} else if (operation.equals("newPos")) {
pos.setMemberPos(null);
posService.save(pos);
context.sendMessage("pos.created");
}
final Map<String, Object> params = new HashMap<String, Object>();
params.put("id", pos.getId());
if (form.getMemberId() > 0) {
params.put("memberId", form.getMemberId());
}
return ActionHelper.redirectWithParams(context.getRequest(), context.getSuccessForward(), params);
} catch (final BlockedCredentialsException e) {
request.getSession().invalidate();
return context.sendError("card.updateCard.error.userBlocked");
}
}
@Override
protected void prepareForm(final ActionContext context) throws Exception {
final HttpServletRequest request = context.getRequest();
final EditPosForm form = context.getForm();
final long id = form.getId();
Pos pos;
PosEditionPermissions permissions;
boolean hasMemberPos = false;
permissions = checkPermissionsInformation(context);
final boolean isInsert = id <= 0;
if (isInsert) {
pos = new Pos();
pos.setStatus(Pos.Status.UNASSIGNED);
} else {
pos = posService.load(id, Relationships.MEMBER_POS);
hasMemberPos = pos.getMemberPos() != null;
if (hasMemberPos) {
request.setAttribute("memberLogin", pos.getMemberPos().getMember().getUsername());
request.setAttribute("userName", pos.getMemberPos().getMember().getName());
}
}
getWriteDataBinder().writeAsString(form.getPos(), pos);
// Attributes
request.setAttribute("pos", pos);
request.setAttribute("isInsert", isInsert);
request.setAttribute("hasMemberPos", hasMemberPos);
request.setAttribute("isRegularUser", !context.isAdmin() && !context.isBroker());
// Permissions
request.setAttribute("canAssign", permissions.isCanAssign());
request.setAttribute("canBlock", permissions.isCanBlock());
request.setAttribute("canChangeParameters", permissions.isCanChangeParameters());
request.setAttribute("canChangePin", permissions.isCanChangePin());
request.setAttribute("canDiscard", permissions.isCanDiscard());
request.setAttribute("canUnassign", permissions.isCanUnassign());
request.setAttribute("canUnblock", permissions.isCanUnblock());
request.setAttribute("canUnblockPin", permissions.isCanUnblockPin());
request.setAttribute("editable", permissions.isEditable());
request.setAttribute("isDiscarded", permissions.isDiscarded());
request.setAttribute("memberId", form.getMemberId());
}
@Override
protected void validateForm(final ActionContext context) {
final EditPosForm form = context.getForm();
final Pos pos = getWriteDataBinder().readFromString(form.getPos());
posService.validate(pos);
}
private PosEditionPermissions checkPermissionsInformation(final ActionContext context) {
final PosEditionPermissions permissions = new PosEditionPermissions();
final EditPosForm form = context.getForm();
Pos pos;
boolean hasMemberPos = false;
final long id = form.getId();
final boolean isInsert = id <= 0;
permissions.setEditable(permissionService.hasPermission(AdminMemberPermission.POS_MANAGE) || permissionService.hasPermission(BrokerPermission.POS_MANAGE));
if (isInsert) {
if (!context.isBroker() && !context.isAdmin()) {
throw new PermissionDeniedException();
}
} else {
pos = posService.load(id, Relationships.MEMBER_POS);
hasMemberPos = pos.getMemberPos() != null;
Member member = null;
if (hasMemberPos) {
member = pos.getMemberPos().getMember();
if (member.equals(context.getElement())) {
permissions.setEditable(true);
}
if ((!context.isBroker() && !context.isAdmin() && !member.equals(context.getElement())) || (context.isBroker() && !context.isBrokerOf(member) && !member.equals(context.getElement()))) {
throw new PermissionDeniedException();
}
if (context.isAdmin()) {
final AdminGroup group = groupService.load(context.getGroup().getId(), AdminGroup.Relationships.MANAGES_GROUPS);
if (!group.getManagesGroups().contains(pos.getMemberPos().getMember().getGroup())) {
throw new PermissionDeniedException();
}
}
} else {
if (!context.isBroker() && !context.isAdmin()) {
throw new PermissionDeniedException();
}
}
if (context.isAdmin() || (context.isBroker() && !hasMemberPos) || (context.isBroker() && hasMemberPos && !member.equals(context.getElement()))) {
final boolean isAdmin = context.isAdmin();
switch (pos.getStatus()) {
case UNASSIGNED:
permissions.setCanAssign(permissionService.hasPermission(isAdmin ? AdminMemberPermission.POS_ASSIGN : BrokerPermission.POS_ASSIGN));
break;
case ASSIGNED:
permissions.setCanUnassign(permissionService.hasPermission(isAdmin ? AdminMemberPermission.POS_ASSIGN : BrokerPermission.POS_ASSIGN));
permissions.setCanChangePin(permissionService.hasPermission(isAdmin ? AdminMemberPermission.POS_CHANGE_PIN : BrokerPermission.POS_CHANGE_PIN));
if (hasMemberPos) {
final Status status = pos.getMemberPos().getStatus();
if (status == MemberPos.Status.ACTIVE) {
permissions.setCanBlock(permissionService.hasPermission(isAdmin ? AdminMemberPermission.POS_BLOCK : BrokerPermission.POS_BLOCK));
}
if (status == MemberPos.Status.BLOCKED) {
permissions.setCanUnblock(permissionService.hasPermission(isAdmin ? AdminMemberPermission.POS_BLOCK : BrokerPermission.POS_BLOCK));
}
if (status == MemberPos.Status.PIN_BLOCKED) {
permissions.setCanUnblockPin(permissionService.hasPermission(isAdmin ? AdminMemberPermission.POS_UNBLOCK_PIN : BrokerPermission.POS_UNBLOCK_PIN));
}
}
break;
case DISCARDED:
permissions.setDiscarded(true);
break;
}
if (pos.getStatus() != Pos.Status.DISCARDED) {
permissions.setCanDiscard(permissionService.hasPermission(isAdmin ? AdminMemberPermission.POS_DISCARD : BrokerPermission.POS_DISCARD));
}
permissions.setCanChangeParameters(permissionService.hasPermission(isAdmin ? AdminMemberPermission.POS_CHANGE_PARAMETERS : BrokerPermission.POS_CHANGE_PARAMETERS));
} else if (context.isMember() && hasMemberPos && context.getElement().equals(member)) {
permissions.setCanChangeParameters(true);
final Status status = pos.getMemberPos().getStatus();
if (status == MemberPos.Status.ACTIVE) {
permissions.setCanBlock(true);
} else if (status == MemberPos.Status.BLOCKED) {
permissions.setCanUnblock(true);
} else if (status == MemberPos.Status.PIN_BLOCKED) {
permissions.setCanUnblockPin(true);
}
if (pos.getStatus().equals(Pos.Status.ASSIGNED)) {
permissions.setCanChangePin(true);
}
}
}
return permissions;
}
}