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 dataHolder.removeValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE); 119 if (getLogger().isInfoEnabled()) 120 { 121 getLogger().info("Content with id : '" + uContent.getId() + "' does not have a scheduled archiving date anymore."); 122 } 123 124 dataHolder.removeValue(AlertsConstants.SCHEDULED_ARCHIVING_REMINDER_LAST_DATE); 125 } 126 else 127 { 128 dataHolder.setValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE, scheduledDate); 129 } 130 131 if (uContent.needsSave()) 132 { 133 uContent.saveChanges(); 134 135 // report success 136 successContents.add(uContent.getId()); 137 138 // Notify observer 139 Map<String, Object> eventParams = new HashMap<>(); 140 eventParams.put(ObservationConstants.ARGS_CONTENT, content); 141 eventParams.put(ObservationConstants.ARGS_CONTENT_ID, contentId); 142 143 _observationManager.notify(new Event(ObservationConstants.EVENT_CONTENT_MODIFIED, _currentUserProvider.getUser(), eventParams)); 144 } 145 } 146 else 147 { 148 getLogger().error("Unable to set a scheduled archiving for the content : '" + content.getId() + "'. It is not a ModifiableMetadataAwareVersionableAmetysObject."); 149 150 // report error 151 List<String> i18nParams = new ArrayList<>(); 152 i18nParams.add(content.getTitle(null)); 153 failedContents.add(new I18nizableText("plugin.cms", __I18N_KEY_CONTENT_TYPE_ERROR, i18nParams)); 154 155 } 156 } 157 catch (Exception e) 158 { 159 getLogger().error("Unexpected exception while trying to schedule an archiving for the content : '" + contentId + "'."); 160 161 // report error 162 List<String> i18nParams = new ArrayList<>(); 163 i18nParams.add(contentId); 164 failedContents.add(new I18nizableText("plugin.cms", __I18N_KEY_UNEXPECTED_ERROR, i18nParams)); 165 } 166 } 167 168 results.put("error", failedContents); 169 results.put("success", successContents); 170 171 return results; 172 } 173 174 /** 175 * Gets the scheduled archiving dates of one or several contents 176 * @param contentIds the ids of the contents 177 * @return result the server's response in JSON 178 */ 179 @Callable 180 public Map<String, Object> getScheduledArchivingDate(List<String> contentIds) 181 { 182 Map<String, Object> results = new HashMap<> (); 183 Set<ZonedDateTime> dates = new HashSet<>(); 184 185 // Retrieves the date for each content 186 for (String contentId : contentIds) 187 { 188 Content content = _resolver.resolveById(contentId); 189 190 if (content instanceof ModifiableDataAwareVersionableAmetysObject) 191 { 192 ZonedDateTime date = ((ModifiableDataAwareVersionableAmetysObject) content).getUnversionedDataHolder().getValue(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE); 193 dates.add(date); 194 } 195 } 196 197 // Retrieves the closest date from current time. 198 dates.remove(null); 199 ZonedDateTime scheduledDate = getDateNearestToCurrent(dates); 200 201 // Generate the JSON 202 Map<String, Object> content = new HashMap<> (); 203 if (scheduledDate != null) 204 { 205 content.put("date", DateUtils.zonedDateTimeToString(scheduledDate)); 206 } 207 results.put("content", content); 208 209 return results; 210 } 211 212 private ZonedDateTime getDateNearestToCurrent(Set<ZonedDateTime> dates) 213 { 214 ZonedDateTime returnDate = null; 215 ZonedDateTime currentDate = ZonedDateTime.now(); 216 217 for (ZonedDateTime date : dates) 218 { 219 if (date.compareTo(currentDate) >= 0 && (returnDate == null || date.compareTo(returnDate) < 0)) 220 { 221 returnDate = date; 222 } 223 } 224 return returnDate; 225 } 226 227 @Override 228 public List<Script> getScripts(boolean ignoreRights, Map<String, Object> contextParameters) 229 { 230 boolean enabled = Config.getInstance().getValue("archive.scheduler.enabled"); 231 if (enabled) 232 { 233 return super.getScripts(ignoreRights, contextParameters); 234 } 235 236 return new ArrayList<>(); 237 } 238}