001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.db;
029
030import org.opencms.file.CmsGroup;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.file.CmsUser;
035import org.opencms.file.history.I_CmsHistoryResource;
036import org.opencms.main.CmsException;
037import org.opencms.main.CmsRuntimeException;
038import org.opencms.main.OpenCms;
039import org.opencms.security.CmsPrincipal;
040import org.opencms.security.CmsRole;
041import org.opencms.security.CmsRoleViolationException;
042import org.opencms.util.CmsStringUtil;
043
044import java.util.List;
045
046/**
047 * Manager that provides methods to subscribe resources to users, read subscribed or unvisited resources and more.<p>
048 *
049 * @since 8.0
050 */
051public class CmsSubscriptionManager {
052
053    /** The default maximum number of visited resources to store per user. */
054    private static final int DEFAULT_MAX_VISITEDCOUNT = 1000;
055
056    /** The security manager to access the cms. */
057    protected CmsSecurityManager m_securityManager;
058
059    /** Indicates if the subscription functionality is enabled. */
060    private boolean m_enabled;
061
062    /** Indicates if the configuration can be modified. */
063    private boolean m_frozen;
064
065    /** The maximum number of visited resources to store per user. */
066    private int m_maxVisitedCount;
067
068    /** The name of the database pool to use. */
069    private String m_poolName;
070
071    /**
072     * Initializes a new CmsSubscriptionManager, called from the configuration.<p>
073     */
074    public CmsSubscriptionManager() {
075
076        m_frozen = false;
077    }
078
079    /**
080     * Returns the date when the resource was last visited by the user.<p>
081     *
082     * @param cms the current users context
083     * @param user the user to check the date
084     * @param resource the resource to check the date
085     *
086     * @return the date when the resource was last visited by the user
087     *
088     * @throws CmsException if something goes wrong
089     */
090    public long getDateLastVisitedBy(CmsObject cms, CmsUser user, CmsResource resource) throws CmsException {
091
092        return m_securityManager.getDateLastVisitedBy(cms.getRequestContext(), getPoolName(), user, resource);
093    }
094
095    /**
096     * Returns the date when the resource was last visited by the user.<p>
097     *
098     * @param cms the current users context
099     * @param user the user to check the date
100     * @param resourcePath the name of the resource to check the date
101     *
102     * @return the date when the resource was last visited by the user
103     *
104     * @throws CmsException if something goes wrong
105     */
106    public long getDateLastVisitedBy(CmsObject cms, CmsUser user, String resourcePath) throws CmsException {
107
108        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
109        return m_securityManager.getDateLastVisitedBy(cms.getRequestContext(), getPoolName(), user, resource);
110    }
111
112    /**
113     * Returns the maximum number of visited resources to store per user.<p>
114     *
115     * @return the maximum number of visited resources to store per user
116     */
117    public int getMaxVisitedCount() {
118
119        if (m_maxVisitedCount < 1) {
120            m_maxVisitedCount = DEFAULT_MAX_VISITEDCOUNT;
121        }
122        return m_maxVisitedCount;
123    }
124
125    /**
126     * Returns the name of the database pool to use.<p>
127     *
128     * @return the name of the database pool to use
129     */
130    public String getPoolName() {
131
132        if (CmsStringUtil.isEmpty(m_poolName)) {
133            // use default pool as pool name
134            m_poolName = OpenCms.getSqlManager().getDefaultDbPoolName();
135        }
136        return m_poolName;
137    }
138
139    /**
140     * Initializes this subscription manager with the OpenCms system configuration.<p>
141     *
142     * @param cms an OpenCms context object that must have been initialized with "Admin" permissions
143     *
144     * @throws CmsRoleViolationException in case the given opencms object does not have <code>{@link CmsRole#ROOT_ADMIN}</code> permissions
145     */
146    public void initialize(CmsObject cms) throws CmsRoleViolationException {
147
148        OpenCms.getRoleManager().checkRole(cms, CmsRole.ROOT_ADMIN);
149        m_frozen = true;
150    }
151
152    /**
153     * Returns if the subscription functionality is enabled.<p>
154     *
155     * @return <code>true</code> if the subscription functionality is enabled, otherwise <code>false</code>
156     */
157    public boolean isEnabled() {
158
159        return m_enabled && (m_securityManager != null) && m_securityManager.isSubscriptionDriverAvailable();
160    }
161
162    /**
163     * Mark the given resource as visited by the user.<p>
164     *
165     * @param cms the current users context
166     * @param resource the resource to mark as visited
167     * @param user the user that visited the resource
168     *
169     * @throws CmsException if something goes wrong
170     */
171    public void markResourceAsVisitedBy(CmsObject cms, CmsResource resource, CmsUser user) throws CmsException {
172
173        if (!isEnabled()) {
174            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
175        }
176        m_securityManager.markResourceAsVisitedBy(cms.getRequestContext(), getPoolName(), resource, user);
177    }
178
179    /**
180     * Mark the given resource as visited by the user.<p>
181     *
182     * @param cms the current users context
183     * @param resourcePath the name of the resource to mark as visited
184     * @param user the user that visited the resource
185     *
186     * @throws CmsException if something goes wrong
187     */
188    public void markResourceAsVisitedBy(CmsObject cms, String resourcePath, CmsUser user) throws CmsException {
189
190        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
191        markResourceAsVisitedBy(cms, resource, user);
192    }
193
194    /**
195     * Returns all resources subscribed by the given user or group.<p>
196     *
197     * @param cms the current users context
198     * @param principal the principal to read the subscribed resources
199     *
200     * @return all resources subscribed by the given user or group
201     *
202     * @throws CmsException if something goes wrong
203     */
204    public List<CmsResource> readAllSubscribedResources(CmsObject cms, CmsPrincipal principal) throws CmsException {
205
206        return m_securityManager.readAllSubscribedResources(cms.getRequestContext(), getPoolName(), principal);
207    }
208
209    /**
210     * Returns the resources that were visited by a user set in the filter.<p>
211     *
212     * @param cms the current users context
213     * @param filter the filter that is used to get the visited resources
214     *
215     * @return the resources that were visited by a user set in the filter
216     *
217     * @throws CmsException if something goes wrong
218     */
219    public List<CmsResource> readResourcesVisitedBy(CmsObject cms, CmsVisitedByFilter filter) throws CmsException {
220
221        return m_securityManager.readResourcesVisitedBy(cms.getRequestContext(), getPoolName(), filter);
222    }
223
224    /**
225     * Returns the subscribed history resources that were deleted.<p>
226     *
227     * @param cms the current users context
228     * @param user the user that subscribed to the resource
229     * @param includeGroups indicates if the users groups should also be checked for subscribed deleted resources
230     * @param folderPath the folder path of the deleted resources, if <code>null</code> all deleted resources will be returned
231     * @param includeSubFolders indicates if the sub folders of the specified folder path should be considered, too
232     * @param deletedFrom the time stamp from which the resources should have been deleted
233     *
234     * @return the subscribed history resources that were deleted
235     *
236     * @throws CmsException if something goes wrong
237     */
238    public List<I_CmsHistoryResource> readSubscribedDeletedResources(
239        CmsObject cms,
240        CmsUser user,
241        boolean includeGroups,
242        String folderPath,
243        boolean includeSubFolders,
244        long deletedFrom)
245    throws CmsException {
246
247        List<CmsGroup> groups = null;
248        if (includeGroups) {
249            try {
250                groups = cms.getGroupsOfUser(user.getName(), false);
251            } catch (CmsException e) {
252                // failed to set user groups
253            }
254        }
255        CmsResource resource = null;
256        if (CmsStringUtil.isNotEmpty(folderPath)) {
257            resource = cms.readResource(folderPath, CmsResourceFilter.ALL);
258        }
259        return m_securityManager.readSubscribedDeletedResources(
260            cms.getRequestContext(),
261            getPoolName(),
262            user,
263            groups,
264            resource,
265            includeSubFolders,
266            deletedFrom);
267    }
268
269    /**
270     * Returns the resources that were subscribed by a user or group set in the filter.<p>
271     *
272     * @param cms the current users context
273     * @param filter the filter that is used to get the subscribed resources
274     *
275     * @return the resources that were subscribed by a user or group set in the filter
276     *
277     * @throws CmsException if something goes wrong
278     */
279    public List<CmsResource> readSubscribedResources(CmsObject cms, CmsSubscriptionFilter filter) throws CmsException {
280
281        return m_securityManager.readSubscribedResources(cms.getRequestContext(), getPoolName(), filter);
282    }
283
284    /**
285     * Sets if the subscription functionality is enabled.<p>
286     *
287     * @param enabled the flag indicating if the subscription functionality is enabled
288     */
289    public void setEnabled(boolean enabled) {
290
291        if (m_frozen) {
292            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
293        }
294        m_enabled = enabled;
295    }
296
297    /**
298     * Sets if the subscription functionality is enabled.<p>
299     *
300     * @param enabled the flag indicating if the subscription functionality is enabled
301     */
302    public void setEnabled(String enabled) {
303
304        if (m_frozen) {
305            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
306        }
307        m_enabled = Boolean.valueOf(enabled).booleanValue();
308    }
309
310    /**
311     * Sets the maximum number of visited resources to store per user.<p>
312     *
313     * @param maxVisitedCount the maximum number of visited resources to store per user
314     */
315    public void setMaxVisitedCount(String maxVisitedCount) {
316
317        if (m_frozen) {
318            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
319        }
320        try {
321            int intValue = Integer.parseInt(maxVisitedCount);
322            m_maxVisitedCount = (intValue > 0) ? intValue : DEFAULT_MAX_VISITEDCOUNT;
323        } catch (NumberFormatException e) {
324            // use default value
325            m_maxVisitedCount = DEFAULT_MAX_VISITEDCOUNT;
326        }
327    }
328
329    /**
330     * Sets the name of the database pool to use.<p>
331     *
332     * @param poolName the name of the database pool to use
333     */
334    public void setPoolName(String poolName) {
335
336        if (m_frozen) {
337            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
338        }
339        m_poolName = poolName;
340    }
341
342    /**
343     * Sets the security manager during initialization.<p>
344     *
345     * @param securityManager the security manager
346     */
347    public void setSecurityManager(CmsSecurityManager securityManager) {
348
349        if (m_frozen) {
350            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_CONFIG_SUBSCRIPTIONMANAGER_FROZEN_0));
351        }
352        m_securityManager = securityManager;
353    }
354
355    /**
356     * Marks a subscribed resource as deleted.<p>
357     *
358     * @param cms the current users context
359     * @param resource the subscribed resource to mark as deleted
360     *
361     * @throws CmsException if something goes wrong
362     */
363    public void setSubscribedResourceAsDeleted(CmsObject cms, CmsResource resource) throws CmsException {
364
365        if (!isEnabled()) {
366            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
367        }
368        m_securityManager.setSubscribedResourceAsDeleted(cms.getRequestContext(), getPoolName(), resource);
369    }
370
371    /**
372     * Subscribes the user or group to the resource.<p>
373     *
374     * @param cms the current users context
375     * @param principal the principal that subscribes to the resource
376     * @param resource the resource to subscribe to
377     *
378     * @throws CmsException if something goes wrong
379     */
380    public void subscribeResourceFor(CmsObject cms, CmsPrincipal principal, CmsResource resource) throws CmsException {
381
382        if (!isEnabled()) {
383            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
384        }
385        m_securityManager.subscribeResourceFor(cms.getRequestContext(), getPoolName(), principal, resource);
386    }
387
388    /**
389     * Subscribes the user or group to the resource.<p>
390     *
391     * @param cms the current users context
392     * @param principal the principal that subscribes to the resource
393     * @param resourcePath the name of the resource to subscribe to
394     *
395     * @throws CmsException if something goes wrong
396     */
397    public void subscribeResourceFor(CmsObject cms, CmsPrincipal principal, String resourcePath) throws CmsException {
398
399        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
400        subscribeResourceFor(cms, principal, resource);
401    }
402
403    /**
404     * Unsubscribes all deleted resources that were deleted before the specified time stamp.<p>
405     *
406     * @param cms the current users context
407     * @param deletedTo the time stamp to which the resources have been deleted
408     *
409     * @throws CmsException if something goes wrong
410     */
411    public void unsubscribeAllDeletedResources(CmsObject cms, long deletedTo) throws CmsException {
412
413        if (!isEnabled()) {
414            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
415        }
416        m_securityManager.unsubscribeAllDeletedResources(cms.getRequestContext(), getPoolName(), deletedTo);
417    }
418
419    /**
420    * Unsubscribes the user or group from all resources.<p>
421    *
422    * @param cms the current users context
423    * @param principal the principal that unsubscribes from all resources
424    *
425    * @throws CmsException if something goes wrong
426    */
427    public void unsubscribeAllResourcesFor(CmsObject cms, CmsPrincipal principal) throws CmsException {
428
429        if (!isEnabled()) {
430            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
431        }
432        m_securityManager.unsubscribeAllResourcesFor(cms.getRequestContext(), getPoolName(), principal);
433    }
434
435    /**
436     * Unsubscribes the principal from the resource.<p>
437     *
438     * @param cms the current users context
439     * @param principal the principal that unsubscribes from the resource
440     * @param resource the resource to unsubscribe from
441     *
442     * @throws CmsException if something goes wrong
443     */
444    public void unsubscribeResourceFor(CmsObject cms, CmsPrincipal principal, CmsResource resource)
445    throws CmsException {
446
447        if (!isEnabled()) {
448            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
449        }
450        m_securityManager.unsubscribeResourceFor(cms.getRequestContext(), getPoolName(), principal, resource);
451    }
452
453    /**
454     * Unsubscribes the principal from the resource.<p>
455     *
456     * @param cms the current users context
457     * @param principal the principal that unsubscribes from the resource
458     * @param resourcePath the name of the resource to unsubscribe from
459     *
460     * @throws CmsException if something goes wrong
461     */
462    public void unsubscribeResourceFor(CmsObject cms, CmsPrincipal principal, String resourcePath) throws CmsException {
463
464        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
465        unsubscribeResourceFor(cms, principal, resource);
466    }
467
468    /**
469     * Unsubscribes all groups and users from the resource.<p>
470     *
471     * @param cms the current users context
472     * @param resource the resource to unsubscribe all groups and users from
473     *
474     * @throws CmsException if something goes wrong
475     */
476    public void unsubscribeResourceForAll(CmsObject cms, CmsResource resource) throws CmsException {
477
478        if (!isEnabled()) {
479            throw new CmsRuntimeException(Messages.get().container(Messages.ERR_SUBSCRIPTION_MANAGER_DISABLED_0));
480        }
481        m_securityManager.unsubscribeResourceForAll(cms.getRequestContext(), getPoolName(), resource);
482    }
483
484    /**
485     * Unsubscribes all groups and users from the resource.<p>
486     *
487     * @param cms the current users context
488     * @param resourcePath the name of the resource to unsubscribe all groups and users from
489     *
490     * @throws CmsException if something goes wrong
491     */
492    public void unsubscribeResourceForAll(CmsObject cms, String resourcePath) throws CmsException {
493
494        CmsResource resource = cms.readResource(resourcePath, CmsResourceFilter.ALL);
495        unsubscribeResourceForAll(cms, resource);
496    }
497
498}