# KmeliaService.java

    /*
     * Copyright (C) 2000 - 2026 Silverpeas
     *
     * This program is free software: you can redistribute it and/or modify it under the terms of the
     * GNU Affero General Public License as published by the Free Software Foundation, either version 3
     * of the License, or (at your option) any later version.
     *
     * As a special exception to the terms and conditions of version 3.0 of the GPL, you may
     * redistribute this Program in connection with Free/Libre Open Source Software ("FLOSS")
     * applications as described in Silverpeas's FLOSS exception. You should have received a copy of the
     * text describing the FLOSS exception, and it is also available here:
     * "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
     *
     * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
     * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     * Affero General Public License for more details.
     *
     * You should have received a copy of the GNU Affero General Public License along with this program.
     * If not, see <https://www.gnu.org/licenses/>.
     */
    package org.silverpeas.components.kmelia.service;

    import org.silverpeas.components.kmelia.KmeliaCopyDetail;
    import org.silverpeas.components.kmelia.KmeliaPasteDetail;
    import org.silverpeas.components.kmelia.model.KmeliaPublication;
    import org.silverpeas.components.kmelia.model.TopicDetail;
    import org.silverpeas.components.kmelia.model.ValidatorsList;
    import org.silverpeas.core.ApplicationService;
    import org.silverpeas.core.ResourceReference;
    import org.silverpeas.core.admin.user.model.SilverpeasRole;
    import org.silverpeas.core.contribution.attachment.model.SimpleDocumentPK;
    import org.silverpeas.core.contribution.model.ContributionIdentifier;
    import org.silverpeas.core.contribution.publication.model.CompletePublication;
    import org.silverpeas.core.contribution.publication.model.Location;
    import org.silverpeas.core.contribution.publication.model.PublicationDetail;
    import org.silverpeas.core.contribution.publication.model.PublicationPK;
    import org.silverpeas.core.node.coordinates.model.Coordinate;
    import org.silverpeas.core.node.model.NodeDetail;
    import org.silverpeas.core.node.model.NodePK;
    import org.silverpeas.core.notification.user.UserNotification;
    import org.silverpeas.core.pdc.pdc.model.PdcClassification;
    import org.silverpeas.core.reminder.Reminder;
    import org.silverpeas.core.silverstatistics.access.model.HistoryObjectDetail;
    import org.silverpeas.kernel.annotation.NonNull;
    import org.silverpeas.kernel.util.Pair;
    import org.silverpeas.core.util.ServiceProvider;

    import java.util.Collection;
    import java.util.List;
    import java.util.Optional;

    /**
     * This is the Service interface controller of the MVC. It controls all the activities that happen
     * in a client session. It also provides mechanisms to access other services.
     *
     * @author Nicolas Eysseric
     */
    public interface KmeliaService extends ApplicationService {

      static KmeliaService get() {
        return ServiceProvider.getService(KmeliaService.class);
      }

      @Override
      @SuppressWarnings("unchecked")
      Optional<KmeliaPublication> getContributionById(ContributionIdentifier contributionId);

      TopicDetail goTo(NodePK nodePK, String userId, boolean isTreeStructureUsed, String userProfile,
          boolean mustUserRightsBeChecked);

      List<NodeDetail> getAllowedSubfolders(NodeDetail folder, String userId);

      /**
       * Add a subtopic to the specified topic.
       * @param fatherPK the topic identifier of the father topic.
       * @param subtopic the details about the new subtopic.
       * @return the new added subtopic.
       * @see NodeDetail
       * @see NodePK
       * @since 1.0
       */
      NodeDetail addToTopic(NodePK fatherPK, NodeDetail subtopic);

      /**
       * Add a subtopic to currentTopic and alert users about it.
       * @param subtopic the details about the new subtopic
       * @param alertType Notifies either all users (<code>"All"</code>"), only publishers
       * (<code>"Publisher"</code>) or nobody (<code>"None"</code>) about the topic creation.
       * @return the new added subtopic.
       * @see NodeDetail
       * @see NodePK
       * @since 1.0
       */
      NodeDetail addSubTopic(NodePK fatherPK, NodeDetail subtopic, String alertType);

      /**
       * Update the specified topic and alert users about it.
       * @param topic the updated data of the topic.
       * @param alertType Notifies either all users (<code>"All"</code>"), only publishers
       * (<code>"Publisher"</code>) or nobody (<code>"None"</code>) about the topic creation.
       * @return the updated topic.
       * @see NodeDetail
       * @see NodePK
       * @since 1.0
       */
      NodeDetail updateTopic(NodeDetail topic, String alertType);

      /**
       * Return a subtopic to currentTopic
       * @param nodePK the id of the researched topic
       * @return the detail of the specified topic
       * @see NodeDetail
       * @since 1.0
       */
      NodeDetail getSubTopicDetail(NodePK nodePK);

      void changeTopicStatus(String newStatus, NodePK nodePK, boolean recursiveChanges);

      void sortSubTopics(NodePK fatherPK, boolean recursive, String[] criteria);

      List<NodeDetail> getTreeview(NodePK nodePK, String profile, boolean coWritingEnable,
          boolean draftVisibleWithCoWriting, String userId, boolean displayNb,
          boolean isRightsOnTopicsUsed);

      /**
       * Return the detail of a publication (only the Header)
       * @param pubPK the id of the publication
       * @return a PublicationDetail
       * @see org.silverpeas.core.contribution.publication.model.PublicationDetail
       * @since 1.0
       */
      PublicationDetail getPublicationDetail(PublicationPK pubPK);

      /**
       * Gets the publications linked to the folder represented by given {@link NodePK} reference.
       * <p>
       * In any case, user right access to a publication is verified so that only accessible ones are
       * included into returned list.
       * </p>
       * @param pk the reference to a folder.
       * @param userProfile a user profile
       * @param userId the identifier of the user for which access controls MUST be verified.
       * @param isTreeStructureUsed true if publications are represented into tree structure, false
       * otherwise.
       * @return a list of {@link KmeliaPublication} instances.
       */
      List<KmeliaPublication> getAuthorizedPublicationsOfFolder(NodePK pk, String userProfile,
          String userId, boolean isTreeStructureUsed);

      /**
       * Checks rights on publications order by descending begin visibility date of publication.
       * <p>
       * Due to the nature of this service, it is not designed to by used by update processes and the
       * result is so cached at request scope in order to avoid to perform several times the same
       * request.
       * </p>
       * @param instanceId the identifier of the instance.
       * @param userId the identifier of the user for which access controls MUST be verified.
       * @param limit the maximum number of publications to return (0 = no limit).
       * @return a list of {@link KmeliaPublication} instances.
       */
      List<KmeliaPublication> getLatestAuthorizedPublications(String instanceId, String userId,
          int limit);

      /**
       * Return list of all path to this publication - it's a Collection of NodeDetail collection
       * @param pubPK the id of the publication
       * @return a Collection of NodeDetail collection
       * @see NodeDetail
       * @since 1.0
       */
      Collection<Collection<NodeDetail>> getPathList(PublicationPK pubPK);

      /**
       * Gets the father of the specified publication. If the publication is a clone of a main one, then
       * gets the father of the cloned publication. The father returned should be the main location of
       * the publication. It the publication is an orphaned one, null is returned.
       * @param pubPK the identifying key of the publication.
       * @return the father of the publication or null if the publication is an orphaned one.
       */
      NodePK getPublicationFatherPK(PublicationPK pubPK);

      /**
       * Create a new Publication (only the header - parameters) to the current Topic
       * @param pubDetail a PublicationDetail
       * @return the id of the new publication
       * @see org.silverpeas.core.contribution.publication.model.PublicationDetail
       * @since 1.0
       */
      String createPublicationIntoTopic(PublicationDetail pubDetail, NodePK fatherPK);

      /**
       * Creates a new publication into the specified topic and with the specified classification on the
       * PdC.
       * @param pubDetail the detail about the publication to create.
       * @param fatherPK the unique identifier of the topic into which the publication is published.
       * @param classification the classification on the PdC of the publication content.
       * @return the unique identifier of the created publication.
       */
      String createPublicationIntoTopic(PublicationDetail pubDetail, NodePK fatherPK,
          PdcClassification classification);

      /**
       * Update a publication (only the header - parameters)
       * @param detail a PublicationDetail
       * @see org.silverpeas.core.contribution.publication.model.PublicationDetail
       * @since 1.0
       */
      void updatePublication(PublicationDetail detail);

      /**
       * Update a publication (only the header - parameters)
       * @param detail a PublicationDetail
       * @param classification the classification on the PdC of the publication content.
       * @see org.silverpeas.core.contribution.publication.model.PublicationDetail
       * @since 1.0
       */
      void updatePublication(PublicationDetail detail, PdcClassification classification);

      void updatePublication(PublicationDetail detail, boolean forceUpdateDate);

      /**
       * Add a publication to a topic and send email alerts to topic subscribers
       * @param pubPK the id of the publication
       * @param fatherPK the id of the topic
       * @since 1.0
       */
      void addPublicationToTopic(PublicationPK pubPK, NodePK fatherPK, boolean isACreation);

      void addPublicationToTopicWithoutNotifications(PublicationPK pubPK, NodePK fatherPK,
          boolean isACreation);

      /**
       * Updates the publication links
       * @param pubPK publication identifier which you want to update links
       * @param links list of publication to link with current.
       */
      void addInfoLinks(PublicationPK pubPK, List<ResourceReference> links);

      /**
       * Gets the complete details about the publication referred by the specified unique identifier.
       * @param pubPK the unique identifier of a Kmelia publication.
       * @return a {@link CompletePublication} object.
       */
      CompletePublication getCompletePublication(PublicationPK pubPK);

      /**
       * Gets the Kmelia publication identified by the specified identifying key and that is located
       * into the specified topic. As a Kmelia publication can be in different locations, all
       * publications other than the original father of the publication are considered as an alias of
       * that original publication. This is why it is required to know the father of the asked
       * publication.
       * @param pubPK identifier of the publication to get.
       * @param topicPK identifier of the topic in which the publication is located.
       * @return the asked {@link KmeliaPublication} instance.
       */
      KmeliaPublication getPublication(PublicationPK pubPK, NodePK topicPK);

      /**
       * Gets the details about the father from which the specified publication is accessible to the
       * given user. If the main location of the publication isn't accessible by the user, then the
       * first accessible alias of the publication is returned. If no aliases are accessible or defined,
       * the details of the root topic is returned.
       * <p>
       * The component instance set to given {@link PublicationPK} gives the priority of the resulting
       * {@link TopicDetail}. For example, in case of a main publication on instance A with aliases on
       * instance B, if component instance id set to given {@link PublicationPK} is the B one, then
       * {@link TopicDetail} result is about the best father PK (the best location) on instance B (so an
       * alias in that case).
       * </p>
       * @param pubPK the unique identifier of the publication.
       * @param isTreeStructureUsed is the tree view of the topics enabled?
       * @param userId the unique identifier of a user.
       * @return the details of the topic in which the publication is accessible by the given user.
       */
      TopicDetail getBestTopicDetailOfPublicationForUser(PublicationPK pubPK,
          boolean isTreeStructureUsed, String userId);

      /**
       * Gets the father of the specified publication according to the rights of the user. If the main
       * location of the publication isn't accessible by the user, then the first accessible alias of
       * the publication is returned. If no aliases are accessible or defined, the root topic is
       * returned.
       * <p>
       * The component instance set to given {@link PublicationPK} gives the priority of the resulting
       * {@link NodePK}. For example, into case of a main publication on instance A with aliases on
       * instance B, if component instance id set to given {@link PublicationPK} is the B one, then the
       * best father PK (the best location) on instance B is returned (so an alias in that case).
       * </p>
       * @param pubPK the unique identifier of the publication
       * @param userId the unique identifier of a user.
       * @return a topic in which the publication is accessible by the given user.
       */
      NodePK getBestLocationOfPublicationForUser(PublicationPK pubPK, String userId);

      /**
       * gets a list of PublicationDetail corresponding to the links parameter
       * @param references list of publication (componentID + publicationId)
       * @return a list of PublicationDetail
       */
      <T extends ResourceReference> List<PublicationDetail> getPublicationDetails(List<T> references);

      /**
       * Gets a list of publications with optional control access filtering.
       * <p>
       * When a folder is given as context, then the ALIAS information is computed on each publication.
       * </p>
       * @param references list of publication represented as {@link ResourceReference} instances.
       * @param userId identifier User. allow to check if the publication is accessible for current
       * user
       * @param contextFolder optional folder that represents if specified the folder into which the
       * given references are retrieved. It is MANDATORY to determinate alias status.
       * @param accessControlFiltering true to filter the publication according user rights.
       * @return a collection of Kmelia publications
       */
      <T extends ResourceReference> List<KmeliaPublication> getPublications(List<T> references,
          String userId, final NodePK contextFolder, boolean accessControlFiltering);

      /**
       * Gets a list of {@link Pair} of {@link KmeliaPublication} instances into context of modification
       * by a user represented by the given user id. On the left of a {@link Pair} instance, there is a
       * publication that can not be a null value. On the right, there is the clone of the publication
       * if any, and so, it can be null if the publication has got no clone.
       * <p>
       * The main location is computed for each publication (and clone) by taking care about
       * performances.
       * </p>
       * <p>
       * This service guarantees that the returned {@link KmeliaPublication} instances each aims the
       * main location.
       * </p>
       * @param references list of publication represented as {@link ResourceReference} instances.
       * @param userId identifier User. allow to check if the publication is accessible for current
       * user
       * @return a list of {@link Pair} of {@link KmeliaPublication} instances. A pair represents on the
       * left the publication and the eventual corresponding clone on the right if it exists.
       */
      <T extends ResourceReference> List<Pair<KmeliaPublication, KmeliaPublication>> getPublicationsForModification(
          List<T> references, String userId);

      /**
       * Gets the publications linked with the specified one and for which the specified user is
       * authorized to access.
       * @param publication the publication from which linked publications are get.
       * @param userId the unique identifier of a user. It allows to check if a linked publication is
       * accessible for the specified user.
       * @return a list of Kmelia publications.
       */
      List<KmeliaPublication> getLinkedPublications(KmeliaPublication publication, String userId);

      List<KmeliaPublication> getPublicationsToValidate(String componentId, String userId);

      boolean isUserCanValidatePublication(PublicationPK pubPK, String userId);

      ValidatorsList getAllValidators(PublicationPK pubPK);

      void setValidators(PublicationPK pubPK, String userIds);

      /**
       * @param pubPK id of the publication to validate. If publication is always visible, clone is
       * processed.
       * @param userId id of the user who validate
       * @param force if true, force to validate publication (bypass pending validations)
       * @param hasUserNoMoreValidationRight true if the given id represents a user which has no more
       * validation right (deleted user for example)
       * @return true if the validation process is complete (ie all validators have validated)
       */
      boolean validatePublication(PublicationPK pubPK, String userId, boolean force,
          final boolean hasUserNoMoreValidationRight);

      void unvalidatePublication(PublicationPK pubPK, String userId, String refusalMotive,
          int validationType);

      void suspendPublication(PublicationPK pubPK, String refusalMotive, String userId);

      /**
       * Change publication status from draft to valid (for publisher) or toValidate (for redactor)
       * @param pubPK the id of the publication
       */
      void draftOutPublication(PublicationPK pubPK, NodePK topicPK, String userProfile);

      PublicationDetail draftOutPublicationWithoutNotifications(PublicationPK pubPK, NodePK topicPK,
          String userProfile);

      void draftOutPublication(PublicationPK pubPK, NodePK topicPK, String userProfile,
          boolean forceUpdateDate);

      /**
       * Change publication status from any state to draft
       * @param pubPK the id of the publication
       */
      void draftInPublication(PublicationPK pubPK);

      void draftInPublication(PublicationPK pubPK, String userId);

      void movePublication(PublicationPK pubPK, NodePK to, KmeliaPasteDetail pasteContext);

      void movePublicationInSameApplication(PublicationPK pubPK, NodePK from,
          KmeliaPasteDetail pasteContext);

      /**
       * alert that an external elements of publication (wysiwyg, attachment, versioning) has been
       * created, updated or removed
       * @param pubPK - id of the publication which contains this external elements
       */
      void externalElementsOfPublicationHaveChanged(PublicationPK pubPK, String userId);

      void sendModificationAlert(int modificationScope, PublicationPK pubPK);

      /**
       * Send an email to alert users of a publication creation
       * @param pubPK the publication id
       */
      UserNotification getUserNotification(PublicationPK pubPK, NodePK topicPK);

      /**
       * Send an email to alert users about an attachment
       * @param pubPK the publication id
       */
      UserNotification getUserNotification(PublicationPK pubPK, SimpleDocumentPK documentPk,
          NodePK topicPK);

      /**
       * Send a notification to alert users about a folder
       * @param pk the folder id
       */
      UserNotification getUserNotification(NodePK pk);

      /**
       * delete reading controls to a publication
       * @param pubPK the id of a publication
       * @since 1.0
       */
      void deleteAllReadingControlsByPublication(PublicationPK pubPK);

      void indexKmelia(String componentId);

      int getSilverObjectId(PublicationPK pubPK);

      void deleteSilverContent(PublicationPK pubPK);

      void setModelUsed(String[] models, String instanceId, String nodeId);

      Collection<String> getModelUsed(String instanceId, String nodeId);

      /**
       * Get the axis on which publications are categorized in the specified component instance.
       * @param componentId the unique identifier of a component instance.
       * @return a list of axis as {@link NodeDetail} instances.
       */
      List<NodeDetail> getAxis(String componentId);

      /**
       * Get the header of the axis on which publications are categorized in the specified component
       * instance.
       * @param componentId the unique identifier of a component instance.
       * @return a list of axis headers as {@link NodeDetail} instances.
       */
      List<NodeDetail> getAxisHeaders(String componentId);

      /**
       * Add the given axis into the specified component instance.
       * @param axis the axis to add.
       * @param componentId the unique identifier of the component instance.
       * @return the identifier of the new added axis.
       */
      @SuppressWarnings("UnusedReturnValue")
      NodePK addAxis(NodeDetail axis, String componentId);

      /**
       * Update the given axis in the specified component instance.
       * @param axis the axis from which its counterpart in the data source will be updated.
       * @param componentId the unique identifier of a component instance.
       */
      void updateAxis(NodeDetail axis, String componentId);

      /**
       * Delete the given axis in the specified component instance.
       * @param axisId the unique identifier of the axis to delete.
       * @param componentId the unique identifier of a component instance.
       */
      void deleteAxis(String axisId, String componentId);

      /**
       * Get the header of the specified node.
       * @param id the unique identifier of a node
       * @param componentId the unique identifier of the component instance in which the node is.
       * @return a {@link NodeDetail} instance.
       */
      NodeDetail getNodeHeader(String id, String componentId);

      /**
       * Add position to an axis in the given component instance and for the specified user.
       * @param fatherId the identifier of the position that will be the father of the new one.
       * @param position the position to add.
       * @param componentId the unique identifier of the component instance.
       * @param userId the unique identifier of a user.
       */
      @SuppressWarnings("UnusedReturnValue")
      void addPosition(String fatherId, NodeDetail position, String componentId, String userId);

      /**
       * Update a position in an axis
       * @param position the position from which its counterpart in the data source will be updated.
       * @param componentId the unique identifier of the component instance in which belongs the axis.
       */
      void updatePosition(NodeDetail position, String componentId);

      /**
       * Delete a position in an axis
       * @param positionId the unique identifier of the position to delete.
       * @param componentId the unique identifier of the component instance in which belongs the axis.
       */
      void deletePosition(String positionId, String componentId);

      /**
       * Get path of a position in an axis.
       * @param positionId the unique identifier of a position.
       * @param componentId the unique identifier of the component instance in which belongs the axis.
       * @return the path of the position with a {@link NodeDetail} instance for each path's node.
       */
      Collection<NodeDetail> getPath(String positionId, String componentId);

      /**
       * Get publications categorized in a combination of positions.
       * @param combination a list of positions composing the combination.
       * @param componentId the unique identifier of the component instance in which belongs the
       * combination.
       * @return the publications that satisfy the combination of positions.
       */
      List<KmeliaPublication> search(List<String> combination, String componentId);

      /**
       * Get publications categorized in a combination of positions and that are visible or created the
       * given number of days ago.
       * @param combination a list of positions composing the combination.
       * @param nbDays the number of days before today.
       * @param componentId the unique identifier of the component instance in which belongs the
       * combination.
       * @return the publications that satisfy the combination of positions and the time criteria.
       */
      List<KmeliaPublication> search(List<String> combination, int nbDays, String componentId);

      /**
       * Get publications that aren't categorized on any axis.
       * @param componentId the unique identifier of a component instance.
       * @return the uncategorized publications.
       */
      Collection<KmeliaPublication> getUnbalancedPublications(String componentId);

      void indexKmax(String componentId);

      /**
       * Get the given publication for the given user.
       * @param pubId the unique identifier of a publication.
       * @param currentUserId the unique identifier of the user for whom the publications are asked.
       * @return the publication as a {@link KmeliaPublication} instance.
       */
      @SuppressWarnings("unused")
      KmeliaPublication getKmaxPublication(String pubId, String currentUserId);

      /**
       * Get the coordinates for the given publication on the axis of the specified component instance.
       * @param pubId the unique identifier of a publication.
       * @param componentId the unique identifier of the component instance.
       * @return a collection of coordinates
       */
      Collection<Coordinate> getPublicationCoordinates(String pubId, String componentId);

      /**
       * Add for the given publication a combination of position on the axis of the component instance.
       * @param pubId the unique identifier of a publication.
       * @param combination a list of coordinate identifiers.
       * @param componentId the unique identifier of the component instance.
       */
      void addPublicationToCombination(String pubId, List<String> combination, String componentId);

      /**
       * Remove for the given publication the specified combination of positions on the axis of the
       * component instance.
       * @param pubId the unique identifier of a publication.
       * @param combinationId the unique identifier of a combination of positions.
       * @param componentId the unique identifier of the component instance.
       */
      void deletePublicationFromCombination(String pubId, String combinationId, String componentId);

      /**
       * Create a new publication (only the header, no content) in a Kmax instance.
       * @param pubDetail the publication to create.
       * @return the id of the new publication
       * @see org.silverpeas.core.contribution.publication.model.PublicationDetail
       * @since 1.0
       */
      String createKmaxPublication(PublicationDetail pubDetail);

      /**
       * Gets all the locations of the specified publication; whatever the component instance. If the
       * given publication is a clone, then gets all the locations of the main publication.
       * @param pubPK the unique identifier of the publication.
       * @return a collection of the locations of the given publication.
       */
      Collection<Location> getLocations(PublicationPK pubPK);

      /**
       * Gets all the aliases of the specified publication, whatever the component instance and without
       * taking into account the publication is a clone or not. If the publication is a clone, then
       * nothing will be returned.
       * @param pubPK the unique identifier of the publication.
       * @return a collection of locations that are all the aliases for the given publication.
       */
      Collection<Location> getAliases(PublicationPK pubPK);

      @SuppressWarnings("unused")
      void setAliases(PublicationPK pubPK, List<Location> locations);

      void addAttachmentToPublication(PublicationPK pubPK, String userId, String filename,
          String description, byte[] contents);

      NodeDetail createTopic(String componentId, String topicId, String spaceId, String userId, String name,
          String description);

      /**
       * Clone the given publication. Create new publication based on pubDetail object if not null or
       * CompletePublication otherwise. Original publication will not be modified (except references to
       * clone: cloneId and cloneStatus).
       * @param pubDetail If not null, attribute values are set to the clone
       * @param nextStatus Draft or Clone
       * @return the identifier of the cloned publication.
       */
      String clonePublication(CompletePublication refPubComplete, PublicationDetail pubDetail,
          String nextStatus);

      void removeContentOfPublication(PublicationPK pubPK);

      NodeDetail getRoot(String componentId, String userId);

      Collection<NodeDetail> getFolderChildren(NodePK nodePK, String userId);

      /**
       * Gets the details about the specified folder. The difference with
       * {@link KmeliaService#getNodeHeader(String, String)} is that the children are also set as well
       * as other information like the number of publications.
       * @param nodePK the unique identifier of the folder.
       * @param userId the unique identifier of the user for which the folder is asked.
       * @return the {@link NodeDetail} instance corresponding to the folder.
       */
      NodeDetail getFolder(NodePK nodePK, String userId);

      NodeDetail getExpandedPathToNode(NodePK pk, String userId);

      boolean isUserCanWrite(String componentId, String userId);

      boolean isUserCanValidate(String componentId, String userId);

      boolean isUserCanPublish(String componentId, String userId);

      String getUserTopicProfile(NodePK pk, String userId);

      /**
       * Deletes the specified publications located into the given topic. Before a publication is
       * removed, the privileges of the specified user is checked. This user can be the requester or
       * another user endorsing the deletion for the requester. If the topic is the trash folder, then
       * the publications are definitively deleted. Otherwise, they are just moved into the bin.
       *
       * @param publiIds a list of local identifier of the publications to delete.
       * @param topicId the node PK of the topic in which the publications are located.
       * @param userId the unique identifier of the user for which the deletion is performed.
       * @return the list of the unique identifiers of the actually deleted publications.
       */
      List<String> deletePublications(List<String> publiIds, NodePK topicId, String userId);

      /**
       * Deletes the specified publication. Before the publication is removed, the privileges of the
       * given user is checked. This user can be the requester or another user endorsing the deletion
       * for the requester. For doing, the profile of the user is checked against the topic in which the
       * publication is originally located. If the topic is the trash folder, then the publication is
       * definitively deleted. Otherwise, it is just moved into the bin.
       *
       * @param pubPK the unique identifier of the publication.
       * @param userId the unique identifier of the user for which the deletion is performed.
       */
      void deletePublication(PublicationPK pubPK, String userId);

      /**
       * Deletes the specified topic located into the given parent topic. Before the topic is deleted,
       * the privileges of the specified user is checked. If topic is in the trash folder, then the
       * topic is definitively deleted. Otherwise, it is just moved into the bin.
       *
       * @param topic the unique identifier of the topic
       * @param userId the unique identifier of the user asking the deletion.
       */
      void deleteTopic(@NonNull NodePK topic, String userId);

      List<String> getUserIdsOfFolder(NodePK pk);

      List<HistoryObjectDetail> getLastAccess(PublicationPK pk, NodePK nodePK, String excludedUserId,
          final int maxResult);

      /**
       * Copies the node according to the information provided by the specified copy descriptor.
       *
       * @param copyDetail a descriptor giving details about the copy to perform like the node to copy
       * and the destination.
       * @return the copy of the node.
       */
      @SuppressWarnings("UnusedReturnValue")
      NodeDetail copyNode(KmeliaCopyDetail copyDetail);

      /**
       * Copies all the publications defined in the specified copy descriptor.
       *
       * @param copyDetail a descriptor providing information about the publications to copy and the
       * destination of the copy.
       */
      void copyPublications(KmeliaCopyDetail copyDetail);

      /**
       * Copies the specified publication according to the given copy descriptor. In the case the
       * publication is an alias, then the copy adds a new location to the original copy. Otherwise, the
       * publication is well copied.
       *
       * @param publication the publication to copy.
       * @param copyDetail a descriptor providing details about the copy like the destination.
       * @return the copy of the publication or the publication itself in the case of a new location.
       */
      @SuppressWarnings("UnusedReturnValue")
      PublicationDetail copyPublication(PublicationDetail publication, KmeliaCopyDetail copyDetail);

      void moveNode(NodePK nodePK, NodePK to, KmeliaPasteDetail pasteContext);

      List<KmeliaPublication> filterPublications(List<KmeliaPublication> publications,
          String instanceId, SilverpeasRole profile, String userId);

      void userHaveBeenDeleted(String userId);

      List<String> getActiveValidatorIds(PublicationPK pk);

      /**
       * Performs processes about kmelia linked to given reminder.<br/> If kmelia is not concerned,
       * nothing is performed.
       *
       * @param reminder a {@link Reminder} instance.
       */
      void performReminder(final Reminder reminder);

      void deleteClone(PublicationPK pk);

      List<KmeliaPublication> getNonVisiblePublications(String componentId, String userId);
    }