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.kernel.util.WebKeys;
045    import com.liferay.portal.model.ContainerModel;
046    import com.liferay.portal.model.Group;
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.portlet.PortletURLUtil;
054    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
055    import com.liferay.portlet.trash.model.TrashEntry;
056    import com.liferay.portlet.trash.model.TrashVersion;
057    import com.liferay.portlet.trash.model.impl.TrashEntryImpl;
058    import com.liferay.portlet.trash.service.TrashEntryLocalServiceUtil;
059    import com.liferay.portlet.trash.service.TrashVersionLocalServiceUtil;
060    import com.liferay.portlet.trash.util.comparator.EntryCreateDateComparator;
061    import com.liferay.portlet.trash.util.comparator.EntryTypeComparator;
062    import com.liferay.portlet.trash.util.comparator.EntryUserNameComparator;
063    
064    import java.text.Format;
065    
066    import java.util.ArrayList;
067    import java.util.Collections;
068    import java.util.Date;
069    import java.util.HashMap;
070    import java.util.List;
071    import java.util.Map;
072    
073    import javax.portlet.ActionRequest;
074    import javax.portlet.PortletException;
075    import javax.portlet.PortletRequest;
076    import javax.portlet.PortletURL;
077    
078    import javax.servlet.http.HttpServletRequest;
079    
080    /**
081     * @author Sergio Gonz??lez
082     * @author Julio Camarero
083     */
084    @DoPrivileged
085    public class TrashImpl implements Trash {
086    
087            @Override
088            public void addBaseModelBreadcrumbEntries(
089                            HttpServletRequest request,
090                            LiferayPortletResponse liferayPortletResponse, String className,
091                            long classPK, PortletURL containerModelURL)
092                    throws PortalException, PortletException {
093    
094                    addBreadcrumbEntries(
095                            request, liferayPortletResponse, className, classPK, "classPK",
096                            containerModelURL, true);
097            }
098    
099            @Override
100            public void addContainerModelBreadcrumbEntries(
101                            HttpServletRequest request,
102                            LiferayPortletResponse liferayPortletResponse, String className,
103                            long classPK, PortletURL containerModelURL)
104                    throws PortalException, PortletException {
105    
106                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
107                            WebKeys.THEME_DISPLAY);
108    
109                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
110                            className);
111    
112                    String rootContainerModelTitle = LanguageUtil.get(
113                            themeDisplay.getLocale(), trashHandler.getRootContainerModelName());
114    
115                    if (classPK == 0) {
116                            PortalUtil.addPortletBreadcrumbEntry(
117                                    request, rootContainerModelTitle, null);
118    
119                            return;
120                    }
121    
122                    containerModelURL.setParameter("containerModelId", "0");
123    
124                    PortalUtil.addPortletBreadcrumbEntry(
125                            request, rootContainerModelTitle, containerModelURL.toString());
126    
127                    addBreadcrumbEntries(
128                            request, liferayPortletResponse, className, classPK,
129                            "containerModelId", containerModelURL, false);
130            }
131    
132            @Override
133            public void addTrashSessionMessages(
134                    ActionRequest actionRequest, List<TrashedModel> trashedModels) {
135    
136                    addTrashSessionMessages(
137                            actionRequest, trashedModels, Constants.MOVE_TO_TRASH);
138            }
139    
140            @Override
141            public void addTrashSessionMessages(
142                    ActionRequest actionRequest, List<TrashedModel> trashedModels,
143                    String cmd) {
144    
145                    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(
146                            WebKeys.THEME_DISPLAY);
147    
148                    List<String> classNames = new ArrayList<>();
149                    List<Long> restoreTrashEntryIds = new ArrayList<>();
150                    List<String> titles = new ArrayList<>();
151    
152                    for (int i = 0; i < trashedModels.size(); i++) {
153                            try {
154                                    TrashedModel trashedModel = trashedModels.get(i);
155    
156                                    TrashEntry trashEntry = trashedModel.getTrashEntry();
157    
158                                    TrashHandler trashHandler = trashedModel.getTrashHandler();
159    
160                                    TrashRenderer trashRenderer = trashHandler.getTrashRenderer(
161                                            trashedModel.getTrashEntryClassPK());
162    
163                                    classNames.add(trashRenderer.getClassName());
164                                    restoreTrashEntryIds.add(trashEntry.getEntryId());
165                                    titles.add(trashRenderer.getTitle(themeDisplay.getLocale()));
166                            }
167                            catch (Exception e) {
168                            }
169                    }
170    
171                    Map<String, String[]> data = new HashMap<>();
172    
173                    data.put(Constants.CMD, new String[] {cmd});
174    
175                    data.put(
176                            "deleteEntryClassName",
177                            ArrayUtil.toStringArray(classNames.toArray()));
178                    data.put("deleteEntryTitle", ArrayUtil.toStringArray(titles.toArray()));
179                    data.put(
180                            "restoreTrashEntryIds",
181                            ArrayUtil.toStringArray(restoreTrashEntryIds.toArray()));
182    
183                    SessionMessages.add(
184                            actionRequest,
185                            PortalUtil.getPortletId(actionRequest) +
186                                    SessionMessages.KEY_SUFFIX_DELETE_SUCCESS_DATA,
187                            data);
188            }
189    
190            @Override
191            public void addTrashSessionMessages(
192                    ActionRequest actionRequest, TrashedModel trashedModel) {
193    
194                    addTrashSessionMessages(
195                            actionRequest, trashedModel, Constants.MOVE_TO_TRASH);
196            }
197    
198            @Override
199            public void addTrashSessionMessages(
200                    ActionRequest actionRequest, TrashedModel trashedModel, String cmd) {
201    
202                    List<TrashedModel> trashedModels = new ArrayList<>();
203    
204                    trashedModels.add(trashedModel);
205    
206                    addTrashSessionMessages(actionRequest, trashedModels, cmd);
207            }
208    
209            @Override
210            public void deleteEntriesAttachments(
211                    long companyId, long repositoryId, Date date,
212                    String[] attachmentFileNames) {
213    
214                    for (String attachmentFileName : attachmentFileNames) {
215                            String trashTime = TrashUtil.getTrashTime(
216                                    attachmentFileName, TRASH_TIME_SEPARATOR);
217    
218                            long timestamp = GetterUtil.getLong(trashTime);
219    
220                            if (timestamp < date.getTime()) {
221                                    DLStoreUtil.deleteDirectory(
222                                            companyId, repositoryId, attachmentFileName);
223                            }
224                    }
225            }
226    
227            @Override
228            public Group disableTrash(Group group) {
229                    UnicodeProperties typeSettingsProperties =
230                            group.getParentLiveGroupTypeSettingsProperties();
231    
232                    typeSettingsProperties.setProperty("trashEnabled", StringPool.FALSE);
233    
234                    group.setTypeSettingsProperties(typeSettingsProperties);
235    
236                    return GroupLocalServiceUtil.updateGroup(group);
237            }
238    
239            @Override
240            public List<TrashEntry> getEntries(Hits hits) {
241                    List<TrashEntry> entries = new ArrayList<>();
242    
243                    for (Document document : hits.getDocs()) {
244                            String entryClassName = GetterUtil.getString(
245                                    document.get(Field.ENTRY_CLASS_NAME));
246                            long classPK = GetterUtil.getLong(
247                                    document.get(Field.ENTRY_CLASS_PK));
248    
249                            try {
250                                    TrashEntry entry = TrashEntryLocalServiceUtil.fetchEntry(
251                                            entryClassName, classPK);
252    
253                                    if (entry == null) {
254                                            String userName = GetterUtil.getString(
255                                                    document.get(Field.REMOVED_BY_USER_NAME));
256    
257                                            Date removedDate = document.getDate(Field.REMOVED_DATE);
258    
259                                            entry = new TrashEntryImpl();
260    
261                                            entry.setUserName(userName);
262                                            entry.setCreateDate(removedDate);
263    
264                                            TrashHandler trashHandler =
265                                                    TrashHandlerRegistryUtil.getTrashHandler(
266                                                            entryClassName);
267    
268                                            TrashRenderer trashRenderer = trashHandler.getTrashRenderer(
269                                                    classPK);
270    
271                                            entry.setClassName(trashRenderer.getClassName());
272                                            entry.setClassPK(trashRenderer.getClassPK());
273    
274                                            String rootEntryClassName = GetterUtil.getString(
275                                                    document.get(Field.ROOT_ENTRY_CLASS_NAME));
276                                            long rootEntryClassPK = GetterUtil.getLong(
277                                                    document.get(Field.ROOT_ENTRY_CLASS_PK));
278    
279                                            TrashEntry rootTrashEntry =
280                                                    TrashEntryLocalServiceUtil.fetchEntry(
281                                                            rootEntryClassName, rootEntryClassPK);
282    
283                                            if (rootTrashEntry != null) {
284                                                    entry.setRootEntry(rootTrashEntry);
285                                            }
286                                    }
287    
288                                    entries.add(entry);
289                            }
290                            catch (Exception e) {
291                                    if (_log.isWarnEnabled()) {
292                                            _log.warn(
293                                                    "Unable to find trash entry for " + entryClassName +
294                                                            " with primary key " + classPK);
295                                    }
296                            }
297                    }
298    
299                    return entries;
300            }
301    
302            @Override
303            public OrderByComparator<TrashEntry> getEntryOrderByComparator(
304                    String orderByCol, String orderByType) {
305    
306                    boolean orderByAsc = false;
307    
308                    if (orderByType.equals("asc")) {
309                            orderByAsc = true;
310                    }
311    
312                    OrderByComparator<TrashEntry> orderByComparator = null;
313    
314                    if (orderByCol.equals("removed-by")) {
315                            orderByComparator = new EntryUserNameComparator(orderByAsc);
316                    }
317                    else if (orderByCol.equals("removed-date")) {
318                            orderByComparator = new EntryCreateDateComparator(orderByAsc);
319                    }
320                    else if (orderByCol.equals("type")) {
321                            orderByComparator = new EntryTypeComparator(orderByAsc);
322                    }
323    
324                    return orderByComparator;
325            }
326    
327            @Override
328            public int getMaxAge(Group group) {
329                    int trashEntriesMaxAge = PrefsPropsUtil.getInteger(
330                            group.getCompanyId(), PropsKeys.TRASH_ENTRIES_MAX_AGE,
331                            PropsValues.TRASH_ENTRIES_MAX_AGE);
332    
333                    UnicodeProperties typeSettingsProperties =
334                            group.getParentLiveGroupTypeSettingsProperties();
335    
336                    return GetterUtil.getInteger(
337                            typeSettingsProperties.getProperty("trashEntriesMaxAge"),
338                            trashEntriesMaxAge);
339            }
340    
341            @Override
342            public String getNewName(String oldName, String token) {
343                    StringBundler sb = new StringBundler(3);
344    
345                    sb.append(oldName);
346                    sb.append(StringPool.SPACE);
347                    sb.append(token);
348    
349                    return sb.toString();
350            }
351    
352            @Override
353            public String getNewName(
354                            ThemeDisplay themeDisplay, String className, long classPK,
355                            String oldName)
356                    throws PortalException {
357    
358                    TrashRenderer trashRenderer = null;
359    
360                    if (Validator.isNotNull(className) && (classPK > 0)) {
361                            TrashHandler trashHandler =
362                                    TrashHandlerRegistryUtil.getTrashHandler(className);
363    
364                            trashRenderer = trashHandler.getTrashRenderer(classPK);
365                    }
366    
367                    Format dateFormatDateTime = FastDateFormatFactoryUtil.getDateTime(
368                            themeDisplay.getLocale(), themeDisplay.getTimeZone());
369    
370                    StringBundler sb = new StringBundler(3);
371    
372                    sb.append(StringPool.OPEN_PARENTHESIS);
373                    sb.append(
374                            StringUtil.replace(
375                                    dateFormatDateTime.format(new Date()),
376                                    new String[] {StringPool.SLASH, StringPool.COLON},
377                                    new String[] {StringPool.PERIOD, StringPool.PERIOD}));
378                    sb.append(StringPool.CLOSE_PARENTHESIS);
379    
380                    if (trashRenderer != null) {
381                            return trashRenderer.getNewName(oldName, sb.toString());
382                    }
383                    else {
384                            return getNewName(oldName, sb.toString());
385                    }
386            }
387    
388            @Override
389            public String getOriginalTitle(String title) {
390                    return getOriginalTitle(title, "title", TRASH_PREFIX);
391            }
392    
393            @Override
394            public String getOriginalTitle(String title, String paramName) {
395                    return getOriginalTitle(title, paramName, TRASH_PREFIX);
396            }
397    
398            @Override
399            public String getTrashTime(String title, String separator) {
400                    int index = title.lastIndexOf(separator);
401    
402                    if (index < 0) {
403                            return StringPool.BLANK;
404                    }
405    
406                    return title.substring(index + 1, title.length());
407            }
408    
409            @Override
410            public String getTrashTitle(long trashEntryId) {
411                    return getTrashTitle(trashEntryId, TRASH_PREFIX);
412            }
413    
414            @Override
415            public PortletURL getViewContentURL(
416                            HttpServletRequest request, long trashEntryId)
417                    throws PortalException {
418    
419                    TrashEntry trashEntry = TrashEntryLocalServiceUtil.fetchEntry(
420                            trashEntryId);
421    
422                    return getViewContentURL(
423                            request, trashEntry.getClassName(), trashEntry.getClassPK());
424            }
425    
426            @Override
427            public PortletURL getViewContentURL(
428                            HttpServletRequest request, String className, long classPK)
429                    throws PortalException {
430    
431                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
432                            WebKeys.THEME_DISPLAY);
433    
434                    String portletId = PortletProviderUtil.getPortletId(
435                            TrashEntry.class.getName(), PortletProvider.Action.VIEW);
436    
437                    if (!themeDisplay.isSignedIn() ||
438                            !isTrashEnabled(themeDisplay.getScopeGroupId()) ||
439                            !PortletPermissionUtil.hasControlPanelAccessPermission(
440                                    themeDisplay.getPermissionChecker(),
441                                    themeDisplay.getScopeGroupId(), portletId)) {
442    
443                            return null;
444                    }
445    
446                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
447                            className);
448    
449                    if (trashHandler.isInTrashContainer(classPK)) {
450                            TrashEntry trashEntry = trashHandler.getTrashEntry(classPK);
451    
452                            className = trashEntry.getClassName();
453                            classPK = trashEntry.getClassPK();
454    
455                            trashHandler = TrashHandlerRegistryUtil.getTrashHandler(className);
456                    }
457    
458                    TrashRenderer trashRenderer = trashHandler.getTrashRenderer(classPK);
459    
460                    if (trashRenderer == null) {
461                            return null;
462                    }
463    
464                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
465                            request, portletId, PortletRequest.RENDER_PHASE);
466    
467                    portletURL.setParameter("mvcPath", "/view_content.jsp");
468                    portletURL.setParameter("redirect", themeDisplay.getURLCurrent());
469    
470                    TrashEntry trashEntry = TrashEntryLocalServiceUtil.getEntry(
471                            className, classPK);
472    
473                    if (trashEntry.getRootEntry() != null) {
474                            portletURL.setParameter("className", className);
475                            portletURL.setParameter("classPK", String.valueOf(classPK));
476                    }
477                    else {
478                            portletURL.setParameter(
479                                    "trashEntryId", String.valueOf(trashEntry.getEntryId()));
480                    }
481    
482                    portletURL.setParameter("showAssetMetadata", Boolean.TRUE.toString());
483    
484                    return portletURL;
485            }
486    
487            @Override
488            public PortletURL getViewURL(HttpServletRequest request)
489                    throws PortalException {
490    
491                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
492                            WebKeys.THEME_DISPLAY);
493    
494                    String portletId = PortletProviderUtil.getPortletId(
495                            TrashEntry.class.getName(), PortletProvider.Action.VIEW);
496    
497                    if (!themeDisplay.isSignedIn() ||
498                            !isTrashEnabled(themeDisplay.getScopeGroupId()) ||
499                            !PortletPermissionUtil.hasControlPanelAccessPermission(
500                                    themeDisplay.getPermissionChecker(),
501                                    themeDisplay.getScopeGroupId(), portletId)) {
502    
503                            return null;
504                    }
505    
506                    PortletURL portletURL = PortalUtil.getControlPanelPortletURL(
507                            request, portletId, 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    }