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.HashMap;
019import java.util.List;
020import java.util.Map;
021import java.util.Set;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.cocoon.components.ContextHelper;
026import org.apache.cocoon.environment.Request;
027import org.apache.commons.lang3.tuple.Pair;
028
029import org.ametys.core.ui.Callable;
030import org.ametys.core.user.UserIdentity;
031import org.ametys.plugins.pagesubscription.BroadcastChannelHelper.BroadcastChannel;
032import org.ametys.plugins.pagesubscription.FrequencyHelper.Frequency;
033import org.ametys.plugins.pagesubscription.context.PageSubscriptionContext;
034import org.ametys.plugins.pagesubscription.type.PageSubscriptionType;
035import org.ametys.plugins.pagesubscription.type.SubscriptionTypeExtensionPoint;
036import org.ametys.plugins.repository.RepositoryConstants;
037import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
038import org.ametys.web.repository.page.Page;
039import org.ametys.web.repository.site.Site;
040import org.ametys.web.rights.PageRightAssignmentContext;
041
042/**
043 * DAO for page subscriptions
044 */
045public class PageSubscriptionsDAO extends AbstractSubscriptionsDAO
046{
047    /** The subscription type extension point */
048    protected SubscriptionTypeExtensionPoint _subscriptionTypeEP;
049    
050    /** The page subscription type */
051    protected PageSubscriptionType _pageSubscriptionType;
052    
053    @Override
054    public void service(ServiceManager smanager) throws ServiceException
055    {
056        super.service(smanager);
057        _subscriptionTypeEP = (SubscriptionTypeExtensionPoint) smanager.lookup(SubscriptionTypeExtensionPoint.ROLE);
058        _pageSubscriptionType = (PageSubscriptionType) _subscriptionTypeEP.getExtension(PageSubscriptionType.ID);
059    }
060    
061    /**
062     * Get subscriptions of a page
063     * @param pageId the page id
064     * @return the results
065     */
066    @Callable(rights = Callable.READ_ACCESS, paramIndex = 0, rightContext = PageRightAssignmentContext.ID)
067    public Map<String, Object> getPageSubscriptions(String pageId)
068    {
069        UserIdentity user = _currentUserProvider.getUser();
070        
071        Page page = _resolver.resolveById(pageId);
072        
073        return _getPageSubscriptions(page, user);
074    }
075    
076    private Map<String, Object> _getPageSubscriptions(Page page, UserIdentity user)
077    {
078        Map<String, Object> results = new HashMap<>();
079        
080        Set<UserIdentity> subscribers = getPageSubscribers(page);
081        
082        results.put("hasSubscribed", subscribers.stream()
083                .filter(u -> u.equals(user))
084                .findAny()
085                .isPresent()
086        );
087        results.put("nbSubscribers", subscribers.size());
088        
089        return results;
090    }
091    
092    /**
093     * Subscribe the current user to a page 
094     * @param pageId the page id
095     * @return the results
096     */
097    @Callable(rights = Callable.READ_ACCESS, paramIndex = 0, rightContext = PageRightAssignmentContext.ID)
098    public Map<String, Object> subscribePage(String pageId)
099    {
100        Request request = ContextHelper.getRequest(_context);
101        // Retrieve the current workspace.
102        String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
103
104        Map<String, Object> results = new HashMap<>();
105        
106        UserIdentity user = _currentUserProvider.getUser();
107        Page page = _resolver.resolveById(pageId);
108        
109        try
110        {
111            // Force default the workspace.
112            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, RepositoryConstants.DEFAULT_WORKSPACE);
113            
114            Pair<Frequency, List<BroadcastChannel>> defaultPreference = _getDefaultPreference(page.getSite());
115            PageSubscriptionContext context = PageSubscriptionContext.newInstance()
116                    .withPage(page);
117            _pageSubscriptionType.subscribe(page.getSite(), user, defaultPreference.getLeft(), defaultPreference.getRight(), context);
118            results.put("success", true);
119        }
120        catch (Exception e)
121        {
122            getLogger().error("An error occurred subscribing to the page with id '{}'", pageId, e);
123            results.put("success", false);
124        }
125        finally 
126        {
127            // Restore current workspace
128            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp);
129        }
130        
131        results.putAll(_getPageSubscriptions(page, user));
132        return results;
133    }
134    
135    private Pair<Frequency, List<BroadcastChannel>> _getDefaultPreference(Site site)
136    {
137        String frequencyValue = site.getValue("page-default-frequency", true, Frequency.DAILY.name());
138        return "NOMAIL".equals(frequencyValue)
139            ? Pair.of(Frequency.INSTANT, List.of(BroadcastChannel.SITE))
140            : Pair.of(Frequency.valueOf(frequencyValue), List.of(BroadcastChannel.MAIL, BroadcastChannel.SITE));
141    }
142    
143    /**
144     * Unsubscribe the current user to a page 
145     * @param pageId the page id
146     * @return the results
147     */
148    @Callable(rights = Callable.READ_ACCESS, paramIndex = 0, rightContext = PageRightAssignmentContext.ID)
149    public Map<String, Object> unsubscribePage(String pageId)
150    {
151        Map<String, Object> results = new HashMap<>();
152        
153        Request request = ContextHelper.getRequest(_context);
154        // Retrieve the current workspace.
155        String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
156        
157        UserIdentity user = _currentUserProvider.getUser();
158        Page page = _resolver.resolveById(pageId);
159        
160        try
161        {
162            // Force default the workspace.
163            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, RepositoryConstants.DEFAULT_WORKSPACE);
164            
165            PageSubscriptionContext context = PageSubscriptionContext.newInstance()
166                    .withPage(page);
167            _pageSubscriptionType.unsubscribe(page.getSite(), user, context);
168            results.put("success", true);
169        }
170        catch (Exception e)
171        {
172            getLogger().error("An error occurred unsubscribing to the page with id '{}'", pageId, e);
173            results.put("success", false);
174            return results;
175        }
176        finally 
177        {
178            // Restore current workspace
179            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp);
180        }
181        
182        results.putAll(_getPageSubscriptions(page, user));
183        return results;
184    }
185    
186    /**
187     * Get the page subscribers
188     * @param page the page
189     * @return the subscribers
190     */
191    public Set<UserIdentity> getPageSubscribers(Page page)
192    {
193        PageSubscriptionContext context = PageSubscriptionContext.newInstance()
194                .withPage(page);
195        return _pageSubscriptionType.getSubscribers(page.getSite(), null, null, context);
196    }
197    
198}