001/* 002 * Copyright 2015 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.web.clientsideelement; 017 018import java.time.ZonedDateTime; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.avalon.framework.activity.Initializable; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.quartz.JobKey; 027import org.quartz.SchedulerException; 028 029import org.ametys.core.observation.Event; 030import org.ametys.core.observation.ObservationManager; 031import org.ametys.core.schedule.Runnable; 032import org.ametys.core.ui.Callable; 033import org.ametys.core.ui.ClientSideElement; 034import org.ametys.core.user.UserIdentity; 035import org.ametys.plugins.core.schedule.Scheduler; 036import org.ametys.runtime.model.type.ElementType; 037import org.ametys.runtime.model.type.ModelItemTypeConstants; 038import org.ametys.web.ObservationConstants; 039import org.ametys.web.publication.PublishPageRunnable; 040import org.ametys.web.publication.UnpublishPageRunnable; 041import org.ametys.web.repository.page.ModifiablePage; 042import org.ametys.web.repository.page.Page; 043import org.ametys.web.repository.page.PageDataTypeExtensionPoint; 044import org.ametys.web.repository.page.jcr.DefaultPage; 045 046/** 047 * This {@link ClientSideElement} creates a button representing the schedule publication status of a page. 048 * 049 */ 050public class ScheduledPageClientSideElement extends AbstractPageClientSideElement implements Initializable 051{ 052 private ObservationManager _observationManager; 053 private Scheduler _scheduler; 054 private PageDataTypeExtensionPoint _pageDataTypeExtensionPoint; 055 private ElementType<ZonedDateTime> _dateElementType; 056 057 @Override 058 public void service(ServiceManager smanager) throws ServiceException 059 { 060 super.service(smanager); 061 _observationManager = (ObservationManager) smanager.lookup(ObservationManager.ROLE); 062 _scheduler = (Scheduler) smanager.lookup(Scheduler.ROLE); 063 _pageDataTypeExtensionPoint = (PageDataTypeExtensionPoint) smanager.lookup(PageDataTypeExtensionPoint.ROLE); 064 } 065 066 @SuppressWarnings("unchecked") 067 public void initialize() throws Exception 068 { 069 _dateElementType = (ElementType<ZonedDateTime>) _pageDataTypeExtensionPoint.getExtension(ModelItemTypeConstants.DATETIME_TYPE_ID); 070 } 071 072 /** 073 * Get the publication dates of a page 074 * @param pageId the id of the page 075 * @return a map 076 */ 077 @Callable 078 public Map<String, Object> getPublicationDates(String pageId) 079 { 080 Map<String, Object> dates = new HashMap<> (); 081 082 Page page = _resolver.resolveById(pageId); 083 084 ZonedDateTime startDate = page.getValue(DefaultPage.METADATA_PUBLICATION_START_DATE); 085 if (startDate != null) 086 { 087 dates.put("startDate", _dateElementType.toString(startDate)); 088 } 089 090 ZonedDateTime endDate = page.getValue(DefaultPage.METADATA_PUBLICATION_END_DATE); 091 if (endDate != null) 092 { 093 dates.put("endDate", _dateElementType.toString(endDate)); 094 } 095 096 return dates; 097 } 098 099 /** 100 * Set date of publication of pages 101 * @param pageIds The ids of pages to update 102 * @param startDateAsStr The start date. Can be null. 103 * @param endDateAsStr The end date. Can be null. 104 * @return true if operation has succeeded. 105 */ 106 @Callable 107 public boolean setPublicationDate (List<String> pageIds, String startDateAsStr, String endDateAsStr) 108 { 109 ZonedDateTime startDate = startDateAsStr != null ? _dateElementType.castValue(startDateAsStr) : null; 110 ZonedDateTime endDate = endDateAsStr != null ? _dateElementType.castValue(endDateAsStr) : null; 111 112 for (String id : pageIds) 113 { 114 ModifiablePage page = _resolver.resolveById(id); 115 UserIdentity userIdentity = _currentUserProvider.getUser(); 116 117 try 118 { 119 _scheduleStartDate(page, userIdentity, startDate); 120 _scheduleEndDate(page, userIdentity, endDate); 121 122 page.saveChanges(); 123 124 // Notify listeners in case the page has to be publish or unpublish right now 125 Map<String, Object> eventParams = new HashMap<>(); 126 eventParams.put(ObservationConstants.ARGS_PAGE, page); 127 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_CHANGED, _currentUserProvider.getUser(), eventParams)); 128 129 _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_UPDATED, _currentUserProvider.getUser(), eventParams)); 130 } 131 catch (SchedulerException e) 132 { 133 if (getLogger().isErrorEnabled()) 134 { 135 getLogger().error("An error occured when trying to schedule the publishing of the page " + id, e); 136 } 137 } 138 } 139 140 return true; 141 } 142 143 private void _scheduleStartDate (ModifiablePage page, UserIdentity userIdentity, ZonedDateTime startDate) throws SchedulerException 144 { 145 // Publish job 146 Runnable publishRunnable = new PublishPageRunnable(page.getId(), page.getTitle(), userIdentity, startDate); 147 JobKey jobKey = new JobKey(publishRunnable.getId(), Scheduler.JOB_GROUP); 148 149 if (_scheduler.getScheduler().checkExists(jobKey)) 150 { 151 // Remove any existing corresponding job 152 getLogger().debug("Removing the existing job for publishing {} ({})", page.getTitle(), page.getId()); 153 _scheduler.getScheduler().deleteJob(jobKey); 154 } 155 156 if (startDate != null) 157 { 158 page.setValue(DefaultPage.METADATA_PUBLICATION_START_DATE, startDate); 159 160 if (startDate.isAfter(ZonedDateTime.now())) 161 { 162 // No necessary to run job if date is in the past 163 getLogger().debug("Creating a job for publishing {} ({}) on {}", page.getTitle(), page.getId(), startDate); 164 _scheduler.scheduleJob(publishRunnable); 165 } 166 else 167 { 168 getLogger().debug("No job needed for publishing {} ({}) on {}", page.getTitle(), page.getId(), startDate); 169 } 170 } 171 else 172 { 173 page.removeValue(DefaultPage.METADATA_PUBLICATION_START_DATE); 174 getLogger().debug("No schedule for publishing was required for {} ({})", page.getTitle(), page.getId()); 175 } 176 } 177 178 private void _scheduleEndDate (ModifiablePage page, UserIdentity userIdentity, ZonedDateTime endDate) throws SchedulerException 179 { 180 // Unpublish job 181 Runnable unpublishRunnable = new UnpublishPageRunnable(page.getId(), page.getTitle(), userIdentity, endDate); 182 JobKey jobKey = new JobKey(unpublishRunnable.getId(), Scheduler.JOB_GROUP); 183 184 if (_scheduler.getScheduler().checkExists(jobKey)) 185 { 186 // Remove any existing corresponding job 187 getLogger().debug("Removing the existing job for unpublishing {} ({})", page.getTitle(), page.getId()); 188 _scheduler.getScheduler().deleteJob(jobKey); 189 } 190 191 if (endDate != null) 192 { 193 page.setValue(DefaultPage.METADATA_PUBLICATION_END_DATE, endDate); 194 195 if (endDate.isAfter(ZonedDateTime.now())) 196 { 197 // No necessary to run job if date is in the past 198 getLogger().debug("Creating a job for unpublishing {} ({}) on {}", page.getTitle(), page.getId(), endDate); 199 _scheduler.scheduleJob(unpublishRunnable); 200 } 201 else 202 { 203 getLogger().debug("No job needed for unpublishing {} ({}) on {}", page.getTitle(), page.getId(), endDate); 204 } 205 } 206 else 207 { 208 page.removeValue(DefaultPage.METADATA_PUBLICATION_END_DATE); 209 getLogger().debug("No schedule for unpublishing was required for {} ({})", page.getTitle(), page.getId()); 210 } 211 } 212}