/* 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.webshop; import java.util.concurrent.Callable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import nl.strohalm.cyclos.annotations.Inject; import nl.strohalm.cyclos.controls.ActionContext; import nl.strohalm.cyclos.controls.BasePublicFormAction; import nl.strohalm.cyclos.entities.access.Channel; import nl.strohalm.cyclos.entities.access.Channel.Credentials; import nl.strohalm.cyclos.entities.accounts.transactions.Payment; import nl.strohalm.cyclos.entities.accounts.transactions.TransferType; import nl.strohalm.cyclos.entities.accounts.transactions.WebShopTicket; import nl.strohalm.cyclos.entities.exceptions.UnexpectedEntityException; import nl.strohalm.cyclos.entities.members.Element; import nl.strohalm.cyclos.entities.members.Member; import nl.strohalm.cyclos.services.access.AccessService; import nl.strohalm.cyclos.services.access.ChannelService; import nl.strohalm.cyclos.services.access.exceptions.BlockedCredentialsException; import nl.strohalm.cyclos.services.access.exceptions.InvalidCredentialsException; import nl.strohalm.cyclos.services.elements.ElementService; import nl.strohalm.cyclos.services.transactions.DoPaymentDTO; import nl.strohalm.cyclos.services.transactions.PaymentService; import nl.strohalm.cyclos.services.transactions.TicketService; import nl.strohalm.cyclos.services.transactions.exceptions.CreditsException; import nl.strohalm.cyclos.services.transfertypes.TransactionFeePreviewDTO; import nl.strohalm.cyclos.services.transfertypes.TransactionFeeService; import nl.strohalm.cyclos.services.transfertypes.TransferTypeService; import nl.strohalm.cyclos.utils.MessageHelper; import nl.strohalm.cyclos.utils.access.LoggedUser; import nl.strohalm.cyclos.utils.validation.RequiredError; import nl.strohalm.cyclos.utils.validation.ValidationException; import org.apache.commons.lang.StringUtils; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; /** * Action used to confirm a * * @author luis */ public class ConfirmWebShopPaymentAction extends BasePublicFormAction { public static class ShouldValidateTPParameter { public final ActionMapping mapping; public final ActionForm actionForm; public final HttpServletRequest request; public final HttpServletResponse response; public final DoPaymentDTO payment; public final ChannelService channelService; public final ElementService elementService; public final TransferTypeService transferTypeService; public final MessageHelper messageHelper; public ShouldValidateTPParameter(final ActionMapping mapping, final ActionForm actionForm, final HttpServletRequest request, final HttpServletResponse response, final DoPaymentDTO payment, final ChannelService channelService, final ElementService elementService, final TransferTypeService transferTypeService, final MessageHelper messageHelper) { this.mapping = mapping; this.actionForm = actionForm; this.request = request; this.response = response; this.payment = payment; this.channelService = channelService; this.elementService = elementService; this.transferTypeService = transferTypeService; this.messageHelper = messageHelper; } } private static boolean doShouldValidateTransactionPassword(final ShouldValidateTPParameter parameter) { final Channel channel = parameter.channelService.loadByInternalName(Channel.WEBSHOP); // Transaction password is only validated on default credentials if (channel.getCredentials() != Credentials.DEFAULT) { return false; } final Member member = parameter.elementService.load(((Member) parameter.payment.getFrom()).getId(), Element.Relationships.USER); final ActionContext context = new ActionContext(parameter.mapping, parameter.actionForm, parameter.request, parameter.response, member.getUser(), parameter.messageHelper); final TransferType transferType = parameter.transferTypeService.load(parameter.payment.getTransferType().getId(), TransferType.Relationships.FROM); return context.isTransactionPasswordEnabled(transferType.getFrom()); } static boolean shouldValidateTransactionPassword(final ShouldValidateTPParameter parameter) { return LoggedUser.runAsSystem(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return doShouldValidateTransactionPassword(parameter); } }); } private AccessService accessService; private ChannelService channelService; private PaymentService paymentService; private TransactionFeeService transactionFeeService; private TransferTypeService transferTypeService; private TicketService ticketService; @Inject public void setAccessService(final AccessService accessService) { this.accessService = accessService; } @Inject public void setChannelService(final ChannelService channelService) { this.channelService = channelService; } @Inject public void setPaymentService(final PaymentService paymentService) { this.paymentService = paymentService; } @Inject public void setTicketService(final TicketService ticketService) { this.ticketService = ticketService; } @Inject public void setTransactionFeeService(final TransactionFeeService transactionFeeService) { this.transactionFeeService = transactionFeeService; } @Inject public void setTransferTypeService(final TransferTypeService transferTypeService) { this.transferTypeService = transferTypeService; } @Override protected ActionForward handleSubmit(final ActionMapping mapping, final ActionForm actionForm, final HttpServletRequest request, final HttpServletResponse response) { final ConfirmWebShopPaymentForm form = (ConfirmWebShopPaymentForm) actionForm; final DoPaymentDTO paymentDTO = resolvePayment(request); final Member from = (Member) paymentDTO.getFrom(); final HttpSession session = request.getSession(); session.setAttribute("errorReturnTo", "/do/webshop/confirmPayment"); // We must fool the model layer, pretending that there is a logged user return LoggedUser.runAs(from.getUser(), request.getRemoteAddr(), new Callable<ActionForward>() { @Override public ActionForward call() throws Exception { try { // Check for transaction password if (shouldValidateTransactionPassword(new ShouldValidateTPParameter(mapping, actionForm, request, response, paymentDTO, channelService, elementService, transferTypeService, messageHelper))) { accessService.checkTransactionPassword(form.getTransactionPassword()); } } catch (final InvalidCredentialsException e) { throw new ValidationException("transactionPassword.error.invalid"); } catch (final BlockedCredentialsException e) { cancelTicket(request, paymentDTO); throw new ValidationException("transactionPassword.error.blockedByTrials"); } // Perform the actual payment Payment payment; try { payment = paymentService.doPayment(paymentDTO); // Store the payment on the session WebShopHelper.setPerformedPayment(session, payment); return mapping.findForward("success"); } catch (final CreditsException e) { cancelTicket(request, paymentDTO); throw new ValidationException(actionHelper.resolveErrorKey(e), actionHelper.resolveParameters(e)); } catch (final UnexpectedEntityException e) { cancelTicket(request, paymentDTO); throw new ValidationException("payment.error.invalidTransferType"); } } }); } @Override protected void prepareForm(final ActionMapping mapping, final ActionForm actionForm, final HttpServletRequest request, final HttpServletResponse response) { final DoPaymentDTO payment = resolvePayment(request); request.setAttribute("payment", payment); request.setAttribute("requestTransactionPassword", shouldValidateTransactionPassword(new ShouldValidateTPParameter(mapping, actionForm, request, response, payment, channelService, elementService, transferTypeService, messageHelper))); TransactionFeePreviewDTO fees; fees = LoggedUser.runAsSystem(new Callable<TransactionFeePreviewDTO>() { @Override public TransactionFeePreviewDTO call() throws Exception { return transactionFeeService.preview(payment.getFrom(), payment.getTo(), payment.getTransferType(), payment.getAmount()); } }); request.setAttribute("finalAmount", fees.getFinalAmount()); request.setAttribute("fees", fees.getFees()); } @Override protected void validateForm(final ActionMapping mapping, final ActionForm actionForm, final HttpServletRequest request, final HttpServletResponse response) throws ValidationException { final DoPaymentDTO payment = resolvePayment(request); if (shouldValidateTransactionPassword(new ShouldValidateTPParameter(mapping, actionForm, request, response, payment, channelService, elementService, transferTypeService, messageHelper))) { final ConfirmWebShopPaymentForm form = (ConfirmWebShopPaymentForm) actionForm; if (StringUtils.isEmpty(form.getTransactionPassword())) { throw new ValidationException("_transactionPassword", "login.transactionPassword", new RequiredError()); } } } private void cancelTicket(final HttpServletRequest request, final DoPaymentDTO payment) { final WebShopTicket ticket = ticketService.cancelWebShopTicket(payment.getTicket().getId(), request.getRemoteAddr()); final HttpSession session = request.getSession(); session.removeAttribute("forceBack"); session.setAttribute("errorReturnTo", ticket.getReturnUrl()); } private DoPaymentDTO resolvePayment(final HttpServletRequest request) { final DoPaymentDTO payment = WebShopHelper.getUpdatedPayment(request.getSession()); if (payment == null) { throw new ValidationException(); } if (StringUtils.isEmpty(payment.getDescription())) { payment.setDescription(payment.getTransferType().getDescription()); } return payment; } }