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 // If date is in past, unecessary to run the job 152 _scheduler.getScheduler().deleteJob(jobKey); 153 } 154 155 if (startDate != null) 156 { 157 page.setValue(DefaultPage.METADATA_PUBLICATION_START_DATE, startDate); 158 159 if (startDate.isAfter(ZonedDateTime.now())) 160 { 161 // No necessary to run job if date is in the past 162 _scheduler.scheduleJob(publishRunnable); 163 } 164 } 165 else if (page.hasValue(DefaultPage.METADATA_PUBLICATION_START_DATE)) 166 { 167 page.removeValue(DefaultPage.METADATA_PUBLICATION_START_DATE); 168 } 169 } 170 171 private void _scheduleEndDate (ModifiablePage page, UserIdentity userIdentity, ZonedDateTime endDate) throws SchedulerException 172 { 173 // Unpublish job 174 Runnable unpublishRunnable = new UnpublishPageRunnable(page.getId(), page.getTitle(), userIdentity, endDate); 175 JobKey jobKey = new JobKey(unpublishRunnable.getId(), Scheduler.JOB_GROUP); 176 177 if (_scheduler.getScheduler().checkExists(jobKey)) 178 { 179 // A end publication was already scheduled, delete the job 180 _scheduler.getScheduler().deleteJob(jobKey); 181 } 182 183 if (endDate != null) 184 { 185 page.setValue(DefaultPage.METADATA_PUBLICATION_END_DATE, endDate); 186 187 if (endDate.isAfter(ZonedDateTime.now())) 188 { 189 // No necessary to run job if date is in the past 190 _scheduler.scheduleJob(unpublishRunnable); 191 } 192 } 193 else if (page.hasValue(DefaultPage.METADATA_PUBLICATION_END_DATE)) 194 { 195 page.removeValue(DefaultPage.METADATA_PUBLICATION_END_DATE); 196 } 197 } 198}