001/*
002 * (C) Copyright 2007 Nuxeo SA (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 * $Id$
020 */
021
022package org.nuxeo.ecm.webapp.notification;
023
024import java.io.Serializable;
025import java.util.ArrayList;
026import java.util.Collections;
027import java.util.List;
028
029import javax.faces.context.FacesContext;
030
031import org.apache.commons.logging.Log;
032import org.apache.commons.logging.LogFactory;
033import org.jboss.seam.ScopeType;
034import org.jboss.seam.annotations.Factory;
035import org.jboss.seam.annotations.In;
036import org.jboss.seam.annotations.Name;
037import org.jboss.seam.annotations.Observer;
038import org.jboss.seam.annotations.Scope;
039import org.jboss.seam.annotations.datamodel.DataModel;
040import org.jboss.seam.annotations.datamodel.DataModelSelection;
041import org.jboss.seam.annotations.intercept.BypassInterceptors;
042import org.jboss.seam.faces.FacesMessages;
043import org.jboss.seam.international.StatusMessage;
044import org.nuxeo.ecm.core.api.CoreSession;
045import org.nuxeo.ecm.core.api.DocumentModel;
046import org.nuxeo.ecm.core.api.NuxeoPrincipal;
047import org.nuxeo.ecm.platform.ec.notification.NotificationConstants;
048import org.nuxeo.ecm.platform.notification.api.Notification;
049import org.nuxeo.ecm.platform.notification.api.NotificationManager;
050import org.nuxeo.ecm.platform.ui.web.api.NavigationContext;
051import org.nuxeo.ecm.webapp.base.InputController;
052import org.nuxeo.ecm.webapp.helpers.EventNames;
053import org.nuxeo.ecm.webapp.helpers.ResourcesAccessor;
054
055/**
056 * Handles the subscriptions page.
057 *
058 * @author <a href="mailto:npaslaru@nuxeo.com">Narcis Paslaru</a>
059 */
060@Name("subscriptionAction")
061@Scope(ScopeType.PAGE)
062public class SubscriptionsAction extends InputController implements Serializable {
063
064    private static final long serialVersionUID = -2440187703248677446L;
065
066    private static final Log log = LogFactory.getLog(SubscriptionsAction.class);
067
068    @In
069    protected transient NavigationContext navigationContext;
070
071    @In(create = true, required = false)
072    protected transient CoreSession documentManager;
073
074    @DataModel("notificationList")
075    protected List<SelectableSubscription> notificationList;
076
077    @DataModel("inheritedNotifications")
078    private List<Notification> inheritedNotifications;
079
080    @DataModelSelection(value = "notificationList")
081    private SelectableSubscription currentSubscription;
082
083    @In(create = true)
084    protected transient NotificationManager notificationManager;
085
086    @In(create = true, required = false)
087    protected transient FacesMessages facesMessages;
088
089    @In(create = true)
090    protected ResourcesAccessor resourcesAccessor;
091
092    public static final String CONFIRM_FOLLOW = "label.subscriptions.follow.confirm";
093
094    public static final String CONFIRM_UNFOLLOW = "label.subscriptions.unfollow.confirm";
095
096    /**
097     * Gets all the notifications the user may subscribe to.
098     */
099    @Factory("notificationList")
100    public void getNotificationsList() {
101        log.debug("Factory for notifications list");
102
103        DocumentModel currentDocument = navigationContext.getCurrentDocument();
104        String superParentType = documentManager.getSuperParentType(currentDocument);
105
106        List<Notification> notifs = notificationManager.getNotificationsForSubscriptions(superParentType);
107
108        List<String> subscriptions = getSelectedNotifications();
109        log.debug("Selected notifications : " + subscriptions);
110
111        List<SelectableSubscription> notifsResult = new ArrayList<SelectableSubscription>();
112        for (Notification notification : notifs) {
113            String notifName = notification.getName();
114            if (subscriptions.contains(notifName)) {
115                notifsResult.add(new SelectableSubscription(true, notification));
116            } else {
117                notifsResult.add(new SelectableSubscription(false, notification));
118            }
119        }
120        notificationList = notifsResult;
121    }
122
123    /**
124     * Gets all the notifications the user may subscribe to.
125     */
126    @Factory("inheritedNotifications")
127    public void loadInheritedNotifications() throws ClassNotFoundException {
128        inheritedNotifications = new ArrayList<Notification>();
129        DocumentModel currentDoc = navigationContext.getCurrentDocument();
130        NuxeoPrincipal principal = (NuxeoPrincipal) FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
131        for (String group : principal.getAllGroups()) {
132            List<String> notifs = notificationManager.getSubscriptionsForUserOnDocument("group:" + group,
133                    currentDoc);
134            for (String inheritedNotification : notifs) {
135                Notification notif = notificationManager.getNotificationByName(inheritedNotification);
136                inheritedNotifications.add(notif);
137            }
138        }
139    }
140
141    /**
142     * Registers the user's choices.
143     */
144    public void updateSubscriptions() {
145
146        NuxeoPrincipal principal = (NuxeoPrincipal) FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
147        DocumentModel currentDoc = navigationContext.getCurrentDocument();
148        if (currentSubscription.isSelected()) {
149            notificationManager.removeSubscription("user:" + principal.getName(),
150                    currentSubscription.getNotification().getName(), currentDoc);
151        } else {
152            notificationManager.addSubscription(NotificationConstants.USER_PREFIX + principal.getName(),
153                    currentSubscription.getNotification().getName(), currentDoc, false, principal, "");
154        }
155        getNotificationsList();
156    }
157
158    /**
159     * Manage (un)subscription to all notifications
160     */
161    public void updateAllSubscriptions() {
162        NuxeoPrincipal principal = (NuxeoPrincipal) FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
163        DocumentModel currentDoc = navigationContext.getCurrentDocument();
164        List<String> userSubscriptions = notificationManager.getSubscriptionsForUserOnDocument(
165                NotificationConstants.USER_PREFIX + principal.getName(), currentDoc);
166        if (userSubscriptions.size() == 0) {
167            notificationManager.addSubscriptions(NotificationConstants.USER_PREFIX + principal.getName(), currentDoc,
168                    false, principal);
169            facesMessages.add(StatusMessage.Severity.INFO, resourcesAccessor.getMessages().get(CONFIRM_FOLLOW));
170        } else {
171            notificationManager.removeSubscriptions(NotificationConstants.USER_PREFIX + principal.getName(),
172                    userSubscriptions, currentDoc);
173            facesMessages.add(StatusMessage.Severity.INFO, resourcesAccessor.getMessages().get(CONFIRM_UNFOLLOW));
174        }
175        getNotificationsList();
176    }
177
178    @Observer(value = EventNames.DOCUMENT_SELECTION_CHANGED, create = false)
179    @BypassInterceptors
180    public void invalidateNotificationsSelection() {
181        log.debug("Invalidate archive records.................");
182        notificationList = null;
183        currentSubscription = null;
184        inheritedNotifications = null;
185    }
186
187    /**
188     * @return the previously selected notifications.
189     */
190    public List<String> getSelectedNotifications() {
191        return getSubscriptionsForCurrentUser();
192    }
193
194    /**
195     * Returns the notifications that the user already subscribed for.
196     */
197    private List<String> getSubscriptionsForCurrentUser() {
198
199        DocumentModel currentDoc = navigationContext.getCurrentDocument();
200        if (currentDoc == null) {
201            return Collections.emptyList();
202        }
203        NuxeoPrincipal principal = (NuxeoPrincipal) FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
204        List<String> subscriptions = notificationManager.getSubscriptionsForUserOnDocument(
205                "user:" + principal.getName(), currentDoc);
206        return subscriptions;
207    }
208
209    public SelectableSubscription getCurrentSubscription() {
210        return currentSubscription;
211    }
212
213    public void setCurrentSubscription(SelectableSubscription currentSubscription) {
214        this.currentSubscription = currentSubscription;
215    }
216
217    public List<SelectableSubscription> getNotificationList() {
218        return notificationList;
219    }
220
221    public void setNotificationList(List<SelectableSubscription> notificationList) {
222        this.notificationList = notificationList;
223    }
224
225    public List<Notification> getInheritedNotifications() {
226        return inheritedNotifications;
227    }
228
229    public void setInheritedNotifications(List<Notification> inheritedNotifications) {
230        this.inheritedNotifications = inheritedNotifications;
231    }
232
233    /**
234     * @since 9.2
235     */
236    public boolean canFollow() {
237        return !navigationContext.getCurrentDocument().isProxy();
238    }
239
240}