@Override
  public Folder addAttachmentsFolder() throws PortalException {
    if (_attachmentsFolderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {

      return PortletFileRepositoryUtil.getPortletFolder(_attachmentsFolderId);
    }

    ServiceContext serviceContext = new ServiceContext();

    serviceContext.setAddGroupPermissions(true);
    serviceContext.setAddGuestPermissions(true);

    Repository repository =
        PortletFileRepositoryUtil.addPortletRepository(
            getGroupId(), PortletKeys.BACKGROUND_TASK, serviceContext);

    Folder folder =
        PortletFileRepositoryUtil.addPortletFolder(
            getUserId(),
            repository.getRepositoryId(),
            DLFolderConstants.DEFAULT_PARENT_FOLDER_ID,
            String.valueOf(getBackgroundTaskId()),
            serviceContext);

    _attachmentsFolderId = folder.getFolderId();

    return folder;
  }
  protected void deleteImages(ActionRequest actionRequest) throws Exception {
    ThemeDisplay themeDisplay = (ThemeDisplay) actionRequest.getAttribute(WebKeys.THEME_DISPLAY);

    long[] deleteFileEntryIds = null;

    long fileEntryId = ParamUtil.getLong(actionRequest, "fileEntryId");

    if (fileEntryId > 0) {
      deleteFileEntryIds = new long[] {fileEntryId};
    } else {
      deleteFileEntryIds =
          StringUtil.split(ParamUtil.getString(actionRequest, "deleteFileEntryIds"), 0L);
    }

    Folder folder =
        _blogsEntryLocalService.addAttachmentsFolder(
            themeDisplay.getUserId(), themeDisplay.getScopeGroupId());

    for (long deleteFileEntryId : deleteFileEntryIds) {
      FileEntry fileEntry = PortletFileRepositoryUtil.getPortletFileEntry(deleteFileEntryId);

      if (fileEntry.getFolderId() != folder.getFolderId()) {
        continue;
      }

      if ((fileEntry.getUserId() == themeDisplay.getUserId())
          || BlogsPermission.contains(
              themeDisplay.getPermissionChecker(),
              themeDisplay.getScopeGroupId(),
              ActionKeys.UPDATE)) {

        PortletFileRepositoryUtil.deletePortletFileEntry(deleteFileEntryId);
      }
    }
  }
  @Override
  public long getAttachmentsFolderId() {
    if (_attachmentsFolderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {

      return _attachmentsFolderId;
    }

    ServiceContext serviceContext = new ServiceContext();

    serviceContext.setAddGroupPermissions(true);
    serviceContext.setAddGuestPermissions(true);

    Repository repository =
        PortletFileRepositoryUtil.fetchPortletRepository(getGroupId(), PortletKeys.BACKGROUND_TASK);

    if (repository == null) {
      return DLFolderConstants.DEFAULT_PARENT_FOLDER_ID;
    }

    try {
      Folder folder =
          PortletFileRepositoryUtil.getPortletFolder(
              repository.getRepositoryId(),
              DLFolderConstants.DEFAULT_PARENT_FOLDER_ID,
              String.valueOf(getBackgroundTaskId()));

      _attachmentsFolderId = folder.getFolderId();
    } catch (Exception e) {
      if (_log.isDebugEnabled()) {
        _log.debug("No portlet repository for background task " + getBackgroundTaskId(), e);
      }
    }

    return _attachmentsFolderId;
  }
  protected void moveAttachmentsFolders(
      MBMessage message,
      long oldAttachmentsFolderId,
      MBThread oldThread,
      MBThread newThread,
      ServiceContext serviceContext)
      throws PortalException {

    if (oldAttachmentsFolderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {

      Folder newThreadFolder = newThread.addAttachmentsFolder();

      PortletFileRepositoryUtil.movePortletFolder(
          message.getGroupId(),
          message.getUserId(),
          oldAttachmentsFolderId,
          newThreadFolder.getFolderId(),
          serviceContext);
    }

    List<MBMessage> childMessages =
        mbMessagePersistence.findByT_P(oldThread.getThreadId(), message.getMessageId());

    for (MBMessage childMessage : childMessages) {
      moveAttachmentsFolders(
          childMessage,
          childMessage.getAttachmentsFolderId(),
          oldThread,
          newThread,
          serviceContext);
    }
  }
  @Override
  protected FileEntry addFileEntry(
      long userId,
      long groupId,
      long folderId,
      String fileName,
      String contentType,
      InputStream inputStream,
      long size,
      ServiceContext serviceContext)
      throws PortalException {

    Folder folder = BlogsEntryLocalServiceUtil.addAttachmentsFolder(userId, groupId);

    return PortletFileRepositoryUtil.addPortletFileEntry(
        groupId,
        userId,
        BlogsEntry.class.getName(),
        0,
        BlogsConstants.SERVICE_NAME,
        folder.getFolderId(),
        inputStream,
        fileName,
        contentType,
        true);
  }
  @Override
  public int getAttachmentsFileEntriesCount() throws PortalException {
    int attachmentsFileEntriesCount = 0;

    long attachmentsFolderId = getAttachmentsFolderId();

    if (attachmentsFolderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
      attachmentsFileEntriesCount =
          PortletFileRepositoryUtil.getPortletFileEntriesCount(
              getGroupId(), attachmentsFolderId, WorkflowConstants.STATUS_APPROVED);
    }

    return attachmentsFileEntriesCount;
  }
  @Override
  public void deleteThreads(long groupId, long categoryId, boolean includeTrashedEntries)
      throws PortalException {

    List<MBThread> threads = mbThreadPersistence.findByG_C(groupId, categoryId);

    for (MBThread thread : threads) {
      if (includeTrashedEntries || !thread.isInTrashExplicitly()) {
        mbThreadLocalService.deleteThread(thread);
      }
    }

    if (mbThreadPersistence.countByGroupId(groupId) == 0) {
      PortletFileRepositoryUtil.deletePortletRepository(groupId, MBConstants.SERVICE_NAME);
    }
  }
  @Override
  protected FileEntry fetchFileEntry(long userId, long groupId, long folderId, String fileName)
      throws PortalException {

    Folder folder = BlogsEntryLocalServiceUtil.addAttachmentsFolder(userId, groupId);

    try {
      return PortletFileRepositoryUtil.getPortletFileEntry(groupId, folder.getFolderId(), fileName);
    } catch (PortalException pe) {
      if (_log.isDebugEnabled()) {
        _log.debug(pe, pe);
      }

      return null;
    }
  }
  @Override
  public List<FileEntry> getAttachmentsFileEntries(int start, int end) throws PortalException {

    List<FileEntry> fileEntries = new ArrayList<>();

    long attachmentsFolderId = getAttachmentsFolderId();

    if (attachmentsFolderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
      fileEntries =
          PortletFileRepositoryUtil.getPortletFileEntries(
              getGroupId(),
              attachmentsFolderId,
              WorkflowConstants.STATUS_APPROVED,
              start,
              end,
              null);
    }

    return fileEntries;
  }
  @Override
  public void restoreDependentsFromTrash(long groupId, long threadId) throws PortalException {

    Set<Long> userIds = new HashSet<>();

    MBThread thread = mbThreadLocalService.getThread(threadId);

    List<MBMessage> messages =
        mbMessageLocalService.getThreadMessages(threadId, WorkflowConstants.STATUS_ANY);

    for (MBMessage message : messages) {

      // Message

      if (message.isDiscussion()) {
        continue;
      }

      TrashVersion trashVersion =
          trashVersionLocalService.fetchVersion(MBMessage.class.getName(), message.getMessageId());

      int oldStatus = WorkflowConstants.STATUS_APPROVED;

      if (trashVersion != null) {
        oldStatus = trashVersion.getStatus();
      }

      message.setStatus(oldStatus);

      mbMessagePersistence.update(message);

      userIds.add(message.getUserId());

      // Trash

      if (trashVersion != null) {
        trashVersionLocalService.deleteTrashVersion(trashVersion);
      }

      // Asset

      if (oldStatus == WorkflowConstants.STATUS_APPROVED) {
        assetEntryLocalService.updateVisible(
            MBMessage.class.getName(), message.getMessageId(), true);
      }

      // Attachments

      for (FileEntry fileEntry : message.getAttachmentsFileEntries()) {
        PortletFileRepositoryUtil.restorePortletFileEntryFromTrash(
            thread.getStatusByUserId(), fileEntry.getFileEntryId());
      }

      // Indexer

      Indexer<MBMessage> indexer = IndexerRegistryUtil.nullSafeGetIndexer(MBMessage.class);

      indexer.reindex(message);
    }

    // Statistics

    for (long userId : userIds) {
      mbStatsUserLocalService.updateStatsUser(groupId, userId);
    }
  }
  @Override
  public void moveDependentsToTrash(long groupId, long threadId, long trashEntryId)
      throws PortalException {

    Set<Long> userIds = new HashSet<>();

    MBThread thread = mbThreadLocalService.getThread(threadId);

    List<MBMessage> messages =
        mbMessageLocalService.getThreadMessages(threadId, WorkflowConstants.STATUS_ANY);

    for (MBMessage message : messages) {

      // Message

      if (message.isDiscussion()) {
        continue;
      }

      int oldStatus = message.getStatus();

      message.setStatus(WorkflowConstants.STATUS_IN_TRASH);

      mbMessagePersistence.update(message);

      userIds.add(message.getUserId());

      // Trash

      int status = oldStatus;

      if (oldStatus == WorkflowConstants.STATUS_PENDING) {
        status = WorkflowConstants.STATUS_DRAFT;
      }

      if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
        trashVersionLocalService.addTrashVersion(
            trashEntryId, MBMessage.class.getName(), message.getMessageId(), status, null);
      }

      // Asset

      if (oldStatus == WorkflowConstants.STATUS_APPROVED) {
        assetEntryLocalService.updateVisible(
            MBMessage.class.getName(), message.getMessageId(), false);
      }

      // Attachments

      for (FileEntry fileEntry : message.getAttachmentsFileEntries()) {
        PortletFileRepositoryUtil.movePortletFileEntryToTrash(
            thread.getStatusByUserId(), fileEntry.getFileEntryId());
      }

      // Indexer

      Indexer<MBMessage> indexer = IndexerRegistryUtil.nullSafeGetIndexer(MBMessage.class);

      indexer.reindex(message);

      // Workflow

      if (oldStatus == WorkflowConstants.STATUS_PENDING) {
        workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
            message.getCompanyId(), message.getGroupId(),
            MBMessage.class.getName(), message.getMessageId());
      }
    }

    // Statistics

    for (long userId : userIds) {
      mbStatsUserLocalService.updateStatsUser(groupId, userId);
    }
  }
  @Override
  @SystemEvent(action = SystemEventConstants.ACTION_SKIP, type = SystemEventConstants.TYPE_DELETE)
  public void deleteThread(MBThread thread) throws PortalException {
    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(thread.getRootMessageId());

    // Indexer

    Indexer<MBMessage> messageIndexer = IndexerRegistryUtil.nullSafeGetIndexer(MBMessage.class);

    // Attachments

    long folderId = thread.getAttachmentsFolderId();

    if (folderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
      PortletFileRepositoryUtil.deletePortletFolder(folderId);
    }

    // Subscriptions

    subscriptionLocalService.deleteSubscriptions(
        thread.getCompanyId(), MBThread.class.getName(), thread.getThreadId());

    // Thread flags

    mbThreadFlagLocalService.deleteThreadFlagsByThreadId(thread.getThreadId());

    // Messages

    List<MBMessage> messages = mbMessagePersistence.findByThreadId(thread.getThreadId());

    for (MBMessage message : messages) {

      // Ratings

      ratingsStatsLocalService.deleteStats(message.getWorkflowClassName(), message.getMessageId());

      // Asset

      assetEntryLocalService.deleteEntry(message.getWorkflowClassName(), message.getMessageId());

      // Resources

      if (!message.isDiscussion()) {
        resourceLocalService.deleteResource(
            message.getCompanyId(),
            message.getWorkflowClassName(),
            ResourceConstants.SCOPE_INDIVIDUAL,
            message.getMessageId());
      }

      // Message

      mbMessagePersistence.remove(message);

      // Indexer

      messageIndexer.delete(message);

      // Statistics

      if (!message.isDiscussion()) {
        mbStatsUserLocalService.updateStatsUser(message.getGroupId(), message.getUserId());
      }

      // Workflow

      workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
          message.getCompanyId(), message.getGroupId(),
          message.getWorkflowClassName(), message.getMessageId());
    }

    // Category

    if ((rootMessage.getCategoryId() != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID)
        && (rootMessage.getCategoryId() != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {

      try {
        MBCategory category = mbCategoryPersistence.findByPrimaryKey(thread.getCategoryId());

        MBUtil.updateCategoryStatistics(category.getCategoryId());
      } catch (NoSuchCategoryException nsce) {
        if (!thread.isInTrash()) {
          throw nsce;
        }
      }
    }

    // Thread Asset

    AssetEntry assetEntry =
        assetEntryLocalService.fetchEntry(MBThread.class.getName(), thread.getThreadId());

    if (assetEntry != null) {
      assetEntry.setTitle(rootMessage.getSubject());

      assetEntryLocalService.updateAssetEntry(assetEntry);
    }

    assetEntryLocalService.deleteEntry(MBThread.class.getName(), thread.getThreadId());

    // Trash

    if (thread.isInTrashExplicitly()) {
      trashEntryLocalService.deleteEntry(MBThread.class.getName(), thread.getThreadId());
    } else {
      trashVersionLocalService.deleteTrashVersion(MBThread.class.getName(), thread.getThreadId());
    }

    // Indexer

    Indexer<MBThread> threadIndexer = IndexerRegistryUtil.nullSafeGetIndexer(MBThread.class);

    threadIndexer.delete(thread);

    // Thread

    mbThreadPersistence.remove(thread);
  }