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.ui.Callable; 037import org.ametys.core.ui.StaticClientSideElement; 038import org.ametys.core.util.DateUtils; 039import org.ametys.plugins.repository.AmetysObjectResolver; 040import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder; 041import org.ametys.plugins.repository.version.ModifiableDataAwareVersionableAmetysObject; 042import org.ametys.runtime.config.Config; 043import org.ametys.runtime.i18n.I18nizableText; 044 045/** 046 * This element creates a ribbon button to schedule the archiving of a content 047 */ 048public class ScheduleArchivingClientSideElement extends StaticClientSideElement 049{ 050 /** I18n error key : content type error */ 051 private static final String __I18N_KEY_CONTENT_TYPE_ERROR = "PLUGINS_CMS_ARCHIVE_SCHEDULE_CONTENT_TYPE_ERROR"; 052 053 /** I18n error key : unexpected error */ 054 private static final String __I18N_KEY_UNEXPECTED_ERROR = "PLUGINS_CMS_ARCHIVE_SCHEDULE_UNEXPECTED_ERROR"; 055 056 private ObservationManager _observationManager; 057 private AmetysObjectResolver _resolver; 058 059 @Override 060 public void service(ServiceManager manager) throws ServiceException 061 { 062 super.service(manager); 063 _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE); 064 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.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 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 (content instanceof ModifiableDataAwareVersionableAmetysObject) 110 { 111 ModifiableDataAwareVersionableAmetysObject uContent = (ModifiableDataAwareVersionableAmetysObject) content; 112 ModifiableModelLessDataHolder dataHolder = uContent.getUnversionedDataHolder(); 113 114 // Remove META_ARCHIVE_SCHEDULED_DATE and 115 // SCHEDULED_ARCHIVING_REMINDER_LAST_DATE if date is empty. 116 if (StringUtils.isEmpty(scheduledDateAsStr)) 117 { 118 if (dataHolder.hasValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE)) 119 { 120 dataHolder.removeValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE); 121 122 if (getLogger().isInfoEnabled()) 123 { 124 getLogger().info("Content with id : '" + uContent.getId() + "' does not have a scheduled archiving date anymore."); 125 } 126 } 127 128 if (dataHolder.hasValue(AlertsConstants.SCHEDULED_ARCHIVING_REMINDER_LAST_DATE)) 129 { 130 dataHolder.removeValue(AlertsConstants.SCHEDULED_ARCHIVING_REMINDER_LAST_DATE); 131 } 132 } 133 else 134 { 135 dataHolder.setValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE, scheduledDate); 136 } 137 138 if (uContent.needsSave()) 139 { 140 uContent.saveChanges(); 141 142 // report success 143 successContents.add(uContent.getId()); 144 145 // Notify observer 146 Map<String, Object> eventParams = new HashMap<>(); 147 eventParams.put(ObservationConstants.ARGS_CONTENT, content); 148 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, contentId); 149 150 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_MODIFIED, _currentUserProvider.getUser(), eventParams)); 151 } 152 } 153 else 154 { 155 getLogger().error("Unable to set a scheduled archiving for the content : '" + content.getId() + "'. It is not a ModifiableMetadataAwareVersionableAmetysObject."); 156 157 // report error 158 List<String> i18nParams = new ArrayList<>(); 159 i18nParams.add(content.getTitle(null)); 160 failedContents.add(new I18nizableText("plugin.cms", __I18N_KEY_CONTENT_TYPE_ERROR, i18nParams)); 161 162 } 163 } 164 catch (Exception e) 165 { 166 getLogger().error("Unexpected exception while trying to schedule an archiving for the content : '" + contentId + "'."); 167 168 // report error 169 List<String> i18nParams = new ArrayList<>(); 170 i18nParams.add(contentId); 171 failedContents.add(new I18nizableText("plugin.cms", __I18N_KEY_UNEXPECTED_ERROR, i18nParams)); 172 } 173 } 174 175 results.put("error", failedContents); 176 results.put("success", successContents); 177 178 return results; 179 } 180 181 /** 182 * Gets the scheduled archiving dates of one or several contents 183 * @param contentIds the ids of the contents 184 * @return result the server's response in JSON 185 */ 186 @Callable 187 public Map<String, Object> getScheduledArchivingDate(List<String> contentIds) 188 { 189 Map<String, Object> results = new HashMap<> (); 190 Set<ZonedDateTime> dates = new HashSet<>(); 191 192 // Retrieves the date for each content 193 for (String contentId : contentIds) 194 { 195 Content content = _resolver.resolveById(contentId); 196 197 if (content instanceof ModifiableDataAwareVersionableAmetysObject) 198 { 199 ZonedDateTime date = ((ModifiableDataAwareVersionableAmetysObject) content).getUnversionedDataHolder().getValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE); 200 dates.add(date); 201 } 202 } 203 204 // Retrieves the closest date from current time. 205 dates.remove(null); 206 ZonedDateTime scheduledDate = getDateNearestToCurrent(dates); 207 208 // Generate the JSON 209 Map<String, Object> content = new HashMap<> (); 210 if (scheduledDate != null) 211 { 212 content.put("date", DateUtils.zonedDateTimeToString(scheduledDate)); 213 } 214 results.put("content", content); 215 216 return results; 217 } 218 219 private ZonedDateTime getDateNearestToCurrent(Set<ZonedDateTime> dates) 220 { 221 ZonedDateTime returnDate = null; 222 ZonedDateTime currentDate = ZonedDateTime.now(); 223 224 for (ZonedDateTime date : dates) 225 { 226 if (date.compareTo(currentDate) >= 0 && (returnDate == null || date.compareTo(returnDate) < 0)) 227 { 228 returnDate = date; 229 } 230 } 231 return returnDate; 232 } 233 234 @Override 235 public List<Script> getScripts(boolean ignoreRights, Map<String, Object> contextParameters) 236 { 237 boolean enabled = Config.getInstance().getValue("archive.scheduler.enabled"); 238 if (enabled) 239 { 240 return super.getScripts(ignoreRights, contextParameters); 241 } 242 243 return new ArrayList<>(); 244 } 245}