001/* 002 * Copyright 2016 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.core.ui; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.avalon.framework.configuration.Configuration; 024import org.apache.avalon.framework.configuration.ConfigurationException; 025import org.apache.avalon.framework.context.Context; 026import org.apache.avalon.framework.context.ContextException; 027import org.apache.avalon.framework.context.Contextualizable; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.cocoon.components.ContextHelper; 031import org.apache.cocoon.environment.Request; 032import org.quartz.SchedulerException; 033 034import org.ametys.core.schedule.AmetysJob; 035import org.ametys.plugins.core.schedule.Scheduler; 036import org.ametys.plugins.core.ui.log.LogManager; 037import org.ametys.runtime.authentication.AccessDeniedException; 038import org.ametys.runtime.workspace.WorkspaceMatcher; 039 040/** 041 * This implementation creates an element for adding a new task 042 */ 043public class AddTaskClientSideElement extends StaticClientSideElement implements Contextualizable 044{ 045 /** The Avalon context */ 046 protected Context _context; 047 /** The Ametys scheduler */ 048 protected Scheduler _scheduler; 049 /** The log manager */ 050 protected LogManager _logManager; 051 052 private String _schedulableId; 053 private List<String> _logCategories; 054 055 @Override 056 public void contextualize(Context context) throws ContextException 057 { 058 _context = context; 059 } 060 061 @Override 062 public void service(ServiceManager smanager) throws ServiceException 063 { 064 super.service(smanager); 065 _scheduler = (Scheduler) smanager.lookup(Scheduler.ROLE); 066 _logManager = (LogManager) smanager.lookup(LogManager.ROLE); 067 } 068 069 /** 070 * Get event logs 071 * @param timestamp Events after this timestamp will be retrieved 072 * @param categories Events will be filtered by these categories. If empty, all categories configured by the client side are accepted. 073 * @return the target types 074 */ 075 @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION) 076 public List<Map<String, Object>> getEvents (Long timestamp, List<String> categories) 077 { 078 if (!hasRight(getRights(Map.of()))) 079 { 080 throw new AccessDeniedException("The user '" + _currentUserProvider.getUser() + "' try to get logs without sufficient rights"); 081 } 082 083 // Filter allowed categories 084 List<String> allowedCategories = categories 085 .stream() 086 .filter(c -> _logCategories.isEmpty() || _logCategories.contains(c)) 087 .toList(); 088 089 return _logManager.getEvents(timestamp, allowedCategories.isEmpty() ? _logCategories : allowedCategories); 090 } 091 092 @Override 093 protected String _configureClass(Configuration configuration) throws ConfigurationException 094 { 095 return "Ametys.plugins.coreui.schedule.AddTaskButtonController"; 096 } 097 098 @SuppressWarnings("unchecked") 099 @Override 100 protected Map<String, Object> configureInitialParameters(Configuration configuration) throws ConfigurationException 101 { 102 Map<String, Object> initialParameters = super.configureInitialParameters(configuration); 103 _schedulableId = (String) initialParameters.get("schedulable"); 104 105 initialParameters.put("action", _configureClass(configuration) + ".act"); 106 107 // Always have at least the log category 'org.ametys.plugins.core.schedule.Scheduler', 108 // because in case of error in AmetysJob during the execution of the Schedulable, it will log in that category 109 _logCategories = new ArrayList<>(); 110 String jobLogCategory = AmetysJob.class.getName() + "$" + _schedulableId; 111 _logCategories.add(jobLogCategory); 112 if (initialParameters.containsKey("log-category")) 113 { 114 Object initialLogCategory = initialParameters.get("log-category"); 115 116 if (initialLogCategory instanceof String) 117 { 118 _logCategories.add((String) initialLogCategory); 119 } 120 else if (initialLogCategory instanceof List) 121 { 122 _logCategories.addAll((List<String>) initialLogCategory); 123 } 124 } 125 initialParameters.put("log-category", _logCategories); 126 127 return initialParameters; 128 } 129 130 @Override 131 protected Script _configureScript(Configuration configuration) throws ConfigurationException 132 { 133 List<ScriptFile> scriptsImports = _configureImports(configuration.getChild("scripts")); 134 scriptsImports.add(new ScriptFile("/plugins/core-ui/resources/js/Ametys/plugins/coreui/schedule/AddTaskButtonController.js")); 135 List<ScriptFile> cssImports = _configureImports(configuration.getChild("css")); 136 String jsClassName = _configureClass(configuration.getChild("class")); 137 Map<String, Object> initialParameters = configureInitialParameters(configuration); 138 139 return new Script(this.getId(), jsClassName, scriptsImports, cssImports, initialParameters); 140 } 141 142 @Override 143 protected Map<String, List<String>> _configureDependencies(Configuration configuration) throws ConfigurationException 144 { 145 Map<String, List<String>> dependencies = super._configureDependencies(configuration); 146 147 List<String> importDependencies = dependencies.computeIfAbsent("org.ametys.core.ui.StaticFileImportsManager", __ -> new ArrayList<>()); 148 importDependencies.add("org.ametys.core.schedule.Scheduler"); 149 150 List<String> uitoolsDependencies = dependencies.computeIfAbsent("org.ametys.core.ui.UIToolsFactoriesManager", __ -> new ArrayList<>()); 151 uitoolsDependencies.add("uitool-server-logs"); 152 153 return dependencies; 154 } 155 156 @Override 157 public Map<String, List<String>> getDependencies() 158 { 159 // RUNTIME-2913 The task scheduler is opened in the CMS while using the AddTaskButtonController 160 // Load the task scheduler only on admin context 161 Request request = ContextHelper.getRequest(_context); 162 String workspaceName = (String) request.getAttribute(WorkspaceMatcher.WORKSPACE_NAME); 163 if ("admin".equals(workspaceName)) 164 { 165 Map<String, List<String>> clonedDependencies = new HashMap<>(_dependencies); 166 List<String> uitoolsDependencies = new ArrayList<>(); 167 if (clonedDependencies.containsKey("org.ametys.core.ui.UIToolsFactoriesManager")) 168 { 169 uitoolsDependencies.addAll(clonedDependencies.get("org.ametys.core.ui.UIToolsFactoriesManager")); 170 } 171 uitoolsDependencies.add("uitool-scheduled-tasks"); 172 clonedDependencies.put("org.ametys.core.ui.UIToolsFactoriesManager", uitoolsDependencies); 173 return clonedDependencies; 174 } 175 return _dependencies; 176 } 177 178 /** 179 * Schedule a task 180 * @param label the task label 181 * @param description the task description 182 * @param fireProcess the fire process 183 * @param cron the cron 184 * @param schedulableId the id of the schedulable 185 * @param params the schedulable parameters 186 * @return a json 187 * @throws SchedulerException if an error occurs when scheduling the task 188 */ 189 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 190 public Map<String, Object> add(String label, String description, String fireProcess, String cron, String schedulableId, Map<String, Object> params) throws SchedulerException 191 { 192 if (hasRight(getRights(null)) && schedulableId.equals(_schedulableId)) 193 { 194 return _scheduler.add(label, description, fireProcess, cron, schedulableId, params); 195 } 196 throw new AccessDeniedException(_currentUserProvider.getUser() + "' tried to execute schedulable '" + schedulableId + "' without any of the following rights: " + getRights(null)); 197 } 198 199 /** 200 * Get the schedulable parameters 201 * @param schedulableId the id of the schedulable 202 * @return the parameters as json 203 * @throws Exception if an error occurs 204 */ 205 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 206 public Map<String, Object> getParameters(String schedulableId) throws Exception 207 { 208 if (hasRight(getRights(null)) && schedulableId.equals(_schedulableId)) 209 { 210 return _scheduler.getParameters(_schedulableId); 211 } 212 throw new AccessDeniedException(_currentUserProvider.getUser() + "' tried to fetch the schedulable " + _schedulableId + " parameters without any of the following rights: " + getRights(null)); 213 } 214}