001/* 002 * Copyright 2024 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.plugins.pagesubscription.dao; 017 018import java.util.List; 019import java.util.Map; 020 021import org.apache.avalon.framework.component.Component; 022import org.apache.avalon.framework.context.Context; 023import org.apache.avalon.framework.context.ContextException; 024import org.apache.avalon.framework.context.Contextualizable; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028import org.apache.cocoon.components.ContextHelper; 029import org.apache.cocoon.environment.Request; 030import org.apache.commons.lang.StringUtils; 031 032import org.ametys.core.ui.Callable; 033import org.ametys.core.user.CurrentUserProvider; 034import org.ametys.core.user.UserIdentity; 035import org.ametys.plugins.pagesubscription.BroadcastChannelHelper.BroadcastChannel; 036import org.ametys.plugins.pagesubscription.FrequencyHelper.Frequency; 037import org.ametys.plugins.pagesubscription.Subscription; 038import org.ametys.plugins.pagesubscription.SubscriptionException; 039import org.ametys.plugins.pagesubscription.SubscriptionException.Type; 040import org.ametys.plugins.pagesubscription.type.SubscriptionType; 041import org.ametys.plugins.pagesubscription.type.SubscriptionType.FrequencyTiming; 042import org.ametys.plugins.repository.AmetysObjectResolver; 043import org.ametys.plugins.repository.RepositoryConstants; 044import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector; 045import org.ametys.runtime.plugin.component.AbstractLogEnabled; 046 047/** 048 * Abstract DAO for subscriptions 049 */ 050public abstract class AbstractSubscriptionsDAO extends AbstractLogEnabled implements Component, Serviceable, Contextualizable 051{ 052 /** The ametys object resolver */ 053 protected AmetysObjectResolver _resolver; 054 055 /** The current user provider */ 056 protected CurrentUserProvider _currentUserProvider; 057 058 /** the Avalon context */ 059 protected Context _context; 060 061 public void service(ServiceManager smanager) throws ServiceException 062 { 063 _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); 064 _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE); 065 } 066 067 public void contextualize(Context context) throws ContextException 068 { 069 _context = context; 070 } 071 072 private void _checkSubscription(Subscription subscription) 073 { 074 UserIdentity user = _currentUserProvider.getUser(); 075 boolean isSubscriber = subscription.getSubscriber() 076 .filter(u -> u.equals(user)) 077 .isPresent(); 078 if (!isSubscriber) 079 { 080 throw new SubscriptionException("Can access to the subscription with id '" + subscription.getId() + "' because the subscriber is not the current user.", Type.NO_ACCESS); 081 } 082 } 083 084 /** 085 * Get the current user subscription from the given id 086 * @param subscriptionId the subscription id 087 * @return the subscription as JSON 088 */ 089 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 090 public Map<String, Object> getSubscription(String subscriptionId) 091 { 092 return getSubscription(subscriptionId, true); 093 } 094 095 /** 096 * Get the subscription from the given id 097 * @param subscriptionId the subscription id 098 * @param checkCurrentUser <code>true</code> to check if the subscription belong to the current user 099 * @return the subscription as JSON 100 */ 101 public Map<String, Object> getSubscription(String subscriptionId, boolean checkCurrentUser) 102 { 103 try 104 { 105 Subscription subscription = _resolver.resolveById(subscriptionId); 106 if (checkCurrentUser) 107 { 108 _checkSubscription(subscription); 109 } 110 111 return Map.of("success", true, "subscription", subscription.getSubscriptionType().subscriptionToJSON(subscription)); 112 } 113 catch (Exception e) 114 { 115 getLogger().error("Fail to get subscription with id '{}'", subscriptionId, e); 116 return Map.of("success", false); 117 } 118 } 119 120 /** 121 * Edit the current user subscription with the given id 122 * @param subscriptionId the subscription id 123 * @param frequency the frequency 124 * @param broadcastChannels the broadcast channels 125 * @return the subscription as JSON 126 */ 127 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 128 public Map<String, Object> editSubscription(String subscriptionId, String frequency, List<String> broadcastChannels) 129 { 130 return editSubscription(subscriptionId, frequency, null, broadcastChannels, true); 131 } 132 133 /** 134 * Edit the subscription with the given id 135 * @param subscriptionId the subscription id 136 * @param frequency the frequency 137 * @param forcedTiming the force frequency timing. Can be null if not forced 138 * @param broadcastChannels the broadcast channels 139 * @param checkCurrentUser <code>true</code> to check if the subscription belong to the current user 140 * @return a Map with success status and the subscription as JSON 141 */ 142 @SuppressWarnings("unchecked") 143 public Map<String, Object> editSubscription(String subscriptionId, String frequency, FrequencyTiming forcedTiming, List<String> broadcastChannels, boolean checkCurrentUser) 144 { 145 Request request = ContextHelper.getRequest(_context); 146 // Retrieve the current workspace. 147 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 148 149 try 150 { 151 // Force default the workspace. 152 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, RepositoryConstants.DEFAULT_WORKSPACE); 153 154 Subscription subscription = _resolver.resolveById(subscriptionId); 155 if (checkCurrentUser) 156 { 157 _checkSubscription(subscription); 158 } 159 160 SubscriptionType subscriptionType = subscription.getSubscriptionType(); 161 162 Frequency subFrequency = StringUtils.isNotBlank(frequency) 163 ? Frequency.valueOf(frequency) 164 : subscription.getFrequency(); 165 166 List<BroadcastChannel> subChannels = broadcastChannels != null 167 ? broadcastChannels.stream() 168 .map(BroadcastChannel::valueOf) 169 .toList() 170 : subscription.getBroadcastChannels(); 171 172 if (forcedTiming != null) 173 { 174 subscriptionType.editForceSubscription(subscription, subFrequency, subChannels, forcedTiming, null); 175 } 176 else 177 { 178 subscriptionType.editSubscription(subscription, subFrequency, subChannels, null); 179 } 180 181 return Map.of("success", true, "subscription", subscriptionType.subscriptionToJSON(subscription)); 182 } 183 catch (Exception e) 184 { 185 getLogger().error("Unable to edit subscription with id '{}'", subscriptionId, e); 186 return Map.of("success", false); 187 } 188 finally 189 { 190 // Restore current workspace 191 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 192 } 193 } 194 195 /** 196 * Remove the current user subscription with the given id 197 * @param subscriptionId the subscription id 198 * @return true if successfully subscribe, false otherwise 199 * @throws Exception if an error occurred 200 */ 201 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 202 public boolean unsubscribe(String subscriptionId) throws Exception 203 { 204 return unsubscribe(subscriptionId, true); 205 } 206 207 /** 208 * Remove the subscription with the given id 209 * @param subscriptionId the subscription id 210 * @return true if successfully subscribe, false otherwise 211 * @param checkCurrentUser <code>true</code> to check if the subscription belong to the current user 212 * @throws Exception if an error occurred 213 */ 214 public boolean unsubscribe(String subscriptionId, boolean checkCurrentUser) throws Exception 215 { 216 Request request = ContextHelper.getRequest(_context); 217 // Retrieve the current workspace. 218 String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 219 220 try 221 { 222 // Force default the workspace. 223 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, RepositoryConstants.DEFAULT_WORKSPACE); 224 225 Subscription subscription = _resolver.resolveById(subscriptionId); 226 if (checkCurrentUser) 227 { 228 _checkSubscription(subscription); 229 } 230 231 subscription.getSubscriptionType().unsubscribe(subscription); 232 return true; 233 } 234 catch (Exception e) 235 { 236 getLogger().error("Fail to unsubscribe to suscription with id {}", subscriptionId, e); 237 return false; 238 } 239 finally 240 { 241 // Restore current workspace 242 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp); 243 } 244 } 245}