001/* 002 * Copyright 2014 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.cms.clientsideelement; 017 018import java.time.ZonedDateTime; 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.List; 023import java.util.Map; 024import java.util.Set; 025 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.commons.lang3.StringUtils; 029 030import org.ametys.cms.ObservationConstants; 031import org.ametys.cms.alerts.AlertsConstants; 032import org.ametys.cms.content.archive.ArchiveConstants; 033import org.ametys.cms.repository.Content; 034import org.ametys.core.observation.Event; 035import org.ametys.core.observation.ObservationManager; 036import org.ametys.core.right.RightManager.RightResult; 037import org.ametys.core.ui.Callable; 038import org.ametys.core.util.DateUtils; 039import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder; 040import org.ametys.plugins.repository.version.ModifiableDataAwareVersionableAmetysObject; 041import org.ametys.runtime.config.Config; 042import org.ametys.runtime.i18n.I18nizableText; 043 044/** 045 * This element creates a ribbon button to schedule the archiving of a content 046 */ 047public class ScheduleArchivingClientSideElement extends SmartContentClientSideElement 048{ 049 /** I18n error key : content type error */ 050 private static final String __I18N_KEY_CONTENT_TYPE_ERROR = "PLUGINS_CMS_ARCHIVE_SCHEDULE_CONTENT_TYPE_ERROR"; 051 052 /** I18n error key : no right */ 053 private static final String __I18N_KEY_RIGHT_ERROR = "PLUGINS_CMS_ARCHIVE_SCHEDULE_NO_RIGHT"; 054 055 /** I18n error key : unexpected error */ 056 private static final String __I18N_KEY_UNEXPECTED_ERROR = "PLUGINS_CMS_ARCHIVE_SCHEDULE_UNEXPECTED_ERROR"; 057 058 private ObservationManager _observationManager; 059 060 @Override 061 public void service(ServiceManager manager) throws ServiceException 062 { 063 super.service(manager); 064 _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE); 065 } 066 067 /** 068 * Set or remove the <code>ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE</code> on a content. 069 * @param contentIds The ids of contents 070 * @param scheduledDateAsStr The schedule date as string 071 * @return the successful and failed contents 072 */ 073 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 074 public Map<String, Object> setScheduledArchivingDate (List<String> contentIds, String scheduledDateAsStr) 075 { 076 Map<String, Object> results = new HashMap<>(); 077 078 // Error list 079 List<I18nizableText> failedContents = new ArrayList<>(); 080 081 // Success list, containing the contentId that have been successfully scheduled 082 List<String> successContents = new ArrayList<>(); 083 084 ZonedDateTime scheduledDate = DateUtils.parseZonedDateTime(scheduledDateAsStr); 085 086 if (StringUtils.isNotEmpty(scheduledDateAsStr)) 087 { 088 if (scheduledDate == null) 089 { 090 getLogger().error("Cannot cast value '" + scheduledDateAsStr + "' into type 'date'"); 091 throw new IllegalArgumentException("Invalid format for date value '" + scheduledDateAsStr + "'"); 092 } 093 094 // Date must be set at least after tomorrow 095 /*if (scheduledDate.compareTo(new DateMidnight().plusDays(1).toDate()) < 0) 096 { 097 getLogger().error("The scheduled date '" + scheduledDate + "' cannot be set before the current date"); 098 throw new IllegalArgumentException("The scheduled date '" + scheduledDate + "' cannot be set before the current date"); 099 }*/ 100 } 101 102 // For each content 103 for (String contentId : contentIds) 104 { 105 try 106 { 107 Content content = _resolver.resolveById(contentId); 108 109 if (_rightManager.currentUserHasRight(ArchiveContentClientSideElement.WORKFLOW_RIGHTS_ARCHIVE, content) != RightResult.RIGHT_ALLOW) 110 { 111 // report error 112 List<String> i18nParams = new ArrayList<>(); 113 i18nParams.add(content.getTitle(null)); 114 failedContents.add(new I18nizableText("plugin.cms", __I18N_KEY_RIGHT_ERROR, i18nParams)); 115 continue; 116 } 117 118 if (content instanceof ModifiableDataAwareVersionableAmetysObject) 119 { 120 ModifiableDataAwareVersionableAmetysObject uContent = (ModifiableDataAwareVersionableAmetysObject) content; 121 ModifiableModelLessDataHolder dataHolder = uContent.getUnversionedDataHolder(); 122 123 // Remove META_ARCHIVE_SCHEDULED_DATE and 124 // SCHEDULED_ARCHIVING_REMINDER_LAST_DATE if date is empty. 125 if (StringUtils.isEmpty(scheduledDateAsStr)) 126 { 127 dataHolder.removeValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE); 128 if (getLogger().isInfoEnabled()) 129 { 130 getLogger().info("Content with id : '" + uContent.getId() + "' does not have a scheduled archiving date anymore."); 131 } 132 133 dataHolder.removeValue(AlertsConstants.SCHEDULED_ARCHIVING_REMINDER_LAST_DATE); 134 } 135 else 136 { 137 dataHolder.setValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE, scheduledDate); 138 } 139 140 if (uContent.needsSave()) 141 { 142 uContent.saveChanges(); 143 144 // report success 145 successContents.add(uContent.getId()); 146 147 // Notify observer 148 Map<String, Object> eventParams = new HashMap<>(); 149 eventParams.put(ObservationConstants.ARGS_CONTENT, content); 150 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, contentId); 151 152 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_MODIFIED, _currentUserProvider.getUser(), eventParams)); 153 } 154 } 155 else 156 { 157 getLogger().error("Unable to set a scheduled archiving for the content : '" + content.getId() + "'. It is not a ModifiableMetadataAwareVersionableAmetysObject."); 158 159 // report error 160 List<String> i18nParams = new ArrayList<>(); 161 i18nParams.add(content.getTitle(null)); 162 failedContents.add(new I18nizableText("plugin.cms", __I18N_KEY_CONTENT_TYPE_ERROR, i18nParams)); 163 164 } 165 } 166 catch (Exception e) 167 { 168 getLogger().error("Unexpected exception while trying to schedule an archiving for the content : '" + contentId + "'."); 169 170 // report error 171 List<String> i18nParams = new ArrayList<>(); 172 i18nParams.add(contentId); 173 failedContents.add(new I18nizableText("plugin.cms", __I18N_KEY_UNEXPECTED_ERROR, i18nParams)); 174 } 175 } 176 177 results.put("error", failedContents); 178 results.put("success", successContents); 179 180 return results; 181 } 182 183 /** 184 * Gets the scheduled archiving dates of one or several contents 185 * @param contentIds the ids of the contents 186 * @return result the server's response in JSON 187 */ 188 @Callable(rights = ArchiveContentClientSideElement.WORKFLOW_RIGHTS_ARCHIVE) 189 public Map<String, Object> getScheduledArchivingDate(List<String> contentIds) 190 { 191 Map<String, Object> results = new HashMap<> (); 192 Set<ZonedDateTime> dates = new HashSet<>(); 193 194 // Retrieves the date for each content 195 for (String contentId : contentIds) 196 { 197 Content content = _resolver.resolveById(contentId); 198 199 if (content instanceof ModifiableDataAwareVersionableAmetysObject) 200 { 201 ZonedDateTime date = ((ModifiableDataAwareVersionableAmetysObject) content).getUnversionedDataHolder().getValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE); 202 dates.add(date); 203 } 204 } 205 206 // Retrieves the closest date from current time. 207 dates.remove(null); 208 ZonedDateTime scheduledDate = getDateNearestToCurrent(dates); 209 210 // Generate the JSON 211 Map<String, Object> content = new HashMap<> (); 212 if (scheduledDate != null) 213 { 214 content.put("date", DateUtils.zonedDateTimeToString(scheduledDate)); 215 } 216 results.put("content", content); 217 218 return results; 219 } 220 221 private ZonedDateTime getDateNearestToCurrent(Set<ZonedDateTime> dates) 222 { 223 ZonedDateTime returnDate = null; 224 ZonedDateTime currentDate = ZonedDateTime.now(); 225 226 for (ZonedDateTime date : dates) 227 { 228 if (date.compareTo(currentDate) >= 0 && (returnDate == null || date.compareTo(returnDate) < 0)) 229 { 230 returnDate = date; 231 } 232 } 233 return returnDate; 234 } 235 236 @Override 237 public List<Script> getScripts(boolean ignoreRights, Map<String, Object> contextParameters) 238 { 239 boolean enabled = Config.getInstance().getValue("archive.scheduler.enabled"); 240 if (enabled) 241 { 242 return super.getScripts(ignoreRights, contextParameters); 243 } 244 245 return new ArrayList<>(); 246 } 247}