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.language.LanguageUtil;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
022    import com.liferay.portal.kernel.portlet.PortletProvider;
023    import com.liferay.portal.kernel.portlet.PortletProviderUtil;
024    import com.liferay.portal.kernel.search.Document;
025    import com.liferay.portal.kernel.search.Field;
026    import com.liferay.portal.kernel.search.Hits;
027    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
028    import com.liferay.portal.kernel.servlet.SessionMessages;
029    import com.liferay.portal.kernel.trash.TrashHandler;
030    import com.liferay.portal.kernel.trash.TrashHandlerRegistryUtil;
031    import com.liferay.portal.kernel.trash.TrashRenderer;
032    import com.liferay.portal.kernel.util.ArrayUtil;
033    import com.liferay.portal.kernel.util.Constants;
034    import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil;
035    import com.liferay.portal.kernel.util.GetterUtil;
036    import com.liferay.portal.kernel.util.OrderByComparator;
037    import com.liferay.portal.kernel.util.PrefsPropsUtil;
038    import com.liferay.portal.kernel.util.PropsKeys;
039    import com.liferay.portal.kernel.util.StringBundler;
040    import com.liferay.portal.kernel.util.StringPool;
041    import com.liferay.portal.kernel.util.StringUtil;
042    import com.liferay.portal.kernel.util.UnicodeProperties;
043    import com.liferay.portal.kernel.util.Validator;
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 = LanguageUtil.get(
114                            themeDisplay.getLocale(), trashHandler.getRootContainerModelName());
115    
116                    if (classPK == 0) {
117                            PortalUtil.addPortletBreadcrumbEntry(
118                                    request, rootContainerModelTitle, null);
119    
120                            return;
121                    }
122    
123                    containerModelURL.setParameter("containerModelId", "0");
124    
125                    PortalUtil.addPortletBreadcrumbEntry(
126                            request, rootContainerModelTitle, containerModelURL.toString());
127    
128                    addBreadcrumbEntries(
129                            request, liferayPortletResponse, className, classPK,
130                            "containerModelId", containerModelURL, false);
131            }
132    
133            @Override
134            public void addTrashSessionMessages(
135                    ActionRequest actionRequest, List<TrashedModel> trashedModels) {
136    
137                    addTrashSessionMessages(
138                            actionRequest, trashedModels, Constants.MOVE_TO_TRASH);
139            }
140    
141            @Override
142            public void addTrashSessionMessages(
143                    ActionRequest actionRequest, List<TrashedModel> trashedModels,
144                    String cmd) {
145    
146                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
147                            WebKeys.THEME_DISPLAY);
148    
149                    List<String> classNames = new ArrayList<>();
150                    List<Long> restoreTrashEntryIds = new ArrayList<>();
151                    List<String> titles = new ArrayList<>();
152    
153                    for (int i = 0; i < trashedModels.size(); i++) {
154                            try {
155                                    TrashedModel trashedModel = trashedModels.get(i);
156    
157                                    TrashEntry trashEntry = trashedModel.getTrashEntry();
158    
159                                    TrashHandler trashHandler = trashedModel.getTrashHandler();
160    
161                                    TrashRenderer trashRenderer = trashHandler.getTrashRenderer(
162                                            trashedModel.getTrashEntryClassPK());
163    
164                                    classNames.add(trashRenderer.getClassName());
165                                    restoreTrashEntryIds.add(trashEntry.getEntryId());
166                                    titles.add(trashRenderer.getTitle(themeDisplay.getLocale()));
167                            }
168                            catch (Exception e) {
169                            }
170                    }
171    
172                    Map<String, String[]> data = new HashMap<>();
173    
174                    data.put(Constants.CMD, new String[] {cmd});
175    
176                    data.put(
177                            "deleteEntryClassName",
178                            ArrayUtil.toStringArray(classNames.toArray()));
179                    data.put("deleteEntryTitle", ArrayUtil.toStringArray(titles.toArray()));
180                    data.put(
181                            "restoreTrashEntryIds",
182                            ArrayUtil.toStringArray(restoreTrashEntryIds.toArray()));
183    
184                    SessionMessages.add(
185                            actionRequest,
186                            PortalUtil.getPortletId(actionRequest) +
187                                    SessionMessages.KEY_SUFFIX_DELETE_SUCCESS_DATA,
188                            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    
215                    for (String attachmentFileName : attachmentFileNames) {
216                            String trashTime = TrashUtil.getTrashTime(
217                                    attachmentFileName, TRASH_TIME_SEPARATOR);
218    
219                            long timestamp = GetterUtil.getLong(trashTime);
220    
221                            if (timestamp < date.getTime()) {
222                                    DLStoreUtil.deleteDirectory(
223                                            companyId, repositoryId, attachmentFileName);
224                            }
225                    }
226            }
227    
228            @Override
229            public Group disableTrash(Group group) {
230                    UnicodeProperties typeSettingsProperties =
231                            group.getParentLiveGroupTypeSettingsProperties();
232    
233                    typeSettingsProperties.setProperty("trashEnabled", StringPool.FALSE);
234    
235                    group.setTypeSettingsProperties(typeSettingsProperties);
236    
237                    return GroupLocalServiceUtil.updateGroup(group);
238            }
239    
240            @Override
241            public List<TrashEntry> getEntries(Hits hits) {
242                    List<TrashEntry> entries = new ArrayList<>();
243    
244                    for (Document document : hits.getDocs()) {
245                            String entryClassName = GetterUtil.getString(
246                                    document.get(Field.ENTRY_CLASS_NAME));
247                            long classPK = GetterUtil.getLong(
248                                    document.get(Field.ENTRY_CLASS_PK));
249    
250                            try {
251                                    TrashEntry entry = TrashEntryLocalServiceUtil.fetchEntry(
252                                            entryClassName, classPK);
253    
254                                    if (entry == null) {
255                                            String userName = GetterUtil.getString(
256                                                    document.get(Field.REMOVED_BY_USER_NAME));
257    
258                                            Date removedDate = document.getDate(Field.REMOVED_DATE);
259    
260                                            entry = new TrashEntryImpl();
261    
262                                            entry.setClassName(entryClassName);
263                                            entry.setClassPK(classPK);
264    
265                                            entry.setUserName(userName);
266                                            entry.setCreateDate(removedDate);
267    
268                                            String rootEntryClassName = GetterUtil.getString(
269                                                    document.get(Field.ROOT_ENTRY_CLASS_NAME));
270                                            long rootEntryClassPK = GetterUtil.getLong(
271                                                    document.get(Field.ROOT_ENTRY_CLASS_PK));
272    
273                                            TrashEntry rootTrashEntry =
274                                                    TrashEntryLocalServiceUtil.fetchEntry(
275                                                            rootEntryClassName, rootEntryClassPK);
276    
277                                            if (rootTrashEntry != null) {
278                                                    entry.setRootEntry(rootTrashEntry);
279                                            }
280                                    }
281    
282                                    entries.add(entry);
283                            }
284                            catch (Exception e) {
285                                    if (_log.isWarnEnabled()) {
286                                            _log.warn(
287                                                    "Unable to find trash entry for " + entryClassName +
288                                                            " with primary key " + classPK);
289                                    }
290                            }
291                    }
292    
293                    return entries;
294            }
295    
296            @Override
297            public OrderByComparator<TrashEntry> getEntryOrderByComparator(
298                    String orderByCol, String orderByType) {
299    
300                    boolean orderByAsc = false;
301    
302                    if (orderByType.equals("asc")) {
303                            orderByAsc = true;
304                    }
305    
306                    OrderByComparator<TrashEntry> orderByComparator = null;
307    
308                    if (orderByCol.equals("removed-by")) {
309                            orderByComparator = new EntryUserNameComparator(orderByAsc);
310                    }
311                    else if (orderByCol.equals("removed-date")) {
312                            orderByComparator = new EntryCreateDateComparator(orderByAsc);
313                    }
314                    else if (orderByCol.equals("type")) {
315                            orderByComparator = new EntryTypeComparator(orderByAsc);
316                    }
317    
318                    return orderByComparator;
319            }
320    
321            @Override
322            public int getMaxAge(Group group) {
323                    int trashEntriesMaxAge = PrefsPropsUtil.getInteger(
324                            group.getCompanyId(), PropsKeys.TRASH_ENTRIES_MAX_AGE,
325                            PropsValues.TRASH_ENTRIES_MAX_AGE);
326    
327                    UnicodeProperties typeSettingsProperties =
328                            group.getParentLiveGroupTypeSettingsProperties();
329    
330                    return GetterUtil.getInteger(
331                            typeSettingsProperties.getProperty("trashEntriesMaxAge"),
332                            trashEntriesMaxAge);
333            }
334    
335            @Override
336            public String getNewName(String oldName, String token) {
337                    StringBundler sb = new StringBundler(3);
338    
339                    sb.append(oldName);
340                    sb.append(StringPool.SPACE);
341                    sb.append(token);
342    
343                    return sb.toString();
344            }
345    
346            @Override
347            public String getNewName(
348                            ThemeDisplay themeDisplay, String className, long classPK,
349                            String oldName)
350                    throws PortalException {
351    
352                    TrashRenderer trashRenderer = null;
353    
354                    if (Validator.isNotNull(className) && (classPK > 0)) {
355                            TrashHandler trashHandler =
356                                    TrashHandlerRegistryUtil.getTrashHandler(className);
357    
358                            trashRenderer = trashHandler.getTrashRenderer(classPK);
359                    }
360    
361                    Format dateFormatDateTime = FastDateFormatFactoryUtil.getDateTime(
362                            themeDisplay.getLocale(), themeDisplay.getTimeZone());
363    
364                    StringBundler sb = new StringBundler(3);
365    
366                    sb.append(StringPool.OPEN_PARENTHESIS);
367                    sb.append(
368                            StringUtil.replace(
369                                    dateFormatDateTime.format(new Date()),
370                                    new String[] {StringPool.SLASH, StringPool.COLON},
371                                    new String[] {StringPool.PERIOD, StringPool.PERIOD}));
372                    sb.append(StringPool.CLOSE_PARENTHESIS);
373    
374                    if (trashRenderer != null) {
375                            return trashRenderer.getNewName(oldName, sb.toString());
376                    }
377                    else {
378                            return getNewName(oldName, sb.toString());
379                    }
380            }
381    
382            @Override
383            public String getOriginalTitle(String title) {
384                    return getOriginalTitle(title, "title", TRASH_PREFIX);
385            }
386    
387            @Override
388            public String getOriginalTitle(String title, String paramName) {
389                    return getOriginalTitle(title, paramName, TRASH_PREFIX);
390            }
391    
392            @Override
393            public String getTrashTime(String title, String separator) {
394                    int index = title.lastIndexOf(separator);
395    
396                    if (index < 0) {
397                            return StringPool.BLANK;
398                    }
399    
400                    return title.substring(index + 1, title.length());
401            }
402    
403            @Override
404            public String getTrashTitle(long trashEntryId) {
405                    return getTrashTitle(trashEntryId, TRASH_PREFIX);
406            }
407    
408            @Override
409            public PortletURL getViewContentURL(
410                            HttpServletRequest request, long trashEntryId)
411                    throws PortalException {
412    
413                    TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
414                            trashEntryId);
415    
416                    return getViewContentURL(
417                            request, trashEntry.getClassName(), trashEntry.getClassPK());
418            }
419    
420            @Override
421            public PortletURL getViewContentURL(
422                            HttpServletRequest request, String className, long classPK)
423                    throws PortalException {
424    
425                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
426                            WebKeys.THEME_DISPLAY);
427    
428                    String portletId = PortletProviderUtil.getPortletId(
429                            TrashEntry.class.getName(), PortletProvider.Action.VIEW);
430    
431                    if (!themeDisplay.isSignedIn() ||
432                            !isTrashEnabled(themeDisplay.getScopeGroupId()) ||
433                            !PortletPermissionUtil.hasControlPanelAccessPermission(
434                                    themeDisplay.getPermissionChecker(),
435                                    themeDisplay.getScopeGroupId(), portletId)) {
436    
437                            return null;
438                    }
439    
440                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
441                            className);
442    
443                    if (trashHandler.isInTrashContainer(classPK)) {
444                            TrashEntry trashEntry = trashHandler.getTrashEntry(classPK);
445    
446                            className = trashEntry.getClassName();
447                            classPK = trashEntry.getClassPK();
448    
449                            trashHandler = TrashHandlerRegistryUtil.getTrashHandler(className);
450                    }
451    
452                    TrashRenderer trashRenderer = trashHandler.getTrashRenderer(classPK);
453    
454                    if (trashRenderer == null) {
455                            return null;
456                    }
457    
458                    Layout layout = themeDisplay.getLayout();
459    
460                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
461                            request, portletId, layout.getLayoutId(),
462                            PortletRequest.RENDER_PHASE);
463    
464                    portletURL.setParameter("mvcPath", "/view_content.jsp");
465                    portletURL.setParameter("redirect", themeDisplay.getURLCurrent());
466    
467                    TrashEntry trashEntry = TrashEntryLocalServiceUtil.getEntry(
468                            className, classPK);
469    
470                    if (trashEntry.getRootEntry() != null) {
471                            portletURL.setParameter("className", className);
472                            portletURL.setParameter("classPK", String.valueOf(classPK));
473                    }
474                    else {
475                            portletURL.setParameter(
476                                    "trashEntryId", String.valueOf(trashEntry.getEntryId()));
477                    }
478    
479                    portletURL.setParameter("showAssetMetadata", Boolean.TRUE.toString());
480    
481                    return portletURL;
482            }
483    
484            @Override
485            public PortletURL getViewURL(HttpServletRequest request)
486                    throws PortalException {
487    
488                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
489                            WebKeys.THEME_DISPLAY);
490    
491                    String portletId = PortletProviderUtil.getPortletId(
492                            TrashEntry.class.getName(), PortletProvider.Action.VIEW);
493    
494                    if (!themeDisplay.isSignedIn() ||
495                            !isTrashEnabled(themeDisplay.getScopeGroupId()) ||
496                            !PortletPermissionUtil.hasControlPanelAccessPermission(
497                                    themeDisplay.getPermissionChecker(),
498                                    themeDisplay.getScopeGroupId(), portletId)) {
499    
500                            return null;
501                    }
502    
503                    Layout layout = themeDisplay.getLayout();
504    
505                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
506                            request, portletId, layout.getLayoutId(),
507                            PortletRequest.RENDER_PHASE);
508    
509                    portletURL.setParameter("redirect", themeDisplay.getURLCurrent());
510    
511                    return portletURL;
512            }
513    
514            @Override
515            public boolean isInTrash(String className, long classPK)
516                    throws PortalException {
517    
518                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
519                            className);
520    
521                    if (trashHandler == null) {
522                            return false;
523                    }
524    
525                    return trashHandler.isInTrash(classPK);
526            }
527    
528            @Override
529            public boolean isTrashEnabled(Group group) {
530                    boolean companyTrashEnabled = PrefsPropsUtil.getBoolean(
531                            group.getCompanyId(), PropsKeys.TRASH_ENABLED);
532    
533                    if (!companyTrashEnabled) {
534                            return false;
535                    }
536    
537                    UnicodeProperties typeSettingsProperties =
538                            group.getParentLiveGroupTypeSettingsProperties();
539    
540                    return GetterUtil.getBoolean(
541                            typeSettingsProperties.getProperty("trashEnabled"), true);
542            }
543    
544            @Override
545            public boolean isTrashEnabled(long groupId) throws PortalException {
546                    return isTrashEnabled(GroupLocalServiceUtil.getGroup(groupId));
547            }
548    
549            @Override
550            public boolean isValidTrashTitle(String title) {
551                    return isValidTrashTitle(title, TRASH_PREFIX);
552            }
553    
554            protected void addBreadcrumbEntries(
555                            HttpServletRequest request,
556                            LiferayPortletResponse liferayPortletResponse, String className,
557                            long classPK, String paramName, PortletURL containerModelURL,
558                            boolean checkInTrashContainers)
559                    throws PortalException, PortletException {
560    
561                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
562                            WebKeys.THEME_DISPLAY);
563    
564                    PortletURL portletURL = PortletURLUtil.clone(
565                            containerModelURL, liferayPortletResponse);
566    
567                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
568                            className);
569    
570                    List<ContainerModel> containerModels =
571                            trashHandler.getParentContainerModels(classPK);
572    
573                    Collections.reverse(containerModels);
574    
575                    for (ContainerModel containerModel : containerModels) {
576                            TrashHandler containerModelTrashHandler =
577                                    TrashHandlerRegistryUtil.getTrashHandler(
578                                            containerModel.getModelClassName());
579    
580                            if (checkInTrashContainers &&
581                                    !containerModelTrashHandler.isInTrash(
582                                            containerModel.getContainerModelId())) {
583    
584                                    continue;
585                            }
586    
587                            portletURL.setParameter(
588                                    paramName,
589                                    String.valueOf(containerModel.getContainerModelId()));
590    
591                            String name = containerModel.getContainerModelName();
592    
593                            if (containerModelTrashHandler.isInTrash(
594                                            containerModel.getContainerModelId())) {
595    
596                                    name = TrashUtil.getOriginalTitle(name);
597                            }
598    
599                            PortalUtil.addPortletBreadcrumbEntry(
600                                    request, name, portletURL.toString());
601                    }
602    
603                    TrashRenderer trashRenderer = trashHandler.getTrashRenderer(classPK);
604    
605                    PortalUtil.addPortletBreadcrumbEntry(
606                            request, trashRenderer.getTitle(themeDisplay.getLocale()), null);
607            }
608    
609            protected String getOriginalTitle(
610                    String title, String paramName, String prefix) {
611    
612                    if (!isValidTrashTitle(title, prefix)) {
613                            return title;
614                    }
615    
616                    title = title.substring(prefix.length());
617    
618                    long trashEntryId = GetterUtil.getLong(title);
619    
620                    if (trashEntryId <= 0) {
621                            return title;
622                    }
623    
624                    try {
625                            TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
626                                    trashEntryId);
627    
628                            if (trashEntry == null) {
629                                    TrashVersion trashVersion =
630                                            TrashVersionLocalServiceUtil.getTrashVersion(trashEntryId);
631    
632                                    title = trashVersion.getTypeSettingsProperty(paramName);
633                            }
634                            else {
635                                    title = trashEntry.getTypeSettingsProperty(paramName);
636                            }
637                    }
638                    catch (Exception e) {
639                            if (_log.isDebugEnabled()) {
640                                    _log.debug(
641                                            "No trash entry or trash version exists with ID " +
642                                                    trashEntryId);
643                            }
644                    }
645    
646                    return title;
647            }
648    
649            protected String getTrashTitle(long trashEntryId, String prefix) {
650                    return prefix.concat(String.valueOf(trashEntryId));
651            }
652    
653            protected boolean isValidTrashTitle(String title, String prefix) {
654                    if (title.startsWith(prefix)) {
655                            return true;
656                    }
657    
658                    return false;
659            }
660    
661            protected final String TRASH_PREFIX = StringPool.SLASH;
662    
663            private static final Log _log = LogFactoryUtil.getLog(TrashImpl.class);
664    
665    }