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 void addAttachment(ClassedModel classedModel) throws Exception {
    MBMessage message = (MBMessage) classedModel;

    List<FileEntry> fileEntries = message.getAttachmentsFileEntries();

    List<String> existingFiles = new ArrayList<>();

    for (FileEntry fileEntry : fileEntries) {
      existingFiles.add(fileEntry.getTitle());
    }

    ServiceContext serviceContext = ServiceContextTestUtil.getServiceContext(message.getGroupId());

    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
        MBTestUtil.getInputStreamOVPs("OSX_Test.docx", getClass(), getSearchKeywords());

    MBMessageLocalServiceUtil.updateMessage(
        TestPropsValues.getUserId(),
        message.getMessageId(),
        getSearchKeywords(),
        getSearchKeywords(),
        inputStreamOVPs,
        existingFiles,
        0,
        false,
        serviceContext);
  }
  @Override
  public void restoreMessageAttachmentFromTrash(long messageId, String fileName)
      throws PortalException, SystemException {

    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

    MBCategoryPermission.check(
        getPermissionChecker(), message.getGroupId(), message.getCategoryId(), ActionKeys.ADD_FILE);

    mbMessageLocalService.restoreMessageAttachmentFromTrash(getUserId(), messageId, fileName);
  }
  @Override
  protected void updateBaseModel(long userId, long baseModelId) throws Exception {

    MBMessage message = MBMessageLocalServiceUtil.getMessage(baseModelId);

    ServiceContext serviceContext =
        ServiceContextTestUtil.getServiceContext(message.getGroupId(), userId);

    MBTestUtil.populateNotificationsServiceContext(serviceContext, Constants.UPDATE);

    MBMessageLocalServiceUtil.updateMessage(
        userId, message.getMessageId(), RandomTestUtil.randomString(), serviceContext);
  }
  protected long importMBMessage(
      MBMessage mbMessage, long threadId, long calendarBookingId, Map<Long, Long> mbMessageIds)
      throws PortalException, SystemException {

    Long messageId = mbMessageIds.get(mbMessage.getMessageId());

    if (messageId != null) {
      return messageId;
    }

    messageId = counterLocalService.increment();

    addMBMessage(
        PortalUUIDUtil.generate(),
        messageId,
        mbMessage.getGroupId(),
        mbMessage.getCompanyId(),
        mbMessage.getUserId(),
        mbMessage.getUserName(),
        mbMessage.getCreateDate(),
        mbMessage.getModifiedDate(),
        classNameLocalService.getClassNameId(CalendarBooking.class.getName()),
        calendarBookingId,
        mbMessage.getCategoryId(),
        threadId,
        mbMessage.getRootMessageId(),
        mbMessage.getParentMessageId(),
        mbMessage.getSubject(),
        mbMessage.getBody(),
        mbMessage.getFormat(),
        mbMessage.isAnonymous(),
        mbMessage.getPriority(),
        mbMessage.getAllowPingbacks(),
        mbMessage.isAnswer(),
        mbMessage.getStatus(),
        mbMessage.getStatusByUserId(),
        mbMessage.getStatusByUserName(),
        mbMessage.getStatusDate(),
        mbMessageIds);

    long mbDiscussionClassNameId =
        classNameLocalService.getClassNameId(MBDiscussion.class.getName());

    importRatings(
        mbDiscussionClassNameId, mbMessage.getMessageId(), mbDiscussionClassNameId, messageId);

    mbMessageIds.put(mbMessage.getMessageId(), messageId);

    return messageId;
  }
  protected void updateDependentStatus(long groupId, long threadId, int status)
      throws PortalException, SystemException {

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

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

    for (MBMessage message : messages) {
      if (message.isDiscussion()) {
        continue;
      }

      userIds.add(message.getUserId());

      if (status == WorkflowConstants.STATUS_IN_TRASH) {

        // Asset

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

        // Social

        socialActivityCounterLocalService.disableActivityCounters(
            MBMessage.class.getName(), message.getMessageId());

        // Index

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

        indexer.reindex(message);

        // Workflow

        if (message.getStatus() == WorkflowConstants.STATUS_PENDING) {
          message.setStatus(WorkflowConstants.STATUS_DRAFT);

          mbMessagePersistence.update(message);

          workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
              message.getCompanyId(), message.getGroupId(),
              MBMessage.class.getName(), message.getMessageId());
        }
      } else {

        // Asset

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

        // Social

        socialActivityCounterLocalService.enableActivityCounters(
            MBMessage.class.getName(), message.getMessageId());

        // Index

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

        indexer.reindex(message);
      }
    }

    // Statistics

    for (long userId : userIds) {
      mbStatsUserLocalService.updateStatsUser(groupId, userId);
    }
  }
  @Override
  public MBThread addThread(long categoryId, MBMessage message, ServiceContext serviceContext)
      throws PortalException, SystemException {

    // Thread

    Date now = new Date();

    long threadId = message.getThreadId();

    if (!message.isRoot() || (threadId <= 0)) {
      threadId = counterLocalService.increment();
    }

    MBThread thread = mbThreadPersistence.create(threadId);

    thread.setUuid(serviceContext.getUuid());
    thread.setGroupId(message.getGroupId());
    thread.setCompanyId(message.getCompanyId());
    thread.setUserId(message.getUserId());
    thread.setUserName(message.getUserName());
    thread.setCreateDate(serviceContext.getCreateDate(now));
    thread.setModifiedDate(serviceContext.getModifiedDate(now));
    thread.setCategoryId(categoryId);
    thread.setRootMessageId(message.getMessageId());
    thread.setRootMessageUserId(message.getUserId());

    if (message.isAnonymous()) {
      thread.setLastPostByUserId(0);
    } else {
      thread.setLastPostByUserId(message.getUserId());
    }

    thread.setLastPostDate(message.getCreateDate());

    if (message.getPriority() != MBThreadConstants.PRIORITY_NOT_GIVEN) {
      thread.setPriority(message.getPriority());
    }

    thread.setStatus(message.getStatus());
    thread.setStatusByUserId(message.getStatusByUserId());
    thread.setStatusByUserName(message.getStatusByUserName());
    thread.setStatusDate(message.getStatusDate());

    mbThreadPersistence.update(thread);

    // Asset

    if (categoryId >= 0) {
      assetEntryLocalService.updateEntry(
          message.getUserId(),
          message.getGroupId(),
          thread.getStatusDate(),
          thread.getLastPostDate(),
          MBThread.class.getName(),
          thread.getThreadId(),
          thread.getUuid(),
          0,
          new long[0],
          new String[0],
          false,
          null,
          null,
          null,
          null,
          String.valueOf(thread.getRootMessageId()),
          null,
          null,
          null,
          null,
          0,
          0,
          null,
          false);
    }

    return thread;
  }
  @Override
  @SystemEvent(
      action = SystemEventConstants.ACTION_SKIP,
      send = false,
      type = SystemEventConstants.TYPE_DELETE)
  public void deleteThread(MBThread thread) throws PortalException, SystemException {

    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(thread.getRootMessageId());

    // Indexer

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

    indexer.delete(thread);

    // Attachments

    long folderId = thread.getAttachmentsFolderId();

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

    // Subscriptions

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

    // Thread flags

    mbThreadFlagPersistence.removeByThreadId(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);

      // 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.getCompanyId(), 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

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

    // Thread

    mbThreadPersistence.remove(thread);
  }
  @Override
  public MBMessage updateMessage(
      long messageId,
      String subject,
      String body,
      List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
      List<String> existingFiles,
      double priority,
      boolean allowPingbacks,
      ServiceContext serviceContext)
      throws PortalException, SystemException {

    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);

    boolean preview = ParamUtil.getBoolean(serviceContext, "preview");

    if (preview
        && MBMessagePermission.contains(getPermissionChecker(), message, ActionKeys.UPDATE)) {

      checkReplyToPermission(
          message.getGroupId(), message.getCategoryId(), message.getParentMessageId());
    } else {
      MBMessagePermission.check(getPermissionChecker(), messageId, ActionKeys.UPDATE);
    }

    if (lockLocalService.isLocked(MBThread.class.getName(), message.getThreadId())) {

      throw new LockedThreadException();
    }

    if (!MBCategoryPermission.contains(
        getPermissionChecker(),
        message.getGroupId(),
        message.getCategoryId(),
        ActionKeys.ADD_FILE)) {

      inputStreamOVPs = Collections.emptyList();
    }

    if (!MBCategoryPermission.contains(
        getPermissionChecker(),
        message.getGroupId(),
        message.getCategoryId(),
        ActionKeys.UPDATE_THREAD_PRIORITY)) {

      MBThread thread = mbThreadLocalService.getThread(message.getThreadId());

      priority = thread.getPriority();
    }

    return mbMessageLocalService.updateMessage(
        getGuestOrUserId(),
        messageId,
        subject,
        body,
        inputStreamOVPs,
        existingFiles,
        priority,
        allowPingbacks,
        serviceContext);
  }
  @Override
  public MBMessage addMessage(
      long parentMessageId,
      String subject,
      String body,
      String format,
      List<ObjectValuePair<String, InputStream>> inputStreamOVPs,
      boolean anonymous,
      double priority,
      boolean allowPingbacks,
      ServiceContext serviceContext)
      throws PortalException, SystemException {

    MBMessage parentMessage = mbMessagePersistence.findByPrimaryKey(parentMessageId);

    checkReplyToPermission(
        parentMessage.getGroupId(), parentMessage.getCategoryId(), parentMessageId);

    boolean preview = ParamUtil.getBoolean(serviceContext, "preview");

    int workFlowAction = serviceContext.getWorkflowAction();

    if ((workFlowAction == WorkflowConstants.STATUS_DRAFT)
        && !preview
        && !serviceContext.isSignedIn()) {

      MBMessagePermission.check(getPermissionChecker(), parentMessageId, ActionKeys.UPDATE);
    }

    if (lockLocalService.isLocked(MBThread.class.getName(), parentMessage.getThreadId())) {

      throw new LockedThreadException();
    }

    if (!MBCategoryPermission.contains(
        getPermissionChecker(),
        parentMessage.getGroupId(),
        parentMessage.getCategoryId(),
        ActionKeys.ADD_FILE)) {

      inputStreamOVPs = Collections.emptyList();
    }

    if (!MBCategoryPermission.contains(
        getPermissionChecker(),
        parentMessage.getGroupId(),
        parentMessage.getCategoryId(),
        ActionKeys.UPDATE_THREAD_PRIORITY)) {

      priority = MBThreadConstants.PRIORITY_NOT_GIVEN;
    }

    return mbMessageLocalService.addMessage(
        getGuestOrUserId(),
        null,
        parentMessage.getGroupId(),
        parentMessage.getCategoryId(),
        parentMessage.getThreadId(),
        parentMessageId,
        subject,
        body,
        format,
        inputStreamOVPs,
        anonymous,
        priority,
        allowPingbacks,
        serviceContext);
  }
  @Test
  public void testUpdateExisting() throws Exception {
    long pk = RandomTestUtil.nextLong();

    MBMessage newMBMessage = _persistence.create(pk);

    newMBMessage.setUuid(RandomTestUtil.randomString());

    newMBMessage.setGroupId(RandomTestUtil.nextLong());

    newMBMessage.setCompanyId(RandomTestUtil.nextLong());

    newMBMessage.setUserId(RandomTestUtil.nextLong());

    newMBMessage.setUserName(RandomTestUtil.randomString());

    newMBMessage.setCreateDate(RandomTestUtil.nextDate());

    newMBMessage.setModifiedDate(RandomTestUtil.nextDate());

    newMBMessage.setClassNameId(RandomTestUtil.nextLong());

    newMBMessage.setClassPK(RandomTestUtil.nextLong());

    newMBMessage.setCategoryId(RandomTestUtil.nextLong());

    newMBMessage.setThreadId(RandomTestUtil.nextLong());

    newMBMessage.setRootMessageId(RandomTestUtil.nextLong());

    newMBMessage.setParentMessageId(RandomTestUtil.nextLong());

    newMBMessage.setSubject(RandomTestUtil.randomString());

    newMBMessage.setBody(RandomTestUtil.randomString());

    newMBMessage.setFormat(RandomTestUtil.randomString());

    newMBMessage.setAnonymous(RandomTestUtil.randomBoolean());

    newMBMessage.setPriority(RandomTestUtil.nextDouble());

    newMBMessage.setAllowPingbacks(RandomTestUtil.randomBoolean());

    newMBMessage.setAnswer(RandomTestUtil.randomBoolean());

    newMBMessage.setStatus(RandomTestUtil.nextInt());

    newMBMessage.setStatusByUserId(RandomTestUtil.nextLong());

    newMBMessage.setStatusByUserName(RandomTestUtil.randomString());

    newMBMessage.setStatusDate(RandomTestUtil.nextDate());

    _mbMessages.add(_persistence.update(newMBMessage));

    MBMessage existingMBMessage = _persistence.findByPrimaryKey(newMBMessage.getPrimaryKey());

    Assert.assertEquals(existingMBMessage.getUuid(), newMBMessage.getUuid());
    Assert.assertEquals(existingMBMessage.getMessageId(), newMBMessage.getMessageId());
    Assert.assertEquals(existingMBMessage.getGroupId(), newMBMessage.getGroupId());
    Assert.assertEquals(existingMBMessage.getCompanyId(), newMBMessage.getCompanyId());
    Assert.assertEquals(existingMBMessage.getUserId(), newMBMessage.getUserId());
    Assert.assertEquals(existingMBMessage.getUserName(), newMBMessage.getUserName());
    Assert.assertEquals(
        Time.getShortTimestamp(existingMBMessage.getCreateDate()),
        Time.getShortTimestamp(newMBMessage.getCreateDate()));
    Assert.assertEquals(
        Time.getShortTimestamp(existingMBMessage.getModifiedDate()),
        Time.getShortTimestamp(newMBMessage.getModifiedDate()));
    Assert.assertEquals(existingMBMessage.getClassNameId(), newMBMessage.getClassNameId());
    Assert.assertEquals(existingMBMessage.getClassPK(), newMBMessage.getClassPK());
    Assert.assertEquals(existingMBMessage.getCategoryId(), newMBMessage.getCategoryId());
    Assert.assertEquals(existingMBMessage.getThreadId(), newMBMessage.getThreadId());
    Assert.assertEquals(existingMBMessage.getRootMessageId(), newMBMessage.getRootMessageId());
    Assert.assertEquals(existingMBMessage.getParentMessageId(), newMBMessage.getParentMessageId());
    Assert.assertEquals(existingMBMessage.getSubject(), newMBMessage.getSubject());
    Assert.assertEquals(existingMBMessage.getBody(), newMBMessage.getBody());
    Assert.assertEquals(existingMBMessage.getFormat(), newMBMessage.getFormat());
    Assert.assertEquals(existingMBMessage.getAnonymous(), newMBMessage.getAnonymous());
    AssertUtils.assertEquals(existingMBMessage.getPriority(), newMBMessage.getPriority());
    Assert.assertEquals(existingMBMessage.getAllowPingbacks(), newMBMessage.getAllowPingbacks());
    Assert.assertEquals(existingMBMessage.getAnswer(), newMBMessage.getAnswer());
    Assert.assertEquals(existingMBMessage.getStatus(), newMBMessage.getStatus());
    Assert.assertEquals(existingMBMessage.getStatusByUserId(), newMBMessage.getStatusByUserId());
    Assert.assertEquals(
        existingMBMessage.getStatusByUserName(), newMBMessage.getStatusByUserName());
    Assert.assertEquals(
        Time.getShortTimestamp(existingMBMessage.getStatusDate()),
        Time.getShortTimestamp(newMBMessage.getStatusDate()));
  }
  @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);
    }
  }