001/* 002 * Copyright 2022 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.forms.generators; 017 018import java.io.IOException; 019import java.time.ZoneId; 020import java.time.ZonedDateTime; 021import java.util.List; 022import java.util.Map; 023import java.util.stream.Collectors; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.cocoon.ProcessingException; 028import org.apache.cocoon.environment.ObjectModelHelper; 029import org.apache.cocoon.environment.Request; 030import org.apache.cocoon.generation.ServiceableGenerator; 031import org.apache.cocoon.xml.AttributesImpl; 032import org.apache.cocoon.xml.XMLUtils; 033import org.apache.commons.lang3.StringUtils; 034import org.xml.sax.SAXException; 035 036import org.ametys.core.user.CurrentUserProvider; 037import org.ametys.core.user.UserIdentity; 038import org.ametys.core.user.UserManager; 039import org.ametys.core.util.DateUtils; 040import org.ametys.plugins.forms.helper.FormMailHelper; 041import org.ametys.plugins.forms.question.FormQuestionType; 042import org.ametys.plugins.forms.question.computing.ComputingType; 043import org.ametys.plugins.forms.question.types.ComputedQuestionType; 044import org.ametys.plugins.forms.repository.FormEntry; 045import org.ametys.plugins.forms.repository.FormQuestion; 046import org.ametys.plugins.repository.AmetysObjectResolver; 047import org.ametys.runtime.authentication.AccessDeniedException; 048 049/** 050 * Generate the entry of a form 051 */ 052public class FormEntryInformationGenerator extends ServiceableGenerator 053{ 054 /** The current user provider */ 055 protected CurrentUserProvider _currentUserProvider; 056 057 /** The Ametys Object resolver */ 058 protected AmetysObjectResolver _resolver; 059 060 /** The user manager */ 061 protected UserManager _userManager; 062 063 @Override 064 public void service(ServiceManager smanager) throws ServiceException 065 { 066 super.service(smanager); 067 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 068 _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE); 069 _userManager = (UserManager) smanager.lookup(UserManager.ROLE); 070 } 071 072 public void generate() throws IOException, SAXException, ProcessingException 073 { 074 String entryId = _getFormEntryId(); 075 076 contentHandler.startDocument(); 077 078 try 079 { 080 FormEntry entry = _resolver.resolveById(entryId); 081 082 _checkRights(entry); 083 084 _saxEntry(entry); 085 } 086 catch (SAXException e) 087 { 088 getLogger().error("An error occurred saxing entry information for entry '" + entryId + "'", e); 089 } 090 091 contentHandler.endDocument(); 092 } 093 094 /** 095 * Check right before saxing entry 096 * @param entry the entry 097 */ 098 protected void _checkRights(FormEntry entry) 099 { 100 Request request = ObjectModelHelper.getRequest(objectModel); 101 Boolean ignoreRight = (Boolean) request.getAttribute(FormMailHelper.IGNORE_RIGHT_KEY); 102 103 if (ignoreRight == null || !ignoreRight) 104 { 105 UserIdentity currentUser = _currentUserProvider.getUser(); 106 if (!entry.getUser().equals(currentUser)) 107 { 108 throw new AccessDeniedException("User '" + currentUser + "' is not allowed to access to user entry data."); 109 } 110 } 111 } 112 113 /** 114 * Sax the entry 115 * @param entry the entry 116 * @throws SAXException if a saxing error occurred 117 */ 118 protected void _saxEntry(FormEntry entry) throws SAXException 119 { 120 AttributesImpl formAttrs = new AttributesImpl(); 121 formAttrs.addCDATAAttribute("formId", entry.getForm().getId()); 122 formAttrs.addCDATAAttribute("label", entry.getForm().getTitle()); 123 formAttrs.addCDATAAttribute("entryId", String.valueOf(entry.getEntryId())); 124 125 ZonedDateTime submittedAt = entry.getSubmitDate().toInstant().atZone(ZoneId.systemDefault()); 126 formAttrs.addCDATAAttribute("id", entry.getId()); 127 formAttrs.addCDATAAttribute("creationDate", DateUtils.zonedDateTimeToString(submittedAt)); 128 UserIdentity user = entry.getUser(); 129 if (user != null) 130 { 131 formAttrs.addCDATAAttribute("user", _userManager.getUser(user).getFullName()); 132 formAttrs.addCDATAAttribute("userId", UserIdentity.userIdentityToString(user)); 133 } 134 135 Long entryId = entry.getEntryId(); 136 if (entryId != null) 137 { 138 formAttrs.addCDATAAttribute("entryId", String.valueOf(entryId)); 139 } 140 141 _addAdditionalEntryAttributes(entry, formAttrs); 142 143 XMLUtils.startElement(contentHandler, "entry", formAttrs); 144 145 List<FormQuestion> questions = entry.getForm() 146 .getQuestions() 147 .stream() 148 .filter(this::_displayField) 149 .collect(Collectors.toList()); 150 151 for (FormQuestion question : questions) 152 { 153 AttributesImpl attrs = new AttributesImpl(); 154 attrs.addCDATAAttribute("type", question.getType().getStorageType(question)); 155 attrs.addCDATAAttribute("typeId", question.getType().getId()); 156 attrs.addCDATAAttribute("label", question.getTitle()); 157 attrs.addCDATAAttribute("name", question.getNameForForm()); 158 159 XMLUtils.startElement(contentHandler, "field", attrs); 160 question.getType().saxEntryValue(contentHandler, question, entry); 161 XMLUtils.endElement(contentHandler, "field"); 162 } 163 164 XMLUtils.endElement(contentHandler, "entry"); 165 } 166 167 /** 168 * Add additional entry attributes 169 * @param entry the entry 170 * @param attrs the attributes 171 */ 172 protected void _addAdditionalEntryAttributes(FormEntry entry, AttributesImpl attrs) 173 { 174 // Do nothing 175 } 176 177 private boolean _displayField(FormQuestion question) 178 { 179 FormQuestionType type = question.getType(); 180 // This generator is used for front display or mail. Do not display computed field with only server computed value 181 if (type instanceof ComputedQuestionType questionType) 182 { 183 ComputingType computingType = questionType.getComputingType(question); 184 return StringUtils.isNotBlank(questionType.getDisplayXSLT()) && computingType.hasComputedValue(); 185 } 186 return !type.onlyForDisplay(question); 187 } 188 189 private String _getFormEntryId() 190 { 191 Request request = ObjectModelHelper.getRequest(objectModel); 192 @SuppressWarnings("unchecked") 193 Map<String, Object> params = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); 194 String entryId = (String) request.get("entryId"); 195 if (entryId == null) 196 { 197 entryId = (String) params.get("entryId"); 198 } 199 return entryId; 200 } 201}