001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.trash.util;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
021    import com.liferay.portal.kernel.portlet.PortletProvider;
022    import com.liferay.portal.kernel.portlet.PortletProviderUtil;
023    import com.liferay.portal.kernel.search.Document;
024    import com.liferay.portal.kernel.search.Field;
025    import com.liferay.portal.kernel.search.Hits;
026    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
027    import com.liferay.portal.kernel.servlet.SessionMessages;
028    import com.liferay.portal.kernel.trash.TrashHandler;
029    import com.liferay.portal.kernel.trash.TrashHandlerRegistryUtil;
030    import com.liferay.portal.kernel.trash.TrashRenderer;
031    import com.liferay.portal.kernel.util.ArrayUtil;
032    import com.liferay.portal.kernel.util.Constants;
033    import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil;
034    import com.liferay.portal.kernel.util.GetterUtil;
035    import com.liferay.portal.kernel.util.OrderByComparator;
036    import com.liferay.portal.kernel.util.PrefsPropsUtil;
037    import com.liferay.portal.kernel.util.PropsKeys;
038    import com.liferay.portal.kernel.util.StringBundler;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.kernel.util.StringUtil;
041    import com.liferay.portal.kernel.util.UnicodeProperties;
042    import com.liferay.portal.kernel.util.Validator;
043    import com.liferay.portal.kernel.workflow.WorkflowConstants;
044    import com.liferay.portal.model.ContainerModel;
045    import com.liferay.portal.model.Group;
046    import com.liferay.portal.model.Layout;
047    import com.liferay.portal.model.TrashedModel;
048    import com.liferay.portal.service.GroupLocalServiceUtil;
049    import com.liferay.portal.service.permission.PortletPermissionUtil;
050    import com.liferay.portal.theme.ThemeDisplay;
051    import com.liferay.portal.util.PortalUtil;
052    import com.liferay.portal.util.PropsValues;
053    import com.liferay.portal.util.WebKeys;
054    import com.liferay.portlet.PortletURLUtil;
055    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
056    import com.liferay.portlet.trash.model.TrashEntry;
057    import com.liferay.portlet.trash.model.TrashVersion;
058    import com.liferay.portlet.trash.model.impl.TrashEntryImpl;
059    import com.liferay.portlet.trash.service.TrashEntryLocalServiceUtil;
060    import com.liferay.portlet.trash.service.TrashVersionLocalServiceUtil;
061    import com.liferay.portlet.trash.util.comparator.EntryCreateDateComparator;
062    import com.liferay.portlet.trash.util.comparator.EntryTypeComparator;
063    import com.liferay.portlet.trash.util.comparator.EntryUserNameComparator;
064    
065    import java.text.Format;
066    
067    import java.util.ArrayList;
068    import java.util.Collections;
069    import java.util.Date;
070    import java.util.HashMap;
071    import java.util.List;
072    import java.util.Map;
073    
074    import javax.portlet.ActionRequest;
075    import javax.portlet.PortletException;
076    import javax.portlet.PortletRequest;
077    import javax.portlet.PortletURL;
078    
079    import javax.servlet.http.HttpServletRequest;
080    
081    /**
082     * @author Sergio Gonz??lez
083     * @author Julio Camarero
084     */
085    @DoPrivileged
086    public class TrashImpl implements Trash {
087    
088            @Override
089            public void addBaseModelBreadcrumbEntries(
090                            HttpServletRequest request,
091                            LiferayPortletResponse liferayPortletResponse, String className,
092                            long classPK, PortletURL containerModelURL)
093                    throws PortalException, PortletException {
094    
095                    addBreadcrumbEntries(
096                            request, liferayPortletResponse, className, classPK, "classPK",
097                            containerModelURL, true);
098            }
099    
100            @Override
101            public void addContainerModelBreadcrumbEntries(
102                            HttpServletRequest request,
103                            LiferayPortletResponse liferayPortletResponse, String className,
104                            long classPK, PortletURL containerModelURL)
105                    throws PortalException, PortletException {
106    
107                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
108                            WebKeys.THEME_DISPLAY);
109    
110                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
111                            className);
112    
113                    String rootContainerModelTitle =
114                            trashHandler.getRootContainerModelTitle(
115                                    classPK, themeDisplay.getLocale());
116    
117                    if (classPK == 0) {
118                            PortalUtil.addPortletBreadcrumbEntry(
119                                    request, rootContainerModelTitle, null);
120    
121                            return;
122                    }
123    
124                    containerModelURL.setParameter("containerModelId", "0");
125    
126                    PortalUtil.addPortletBreadcrumbEntry(
127                            request, rootContainerModelTitle, containerModelURL.toString());
128    
129                    addBreadcrumbEntries(
130                            request, liferayPortletResponse, className, classPK,
131                            "containerModelId", containerModelURL, false);
132            }
133    
134            @Override
135            public void addTrashSessionMessages(
136                    ActionRequest actionRequest, List<TrashedModel> trashedModels) {
137    
138                    addTrashSessionMessages(
139                            actionRequest, trashedModels, Constants.MOVE_TO_TRASH);
140            }
141    
142            @Override
143            public void addTrashSessionMessages(
144                    ActionRequest actionRequest, List<TrashedModel> trashedModels,
145                    String cmd) {
146    
147                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
148                            WebKeys.THEME_DISPLAY);
149    
150                    List<String> classNames = new ArrayList<>();
151                    List<Long> restoreTrashEntryIds = new ArrayList<>();
152                    List<String> titles = new ArrayList<>();
153    
154                    for (int i = 0; i < trashedModels.size(); i++) {
155                            try {
156                                    TrashedModel trashedModel = trashedModels.get(i);
157    
158                                    TrashEntry trashEntry = trashedModel.getTrashEntry();
159    
160                                    TrashHandler trashHandler = trashedModel.getTrashHandler();
161    
162                                    TrashRenderer trashRenderer = trashHandler.getTrashRenderer(
163                                            trashedModel.getTrashEntryClassPK());
164    
165                                    classNames.add(trashRenderer.getClassName());
166                                    restoreTrashEntryIds.add(trashEntry.getEntryId());
167                                    titles.add(trashRenderer.getTitle(themeDisplay.getLocale()));
168                            }
169                            catch (Exception e) {
170                            }
171                    }
172    
173                    Map<String, String[]> data = new HashMap<>();
174    
175                    data.put(Constants.CMD, new String[] {cmd});
176    
177                    data.put(
178                            "deleteEntryClassName",
179                            ArrayUtil.toStringArray(classNames.toArray()));
180                    data.put("deleteEntryTitle", ArrayUtil.toStringArray(titles.toArray()));
181                    data.put(
182                            "restoreTrashEntryIds",
183                            ArrayUtil.toStringArray(restoreTrashEntryIds.toArray()));
184    
185                    SessionMessages.add(
186                            actionRequest,
187                            PortalUtil.getPortletId(actionRequest) +
188                                    SessionMessages.KEY_SUFFIX_DELETE_SUCCESS_DATA, data);
189            }
190    
191            @Override
192            public void addTrashSessionMessages(
193                    ActionRequest actionRequest, TrashedModel trashedModel) {
194    
195                    addTrashSessionMessages(
196                            actionRequest, trashedModel, Constants.MOVE_TO_TRASH);
197            }
198    
199            @Override
200            public void addTrashSessionMessages(
201                    ActionRequest actionRequest, TrashedModel trashedModel, String cmd) {
202    
203                    List<TrashedModel> trashedModels = new ArrayList<>();
204    
205                    trashedModels.add(trashedModel);
206    
207                    addTrashSessionMessages(actionRequest, trashedModels, cmd);
208            }
209    
210            @Override
211            public void deleteEntriesAttachments(
212                            long companyId, long repositoryId, Date date,
213                            String[] attachmentFileNames)
214                    throws PortalException {
215    
216                    for (String attachmentFileName : attachmentFileNames) {
217                            String trashTime = TrashUtil.getTrashTime(
218                                    attachmentFileName, TRASH_TIME_SEPARATOR);
219    
220                            long timestamp = GetterUtil.getLong(trashTime);
221    
222                            if (timestamp < date.getTime()) {
223                                    DLStoreUtil.deleteDirectory(
224                                            companyId, repositoryId, attachmentFileName);
225                            }
226                    }
227            }
228    
229            @Override
230            public Group disableTrash(Group group) {
231                    UnicodeProperties typeSettingsProperties =
232                            group.getParentLiveGroupTypeSettingsProperties();
233    
234                    typeSettingsProperties.setProperty("trashEnabled", StringPool.FALSE);
235    
236                    group.setTypeSettingsProperties(typeSettingsProperties);
237    
238                    return GroupLocalServiceUtil.updateGroup(group);
239            }
240    
241            @Override
242            public List<TrashEntry> getEntries(Hits hits) {
243                    List<TrashEntry> entries = new ArrayList<>();
244    
245                    for (Document document : hits.getDocs()) {
246                            String entryClassName = GetterUtil.getString(
247                                    document.get(Field.ENTRY_CLASS_NAME));
248                            long classPK = GetterUtil.getLong(
249                                    document.get(Field.ENTRY_CLASS_PK));
250    
251                            try {
252                                    TrashEntry entry = TrashEntryLocalServiceUtil.fetchEntry(
253                                            entryClassName, classPK);
254    
255                                    if (entry == null) {
256                                            String userName = GetterUtil.getString(
257                                                    document.get(Field.REMOVED_BY_USER_NAME));
258    
259                                            Date removedDate = document.getDate(Field.REMOVED_DATE);
260    
261                                            entry = new TrashEntryImpl();
262    
263                                            entry.setClassName(entryClassName);
264                                            entry.setClassPK(classPK);
265    
266                                            entry.setUserName(userName);
267                                            entry.setCreateDate(removedDate);
268    
269                                            String rootEntryClassName = GetterUtil.getString(
270                                                    document.get(Field.ROOT_ENTRY_CLASS_NAME));
271                                            long rootEntryClassPK = GetterUtil.getLong(
272                                                    document.get(Field.ROOT_ENTRY_CLASS_PK));
273    
274                                            TrashEntry rootTrashEntry =
275                                                    TrashEntryLocalServiceUtil.fetchEntry(
276                                                            rootEntryClassName, rootEntryClassPK);
277    
278                                            if (rootTrashEntry != null) {
279                                                    entry.setRootEntry(rootTrashEntry);
280                                            }
281                                    }
282    
283                                    entries.add(entry);
284                            }
285                            catch (Exception e) {
286                                    if (_log.isWarnEnabled()) {
287                                            _log.warn(
288                                                    "Unable to find trash entry for " + entryClassName +
289                                                            " with primary key " + classPK);
290                                    }
291                            }
292                    }
293    
294                    return entries;
295            }
296    
297            @Override
298            public OrderByComparator<TrashEntry> getEntryOrderByComparator(
299                    String orderByCol, String orderByType) {
300    
301                    boolean orderByAsc = false;
302    
303                    if (orderByType.equals("asc")) {
304                            orderByAsc = true;
305                    }
306    
307                    OrderByComparator<TrashEntry> orderByComparator = null;
308    
309                    if (orderByCol.equals("removed-by")) {
310                            orderByComparator = new EntryUserNameComparator(orderByAsc);
311                    }
312                    else if (orderByCol.equals("removed-date")) {
313                            orderByComparator = new EntryCreateDateComparator(orderByAsc);
314                    }
315                    else if (orderByCol.equals("type")) {
316                            orderByComparator = new EntryTypeComparator(orderByAsc);
317                    }
318    
319                    return orderByComparator;
320            }
321    
322            @Override
323            public int getMaxAge(Group group) {
324                    int trashEntriesMaxAge = PrefsPropsUtil.getInteger(
325                            group.getCompanyId(), PropsKeys.TRASH_ENTRIES_MAX_AGE,
326                            PropsValues.TRASH_ENTRIES_MAX_AGE);
327    
328                    UnicodeProperties typeSettingsProperties =
329                            group.getParentLiveGroupTypeSettingsProperties();
330    
331                    return GetterUtil.getInteger(
332                            typeSettingsProperties.getProperty("trashEntriesMaxAge"),
333                            trashEntriesMaxAge);
334            }
335    
336            @Override
337            public String getNewName(String oldName, String token) {
338                    StringBundler sb = new StringBundler(3);
339    
340                    sb.append(oldName);
341                    sb.append(StringPool.SPACE);
342                    sb.append(token);
343    
344                    return sb.toString();
345            }
346    
347            @Override
348            public String getNewName(
349                            ThemeDisplay themeDisplay, String className, long classPK,
350                            String oldName)
351                    throws PortalException {
352    
353                    TrashRenderer trashRenderer = null;
354    
355                    if (Validator.isNotNull(className) && (classPK > 0)) {
356                            TrashHandler trashHandler =
357                                    TrashHandlerRegistryUtil.getTrashHandler(className);
358    
359                            trashRenderer = trashHandler.getTrashRenderer(classPK);
360                    }
361    
362                    Format dateFormatDateTime = FastDateFormatFactoryUtil.getDateTime(
363                            themeDisplay.getLocale(), themeDisplay.getTimeZone());
364    
365                    StringBundler sb = new StringBundler(3);
366    
367                    sb.append(StringPool.OPEN_PARENTHESIS);
368                    sb.append(
369                            StringUtil.replace(
370                                    dateFormatDateTime.format(new Date()),
371                                    new String[] {StringPool.SLASH, StringPool.COLON},
372                                    new String[] {StringPool.PERIOD, StringPool.PERIOD}));
373                    sb.append(StringPool.CLOSE_PARENTHESIS);
374    
375                    if (trashRenderer != null) {
376                            return trashRenderer.getNewName(oldName, sb.toString());
377                    }
378                    else {
379                            return getNewName(oldName, sb.toString());
380                    }
381            }
382    
383            @Override
384            public String getOriginalTitle(String title) {
385                    return getOriginalTitle(title, "title", StringPool.SLASH);
386            }
387    
388            @Override
389            public String getOriginalTitle(String title, String paramName) {
390                    return getOriginalTitle(title, paramName, StringPool.SLASH);
391            }
392    
393            @Override
394            public String getTrashTime(String title, String separator) {
395                    int index = title.lastIndexOf(separator);
396    
397                    if (index < 0) {
398                            return StringPool.BLANK;
399                    }
400    
401                    return title.substring(index + 1, title.length());
402            }
403    
404            @Override
405            public String getTrashTitle(long trashEntryId) {
406                    return getTrashTitle(trashEntryId, StringPool.SLASH);
407            }
408    
409            @Override
410            public PortletURL getViewContentURL(
411                            HttpServletRequest request, long trashEntryId)
412                    throws PortalException {
413    
414                    TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
415                            trashEntryId);
416    
417                    return getViewContentURL(
418                            request, trashEntry.getClassName(), trashEntry.getClassPK());
419            }
420    
421            @Override
422            public PortletURL getViewContentURL(
423                            HttpServletRequest request, String className, long classPK)
424                    throws PortalException {
425    
426                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
427                            WebKeys.THEME_DISPLAY);
428    
429                    String portletId = PortletProviderUtil.getPortletId(
430                            TrashEntry.class.getName(), PortletProvider.Action.VIEW);
431    
432                    if (!themeDisplay.isSignedIn() ||
433                            !isTrashEnabled(themeDisplay.getScopeGroupId()) ||
434                            !PortletPermissionUtil.hasControlPanelAccessPermission(
435                                    themeDisplay.getPermissionChecker(),
436                                    themeDisplay.getScopeGroupId(), portletId)) {
437    
438                            return null;
439                    }
440    
441                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
442                            className);
443    
444                    if (trashHandler.isInTrashContainer(classPK)) {
445                            TrashEntry trashEntry = trashHandler.getTrashEntry(classPK);
446    
447                            className = trashEntry.getClassName();
448                            classPK = trashEntry.getClassPK();
449    
450                            trashHandler = TrashHandlerRegistryUtil.getTrashHandler(className);
451                    }
452    
453                    TrashRenderer trashRenderer = trashHandler.getTrashRenderer(classPK);
454    
455                    if (trashRenderer == null) {
456                            return null;
457                    }
458    
459                    Layout layout = themeDisplay.getLayout();
460    
461                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
462                            request, portletId, layout.getLayoutId(),
463                            PortletRequest.RENDER_PHASE);
464    
465                    portletURL.setParameter("mvcPath", "/view_content.jsp");
466                    portletURL.setParameter("redirect", themeDisplay.getURLCurrent());
467    
468                    TrashEntry trashEntry = TrashEntryLocalServiceUtil.getEntry(
469                            className, classPK);
470    
471                    if (trashEntry.getRootEntry() != null) {
472                            portletURL.setParameter("className", className);
473                            portletURL.setParameter("classPK", String.valueOf(classPK));
474                    }
475                    else {
476                            portletURL.setParameter(
477                                    "trashEntryId", String.valueOf(trashEntry.getEntryId()));
478                    }
479    
480                    portletURL.setParameter("type", trashRenderer.getType());
481                    portletURL.setParameter(
482                            "status", String.valueOf(WorkflowConstants.STATUS_IN_TRASH));
483                    portletURL.setParameter("showActions", Boolean.FALSE.toString());
484                    portletURL.setParameter("showAssetMetadata", Boolean.TRUE.toString());
485                    portletURL.setParameter("showEditURL", Boolean.FALSE.toString());
486    
487                    return portletURL;
488            }
489    
490            @Override
491            public PortletURL getViewURL(HttpServletRequest request)
492                    throws PortalException {
493    
494                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
495                            WebKeys.THEME_DISPLAY);
496    
497                    String portletId = PortletProviderUtil.getPortletId(
498                            TrashEntry.class.getName(), PortletProvider.Action.VIEW);
499    
500                    if (!themeDisplay.isSignedIn() ||
501                            !isTrashEnabled(themeDisplay.getScopeGroupId()) ||
502                            !PortletPermissionUtil.hasControlPanelAccessPermission(
503                                    themeDisplay.getPermissionChecker(),
504                                    themeDisplay.getScopeGroupId(), portletId)) {
505    
506                            return null;
507                    }
508    
509                    Layout layout = themeDisplay.getLayout();
510    
511                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
512                            request, portletId, layout.getLayoutId(),
513                            PortletRequest.RENDER_PHASE);
514    
515                    portletURL.setParameter("redirect", themeDisplay.getURLCurrent());
516    
517                    return portletURL;
518            }
519    
520            @Override
521            public boolean isInTrash(String className, long classPK)
522                    throws PortalException {
523    
524                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
525                            className);
526    
527                    if (trashHandler == null) {
528                            return false;
529                    }
530    
531                    return trashHandler.isInTrash(classPK);
532            }
533    
534            @Override
535            public boolean isTrashEnabled(Group group) {
536                    boolean companyTrashEnabled = PrefsPropsUtil.getBoolean(
537                            group.getCompanyId(), PropsKeys.TRASH_ENABLED);
538    
539                    if (!companyTrashEnabled) {
540                            return false;
541                    }
542    
543                    UnicodeProperties typeSettingsProperties =
544                            group.getParentLiveGroupTypeSettingsProperties();
545    
546                    return GetterUtil.getBoolean(
547                            typeSettingsProperties.getProperty("trashEnabled"), true);
548            }
549    
550            @Override
551            public boolean isTrashEnabled(long groupId) throws PortalException {
552                    return isTrashEnabled(GroupLocalServiceUtil.getGroup(groupId));
553            }
554    
555            protected void addBreadcrumbEntries(
556                            HttpServletRequest request,
557                            LiferayPortletResponse liferayPortletResponse, String className,
558                            long classPK, String paramName, PortletURL containerModelURL,
559                            boolean checkInTrashContainers)
560                    throws PortalException, PortletException {
561    
562                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
563                            WebKeys.THEME_DISPLAY);
564    
565                    PortletURL portletURL = PortletURLUtil.clone(
566                            containerModelURL, liferayPortletResponse);
567    
568                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
569                            className);
570    
571                    List<ContainerModel> containerModels =
572                            trashHandler.getParentContainerModels(classPK);
573    
574                    Collections.reverse(containerModels);
575    
576                    for (ContainerModel containerModel : containerModels) {
577                            TrashHandler containerModelTrashHandler =
578                                    TrashHandlerRegistryUtil.getTrashHandler(
579                                            containerModel.getModelClassName());
580    
581                            if (checkInTrashContainers &&
582                                    !containerModelTrashHandler.isInTrash(
583                                            containerModel.getContainerModelId())) {
584    
585                                    continue;
586                            }
587    
588                            portletURL.setParameter(
589                                    paramName,
590                                    String.valueOf(containerModel.getContainerModelId()));
591    
592                            String name = containerModel.getContainerModelName();
593    
594                            if (containerModelTrashHandler.isInTrash(
595                                            containerModel.getContainerModelId())) {
596    
597                                    name = TrashUtil.getOriginalTitle(name);
598                            }
599    
600                            PortalUtil.addPortletBreadcrumbEntry(
601                                    request, name, portletURL.toString());
602                    }
603    
604                    TrashRenderer trashRenderer = trashHandler.getTrashRenderer(classPK);
605    
606                    PortalUtil.addPortletBreadcrumbEntry(
607                            request, trashRenderer.getTitle(themeDisplay.getLocale()), null);
608            }
609    
610            protected String getOriginalTitle(
611                    String title, String paramName, String prefix) {
612    
613                    if (!title.startsWith(prefix)) {
614                            return title;
615                    }
616    
617                    title = title.substring(prefix.length());
618    
619                    long trashEntryId = GetterUtil.getLong(title);
620    
621                    if (trashEntryId <= 0) {
622                            return title;
623                    }
624    
625                    try {
626                            TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
627                                    trashEntryId);
628    
629                            if (trashEntry == null) {
630                                    TrashVersion trashVersion =
631                                            TrashVersionLocalServiceUtil.getTrashVersion(trashEntryId);
632    
633                                    title = trashVersion.getTypeSettingsProperty(paramName);
634                            }
635                            else {
636                                    title = trashEntry.getTypeSettingsProperty(paramName);
637                            }
638                    }
639                    catch (Exception e) {
640                            if (_log.isDebugEnabled()) {
641                                    _log.debug(
642                                            "No trash entry or trash version exists with ID " +
643                                                    trashEntryId);
644                            }
645                    }
646    
647                    return title;
648            }
649    
650            protected String getTrashTitle(long trashEntryId, String prefix) {
651                    return prefix.concat(String.valueOf(trashEntryId));
652            }
653    
654            private static final Log _log = LogFactoryUtil.getLog(TrashImpl.class);
655    
656    }