@Test
  public void testReadAclAfterCopy() {
    DocumentModel folder1 = new DocumentModelImpl("/", "folder1", "Folder");
    folder1 = session.createDocument(folder1);
    DocumentModel folder2 = new DocumentModelImpl("/", "folder2", "Folder");
    folder2 = session.createDocument(folder2);
    DocumentModel doc = new DocumentModelImpl("/folder1", "doc", "File");
    doc = session.createDocument(doc);

    // set ACL on folder2
    ACL acl = new ACLImpl();
    acl.add(new ACE("Everyone", "Read", true));
    ACP acp = new ACPImpl();
    acp.addACL(acl);
    folder2.setACP(acp, true);
    session.save();

    // doc under folder1 cannot be read by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM File");
      assertEquals(0, list.size());
    }

    // copy doc under folder2
    session.copy(doc.getRef(), folder2.getRef(), "doccopy");
    session.save();

    // check doc copy now readable by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM File");
      assertEquals(1, list.size());
      assertEquals("doccopy", list.get(0).getName());
    }
  }
 public DocumentModelList getPageWidgets(String docType) {
   DocumentModelList list = new DocumentModelListImpl();
   Directories dirEnum = Directories.fromString("labs_" + docType + "_widgets");
   Map<String, Serializable> filter = new HashMap<String, Serializable>();
   filter.put("obsolete", "0");
   list.addAll(DirectoriesUtils.getDirDocumentModelList(dirEnum, filter));
   return list;
 }
  private void emailEnglishAssertions(String filePath) throws Exception {
    // initialize mailboxes
    getPersonalMailbox("jdoe");

    injectEmail(filePath);
    DocumentRef dayRef = new PathRef(CaseConstants.CASE_ROOT_DOCUMENT_PATH + "/2009/03/17");
    assertTrue(session.exists(dayRef));
    DocumentModelList envelopes = session.getChildren(dayRef, MailConstants.MAIL_ENVELOPE_TYPE);
    assertEquals(1, envelopes.size());

    DocumentModel envelopeDoc = envelopes.get(0);
    Case envelope = envelopeDoc.getAdapter(Case.class);
    List<DocumentModel> linkedDocs = envelope.getDocuments();
    assertEquals(2, linkedDocs.size());
    DocumentModel firstDoc = linkedDocs.get(0);

    String title = (String) firstDoc.getPropertyValue(CaseConstants.TITLE_PROPERTY_NAME);
    assertEquals("[Fwd: RENOUVELLEMENT DE SUPPORT ANNUEL NUXEO]", title);
    Calendar originalReceptionDate =
        (Calendar) firstDoc.getPropertyValue(CaseConstants.DOCUMENT_IMPORT_DATE_PROPERTY_NAME);
    assertEquals(
        emailDateParser.parse("Wed, 14 Jan 2009 15:15:25 +0100").getTime(),
        originalReceptionDate.getTime().getTime());
    Calendar receptionDate =
        (Calendar) firstDoc.getPropertyValue(CaseConstants.DOCUMENT_RECEIVE_DATE_PROPERTY_NAME);
    assertEquals(
        emailDateParser.parse("Tue, 17 Mar 2009 13:39:05 +0100").getTime(),
        receptionDate.getTime().getTime());

    Contacts senders = Contacts.getContactsForDoc(firstDoc, CaseConstants.CONTACTS_SENDERS);
    assertNotNull(senders);
    assertEquals(1, senders.size());
    Contact sender = senders.get(0);
    assertEquals("Sylvie KAPCOM", sender.getName());
    assertEquals("*****@*****.**", sender.getEmail());

    Contacts recipients = Contacts.getContactsForDoc(firstDoc, CaseConstants.CONTACTS_PARTICIPANTS);
    assertNotNull(recipients);
    assertEquals(2, recipients.size());

    assertEquals("*****@*****.**", recipients.get(0).getEmail());

    assertTrue(
        (recipients.get(1).getName() == null) || ("".equals(recipients.get(1).getName().trim())));
    assertEquals("*****@*****.**", recipients.get(1).getEmail());

    // testing content
    DocumentModel secondDoc = linkedDocs.get(1);
    Blob fileBlob = (Blob) secondDoc.getPropertyValue(CaseConstants.FILE_PROPERTY_NAME);

    assertEquals("The file blob filename is", "testpdf.pdf", fileBlob.getFilename());
    assertEquals("the file blob length is", 24016, fileBlob.getLength());

    String fileNamePropertyValue =
        (String) secondDoc.getPropertyValue(CaseConstants.FILENAME_PROPERTY_NAME);
    assertEquals("The filename property value is", "testpdf.pdf", fileNamePropertyValue);
  }
Example #4
0
  @Test
  public void shouldDenyAccessOnUnsupportedACL() throws Exception {
    assumeTrue(session.isNegativeAclAllowed());

    buildAndIndexTree();
    DocumentModelList docs = ess.query(new NxQueryBuilder(session).nxql("select * from Document"));
    Assert.assertEquals(10, docs.totalSize());

    // check for user with no rights
    CoreSession restrictedSession = getRestrictedSession("toto");
    try {
      docs = ess.query(new NxQueryBuilder(restrictedSession).nxql("select * from Document"));
      Assert.assertEquals(0, docs.totalSize());

      // add READ rights and check that user now has access
      DocumentRef ref = new PathRef("/folder0/folder1/folder2");
      ACP acp = new ACPImpl();
      ACL acl = ACPImpl.newACL(ACL.LOCAL_ACL);
      acl.add(new ACE("toto", SecurityConstants.READ, true));
      acp.addACL(acl);
      session.setACP(ref, acp, true);

      TransactionHelper.commitOrRollbackTransaction();
      waitForCompletion();

      startTransaction();
      docs =
          ess.query(
              new NxQueryBuilder(restrictedSession)
                  .nxql("select * from Document order by dc:title"));
      Assert.assertEquals(8, docs.totalSize());

      // Add an unsupported negative ACL
      ref = new PathRef("/folder0/folder1/folder2/folder3/folder4/folder5");
      acp = new ACPImpl();
      acl = ACPImpl.newACL(ACL.LOCAL_ACL);
      acl.add(new ACE("bob", SecurityConstants.EVERYTHING, false));

      acp.addACL(acl);
      session.setACP(ref, acp, true);
      session.save();
      TransactionHelper.commitOrRollbackTransaction();
      waitForCompletion();

      startTransaction();
      docs =
          ess.query(
              new NxQueryBuilder(restrictedSession)
                  .nxql("select * from Document order by dc:title"));
      // can view folder2, folder3 and folder4
      Assert.assertEquals(3, docs.totalSize());
    } finally {
      restrictedSession.close();
    }
  }
Example #5
0
  @Test
  public void shouldStoreOnlyEffectiveACEs() throws Exception {
    buildAndIndexTree();

    DocumentModelList docs = ess.query(new NxQueryBuilder(session).nxql("select * from Document"));
    Assert.assertEquals(10, docs.totalSize());

    CoreSession restrictedSession = getRestrictedSession("toto");
    try {
      docs = ess.query(new NxQueryBuilder(restrictedSession).nxql("select * from Document"));
      Assert.assertEquals(0, docs.totalSize());

      DocumentRef ref = new PathRef("/folder0");
      ACP acp = new ACPImpl();
      ACL acl = ACPImpl.newACL(ACL.LOCAL_ACL);
      acl.add(ACE.builder("toto", SecurityConstants.READ).build());
      acp.addACL(acl);
      session.setACP(ref, acp, true);

      TransactionHelper.commitOrRollbackTransaction();
      waitForCompletion();

      startTransaction();
      docs =
          ess.query(
              new NxQueryBuilder(restrictedSession)
                  .nxql("select * from Document order by dc:title"));
      Assert.assertEquals(10, docs.totalSize());

      acp = new ACPImpl();
      acl = ACPImpl.newACL(ACL.LOCAL_ACL);
      // make the ACE archived
      Date now = new Date();
      Calendar begin = new GregorianCalendar();
      begin.setTimeInMillis(now.toInstant().minus(10, ChronoUnit.DAYS).toEpochMilli());
      Calendar end = new GregorianCalendar();
      end.setTimeInMillis(now.toInstant().minus(2, ChronoUnit.DAYS).toEpochMilli());
      acl.add(ACE.builder("toto", SecurityConstants.READ).begin(begin).end(end).build());
      acp.addACL(acl);
      session.setACP(ref, acp, true);

      TransactionHelper.commitOrRollbackTransaction();
      waitForCompletion();

      startTransaction();
      docs =
          ess.query(
              new NxQueryBuilder(restrictedSession)
                  .nxql("select * from Document order by dc:title"));
      Assert.assertEquals(0, docs.totalSize());
    } finally {
      restrictedSession.close();
    }
  }
 @Test
 public void testQueryFulltext() throws Exception {
   Map<String, Serializable> filter = new HashMap<String, Serializable>();
   Set<String> fulltext = new HashSet<String>();
   DocumentModelList entries;
   entries = dir.query(filter, fulltext);
   assertEquals(4, entries.size());
   // null fulltext set should be equivalent to empty one
   entries = dir.query(filter, null);
   assertEquals(4, entries.size());
 }
  /**
   * Returns the CSIDs of CollectionObject records that are related to a Movement record.
   *
   * @param movementCsid the CSID of a Movement record.
   * @param coreSession a repository session.
   * @throws ClientException
   * @return the CSIDs of the CollectionObject records, if any, which are related to the Movement
   *     record.
   */
  private Set<String> getCollectionObjectCsidsRelatedToMovement(
      String movementCsid, CoreSession coreSession) throws ClientException {

    Set<String> csids = new HashSet<>();

    // Via an NXQL query, get a list of active relation records where:
    // * This movement record's CSID is the subject CSID of the relation,
    //   and its object document type is a CollectionObject doctype;
    // or
    // * This movement record's CSID is the object CSID of the relation,
    //   and its subject document type is a CollectionObject doctype.
    //
    // Some values below are hard-coded for readability, rather than
    // being obtained from constants.
    String query =
        String.format(
            "SELECT * FROM %1$s WHERE " // collectionspace_core:tenantId = 1 "
                + "("
                + "  (%2$s:subjectCsid = '%3$s' "
                + "  AND %2$s:objectDocumentType = '%4$s') "
                + " OR "
                + "  (%2$s:objectCsid = '%3$s' "
                + "  AND %2$s:subjectDocumentType = '%4$s') "
                + ")"
                + ACTIVE_DOCUMENT_WHERE_CLAUSE_FRAGMENT,
            RELATION_DOCTYPE,
            RELATIONS_COMMON_SCHEMA,
            movementCsid,
            COLLECTIONOBJECT_DOCTYPE);
    DocumentModelList relationDocModels = coreSession.query(query);
    if (relationDocModels == null || relationDocModels.isEmpty()) {
      // Encountering a Movement record that is not related to any
      // CollectionObject is potentially a normal occurrence, so no
      // error messages are logged here when we stop handling this event.
      return csids;
    }
    // Iterate through the list of Relation records found and build
    // a list of CollectionObject CSIDs, by extracting the relevant CSIDs
    // from those Relation records.
    String csid;
    for (DocumentModel relationDocModel : relationDocModels) {
      csid =
          getCsidForDesiredDocTypeFromRelation(
              relationDocModel, COLLECTIONOBJECT_DOCTYPE, MOVEMENT_DOCTYPE);
      if (Tools.notBlank(csid)) {
        csids.add(csid);
      }
    }
    return csids;
  }
  @Test
  public void testReadAclAfterSetACP() {
    DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel doc = new DocumentModelImpl("/folder", "doc", "File");
    doc = session.createDocument(doc);
    session.save();

    // nothing can be seen by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(0, list.size());
      list = joeSession.query("SELECT * FROM File");
      assertEquals(0, list.size());
    }

    // set ACL on folder
    ACL acl = new ACLImpl();
    acl.add(new ACE("Everyone", "Read", true));
    ACP acp = new ACPImpl();
    acp.addACL(acl);
    folder.setACP(acp, true);
    session.save();

    // now joe sees things
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
      assertEquals(folder.getId(), list.get(0).getId());
      list = joeSession.query("SELECT * FROM File");
      assertEquals(1, list.size());
      assertEquals(doc.getId(), list.get(0).getId());
    }
  }
Example #9
0
  @Test
  public void shouldIndexOnCopy() throws Exception {
    buildAndIndexTree();

    DocumentRef src = new PathRef("/folder0/folder1/folder2");
    DocumentRef dst = new PathRef("/folder0");
    session.copy(src, dst, "folder2-copy");

    TransactionHelper.commitOrRollbackTransaction();
    waitForCompletion();

    startTransaction();
    DocumentModelList docs = ess.query(new NxQueryBuilder(session).nxql("select * from Document"));
    Assert.assertEquals(18, docs.totalSize());
  }
 @Test
 public void testGetEntries() throws Exception {
   DocumentModelList l;
   l = dir.getEntries();
   assertEquals(4, l.size());
   DocumentModel entry = null;
   for (DocumentModel e : l) {
     if (e.getId().equals("1")) {
       entry = e;
       break;
     }
   }
   assertNotNull(entry);
   assertEquals("foo1", entry.getProperty("schema3", "thefoo"));
 }
Example #11
0
 public static DocumentModelList getDirectoryEntries(String directoryName, String... entryIds)
     throws ClientException {
   if (entryIds == null) {
     return null;
   }
   DirectoryService dirService = Framework.getService(DirectoryService.class);
   try (Session session = dirService.open(directoryName)) {
     DocumentModelList result = new DocumentModelListImpl();
     for (String entryId : entryIds) {
       DocumentModel entry = session.getEntry(entryId);
       if (entry != null) {
         result.add(entry);
       }
     }
     return result;
   }
 }
  @Test
  public void testReadOnlyEntryInGetEntriesResults() throws Exception {
    Map<String, String> orderBy = new HashMap<String, String>();
    orderBy.put("schema3:uid", "asc");
    DocumentModelComparator comp = new DocumentModelComparator(orderBy);

    DocumentModelList results = dir.getEntries();
    Collections.sort(results, comp);

    // by default no backing dir is readonly
    assertFalse(BaseSession.isReadOnlyEntry(results.get(0)));
    assertFalse(BaseSession.isReadOnlyEntry(results.get(1)));
    assertFalse(BaseSession.isReadOnlyEntry(results.get(2)));
    assertFalse(BaseSession.isReadOnlyEntry(results.get(3)));

    memdir1.setReadOnly(true);
    memdir2.setReadOnly(false);
    memdir3.setReadOnly(false);
    results = dir.getEntries();
    Collections.sort(results, comp);
    assertTrue(BaseSession.isReadOnlyEntry(results.get(0)));
    assertTrue(BaseSession.isReadOnlyEntry(results.get(1)));
    assertFalse(BaseSession.isReadOnlyEntry(results.get(2)));
    assertFalse(BaseSession.isReadOnlyEntry(results.get(3)));

    memdir1.setReadOnly(false);
    memdir2.setReadOnly(false);
    memdir3.setReadOnly(true);
    results = dir.getEntries();
    Collections.sort(results, comp);
    assertFalse(BaseSession.isReadOnlyEntry(results.get(0)));
    assertFalse(BaseSession.isReadOnlyEntry(results.get(1)));
    assertTrue(BaseSession.isReadOnlyEntry(results.get(2)));
    assertTrue(BaseSession.isReadOnlyEntry(results.get(3)));
  }
 @Test
 public void testGetEntries() throws ClientException {
   Session session = getLDAPDirectory("userDirectory").getSession();
   try {
     DocumentModelList entries = session.getEntries();
     assertNotNull(entries);
     assertEquals(4, entries.size());
     List<String> entryIds = new ArrayList<String>();
     for (DocumentModel entry : entries) {
       entryIds.add(entry.getId());
     }
     Collections.sort(entryIds);
     assertEquals("Administrator", entryIds.get(0));
     assertEquals("user1", entryIds.get(1));
     assertEquals("user2", entryIds.get(2));
     assertEquals("user3", entryIds.get(3));
   } finally {
     session.close();
   }
 }
  @Test
  public void testBlobFilenamePresent() throws Exception {
    createDocs();

    ExportedDocument exportedDoc = new ExportedDocumentImpl(docToExport, true);
    assertEquals("File", exportedDoc.getType());

    session.removeDocument(docToExport.getRef());
    session.save();
    assertEquals(0, session.getChildren(workspace.getRef()).size());

    DocumentWriter writer = new DocumentModelWriter(session, rootDocument.getPathAsString());
    writer.write(exportedDoc);

    DocumentModelList children = session.getChildren(workspace.getRef());
    assertEquals(1, children.size());
    DocumentModel importedDocument = children.get(0);
    Blob blob = (Blob) importedDocument.getProperty("file", "content");
    assertEquals("dummyBlob.txt", blob.getFilename());
  }
  @Test
  public void testQuery1() {
    try (Session session = getLDAPDirectory("userDirectory").getSession()) {
      Map<String, Serializable> filter = new HashMap<String, Serializable>();
      filter.put("username", "user");
      Set<String> fulltext = new HashSet<String>();
      fulltext.add("username");
      DocumentModelList entries = session.query(filter, fulltext);
      assertNotNull(entries);
      assertEquals(2, entries.size());

      List<String> entryIds = new ArrayList<String>();
      for (DocumentModel entry : entries) {
        entryIds.add(entry.getId());
      }
      Collections.sort(entryIds);
      assertEquals("*****@*****.**", entryIds.get(0));
      assertEquals("*****@*****.**", entryIds.get(1));
    }
  }
 /** Looks if an existing Document has the same value for a given property. */
 public static DocumentModel getExistingDocByPropertyName(
     CoreSession documentManager, String path, String value, String propertyName)
     throws ClientException {
   DocumentModel existing = null;
   String parentId = documentManager.getDocument(new PathRef(path)).getId();
   String query =
       "SELECT * FROM Document WHERE ecm:parentId = '"
           + parentId
           + "' AND "
           + propertyName
           + " = '"
           + value.replace("'", "\\\'")
           + "' AND ecm:currentLifeCycleState != '"
           + LifeCycleConstants.DELETED_STATE
           + "'";
   DocumentModelList docs = documentManager.query(query, 1);
   if (docs.size() > 0) {
     existing = docs.get(0);
   }
   return existing;
 }
  @Override
  public List<String> getProjection(
      Map<String, Serializable> filter, Set<String> fulltext, String columnName) {

    // There's no way to do an efficient getProjection to a source with
    // multiple subdirectories given the current API (we'd need an API that
    // passes several columns).
    // So just do a non-optimal implementation for now.

    final DocumentModelList entries = query(filter, fulltext);
    final List<String> results = new ArrayList<String>(entries.size());
    for (DocumentModel entry : entries) {
      final Object value = entry.getProperty(schemaName, columnName);
      if (value == null) {
        results.add(null);
      } else {
        results.add(value.toString());
      }
    }
    return results;
  }
 /**
  * Returns a document model for a record identified by a CSID.
  *
  * @param session a repository session.
  * @param collectionObjectCsid a CollectionObject identifier (CSID)
  * @return a document model for the record identified by the supplied CSID.
  */
 protected static DocumentModel getDocModelFromCsid(
     CoreSession session, String collectionObjectCsid) {
   DocumentModelList collectionObjectDocModels = null;
   try {
     final String query =
         "SELECT * FROM "
             + NuxeoUtils.BASE_DOCUMENT_TYPE
             + " WHERE "
             + NuxeoUtils.getByNameWhereClause(collectionObjectCsid);
     collectionObjectDocModels = session.query(query);
   } catch (Exception e) {
     logger.warn("Exception in query to get document model for CollectionObject: ", e);
   }
   if (collectionObjectDocModels == null || collectionObjectDocModels.isEmpty()) {
     logger.warn("Could not get document models for CollectionObject(s).");
     return null;
   } else if (collectionObjectDocModels.size() != 1) {
     logger.debug("Found more than 1 document with CSID=" + collectionObjectCsid);
     return null;
   }
   return collectionObjectDocModels.get(0);
 }
Example #19
0
  @Test
  public void shouldReindexSubTreeInTrash() throws Exception {
    buildAndIndexTree();
    startTransaction();
    DocumentRef ref = new PathRef("/folder0/folder1/folder2");
    Assert.assertTrue(session.exists(ref));
    session.followTransition(ref, "delete");

    TransactionHelper.commitOrRollbackTransaction();
    // let the bulkLifeCycleChangeListener do its work
    waitForCompletion();
    assertNumberOfCommandProcessed(8);

    startTransaction();
    DocumentModelList docs =
        ess.query(
            new NxQueryBuilder(session)
                .nxql("select * from Document where ecm:currentLifeCycleState != 'deleted'"));
    // for (DocumentModel doc : docs) {
    // System.out.println(doc.getPathAsString());
    // }
    Assert.assertEquals(2, docs.totalSize());
  }
 protected void updateUserCatalog(UserManager userManager) throws ClientException {
   DocumentModelList allUsers = userManager.searchUsers(null);
   userCatalog = new HashMap<String, DocumentModelList>();
   String userSortField = userManager.getUserSortField();
   for (DocumentModel user : allUsers) {
     // FIXME: this should use a "display name" dedicated API
     String displayName = null;
     if (userSortField != null) {
       // XXX hack, principals have only one model
       org.nuxeo.ecm.core.api.DataModel dm = user.getDataModels().values().iterator().next();
       displayName = (String) dm.getData(userSortField);
     }
     if (StringUtils.isEmpty(displayName)) {
       displayName = user.getId();
     }
     String firstLetter = displayName.substring(0, 1).toUpperCase();
     DocumentModelList list = userCatalog.get(firstLetter);
     if (list == null) {
       list = new DocumentModelListImpl();
       userCatalog.put(firstLetter, list);
     }
     list.add(user);
   }
 }
  @Test
  public void testReadAclSecurityUpdate() {
    // check that aclOptimization update the user aclr cache
    // NXP-13109
    DocumentModel root = session.getRootDocument();
    // Create a doc and set a new ACLR on it
    DocumentModel doc = new DocumentModelImpl(root.getPathAsString(), "foo", "Folder");
    doc = session.createDocument(doc);
    ACP acp = doc.getACP();
    assertNotNull(acp);
    acp = new ACPImpl();
    ACL acl = new ACLImpl();
    acl.add(new ACE("Everyone", "Read", true));
    acp.addACL(acl);
    doc.setACP(acp, true);
    session.save();

    CoreSession joeSession = openSessionAs("joe");
    try {
      DocumentModelList list;
      list = joeSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
      // Remove the document, so the ACLR created is not anymore assigned
      session.removeDocument(doc.getRef());
      session.save();
      list = joeSession.query("SELECT * FROM Folder");
      assertEquals(0, list.size());
    } finally {
      closeSession(joeSession);
    }

    CoreSession bobSession = openSessionAs("bob");
    try {
      DocumentModelList list;
      // Perform a query to init the ACLR cache
      list = bobSession.query("SELECT * FROM Folder");
      assertEquals(0, list.size());
      // Create a new doc with the same ACLR
      doc = new DocumentModelImpl(root.getPathAsString(), "bar", "Folder");
      doc = session.createDocument(doc);
      doc.setACP(acp, true);
      session.save();
      // Check that the ACLR has been added to the user cache
      list = bobSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
    } finally {
      closeSession(bobSession);
    }
  }
  /**
   * Returns the most recent Movement record related to a CollectionObject.
   *
   * <p>This method currently returns the related Movement record with the latest (i.e. most recent
   * in time) Location Date field value.
   *
   * @param session a repository session.
   * @param collectionObjectCsid a CollectionObject identifier (CSID)
   * @throws ClientException
   * @return the most recent Movement record related to the CollectionObject identified by the
   *     supplied CSID.
   */
  protected static DocumentModel getMostRecentMovement(
      CoreSession session, String collectionObjectCsid) throws ClientException {
    DocumentModel mostRecentMovementDocModel = null;
    // Get Relation records for Movements related to this CollectionObject.
    //
    // Some values below are hard-coded for readability, rather than
    // being obtained from constants.
    String query =
        String.format(
            "SELECT * FROM %1$s WHERE " // collectionspace_core:tenantId = 1 "
                + "("
                + "  (%2$s:subjectCsid = '%3$s' "
                + "  AND %2$s:objectDocumentType = '%4$s') "
                + " OR "
                + "  (%2$s:objectCsid = '%3$s' "
                + "  AND %2$s:subjectDocumentType = '%4$s') "
                + ")"
                + ACTIVE_DOCUMENT_WHERE_CLAUSE_FRAGMENT,
            RELATION_DOCTYPE,
            RELATIONS_COMMON_SCHEMA,
            collectionObjectCsid,
            MOVEMENT_DOCTYPE);
    if (logger.isTraceEnabled()) {
      logger.trace("query=" + query);
    }
    DocumentModelList relationDocModels = session.query(query);
    if (relationDocModels == null || relationDocModels.isEmpty()) {
      logger.warn(
          "Unexpectedly found no relations to Movement records to/from to this CollectionObject record.");
      return mostRecentMovementDocModel;
    } else {
      if (logger.isTraceEnabled()) {
        logger.trace(
            "Found "
                + relationDocModels.size()
                + " relations to Movement records to/from this CollectionObject record.");
      }
    }
    // Iterate through related movement records, to find the related
    // Movement record with the most recent location date.
    GregorianCalendar mostRecentLocationDate = EARLIEST_COMPARISON_DATE;
    // Note: the following value is used to compare any two records, rather
    // than to identify the most recent value so far encountered. Thus, it may
    // occasionally be set backward or forward in time, within the loop below.
    GregorianCalendar comparisonCreationDate = EARLIEST_COMPARISON_DATE;
    DocumentModel movementDocModel;
    Set<String> alreadyProcessedMovementCsids = new HashSet<>();
    String relatedMovementCsid;
    for (DocumentModel relationDocModel : relationDocModels) {
      // Due to the 'OR' operator in the query above, related Movement
      // record CSIDs may reside in either the subject or object CSID fields
      // of the relation record. Whichever CSID value doesn't match the
      // CollectionObject's CSID is inferred to be the related Movement record's CSID.
      relatedMovementCsid =
          (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, SUBJECT_CSID_PROPERTY);
      if (relatedMovementCsid.equals(collectionObjectCsid)) {
        relatedMovementCsid =
            (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_CSID_PROPERTY);
      }
      if (Tools.isBlank(relatedMovementCsid)) {
        continue;
      }
      // Because of the OR clause used in the query above, there may be
      // two or more Relation records returned in the query results that
      // reference the same Movement record, as either the subject
      // or object of a relation to the same CollectionObject record;
      // we need to filter out those duplicates.
      if (alreadyProcessedMovementCsids.contains(relatedMovementCsid)) {
        continue;
      } else {
        alreadyProcessedMovementCsids.add(relatedMovementCsid);
      }
      if (logger.isTraceEnabled()) {
        logger.trace("Related movement CSID=" + relatedMovementCsid);
      }
      movementDocModel = getDocModelFromCsid(session, relatedMovementCsid);
      if (movementDocModel == null) {
        continue;
      }

      // Verify that the Movement record is active. This will also exclude
      // versioned Movement records from the computation of the current
      // location, for tenants that are versioning such records.
      if (!isActiveDocument(movementDocModel)) {
        if (logger.isTraceEnabled()) {
          logger.trace("Skipping this inactive Movement record ...");
        }
        continue;
      }
      GregorianCalendar locationDate =
          (GregorianCalendar)
              movementDocModel.getProperty(MOVEMENTS_COMMON_SCHEMA, LOCATION_DATE_PROPERTY);
      // If the current Movement record lacks a location date, it cannot
      // be established as the most recent Movement record; skip over it.
      if (locationDate == null) {
        continue;
      }
      GregorianCalendar creationDate =
          (GregorianCalendar)
              movementDocModel.getProperty(COLLECTIONSPACE_CORE_SCHEMA, CREATED_AT_PROPERTY);
      if (locationDate.after(mostRecentLocationDate)) {
        mostRecentLocationDate = locationDate;
        if (creationDate != null) {
          comparisonCreationDate = creationDate;
        }
        mostRecentMovementDocModel = movementDocModel;
        // If the current Movement record's location date is identical
        // to that of the (at this time) most recent Movement record, then
        // instead compare the two records using their creation date values
      } else if (locationDate.compareTo(mostRecentLocationDate) == 0) {
        if (creationDate != null && creationDate.after(comparisonCreationDate)) {
          // The most recent location date value doesn't need to be
          // updated here, as the two records' values are identical
          comparisonCreationDate = creationDate;
          mostRecentMovementDocModel = movementDocModel;
        }
      }
    }
    return mostRecentMovementDocModel;
  }
  @Test
  public void testQuery() throws Exception {
    Map<String, Serializable> filter = new HashMap<String, Serializable>();
    DocumentModelList entries;
    DocumentModel e;

    // empty filter means everything (like getEntries)
    entries = dir.query(filter);
    assertNotNull(entries);
    assertEquals(4, entries.size());

    // no result
    filter.put("thefoo", "f");
    entries = dir.query(filter);
    assertEquals(0, entries.size());

    // query matching one source
    // source with two subdirs
    filter.put("thefoo", "foo1");
    entries = dir.query(filter);
    assertEquals(1, entries.size());
    e = entries.get(0);
    assertEquals("1", e.getId());
    assertEquals("bar1", e.getProperty("schema3", "thebar"));
    // simple source
    filter.put("thefoo", "foo3");
    entries = dir.query(filter);
    assertEquals(1, entries.size());
    e = entries.get(0);
    assertEquals("3", e.getId());
    assertEquals("bar3", e.getProperty("schema3", "thebar"));

    // query matching two subdirectories in one source
    filter.put("thefoo", "foo1");
    filter.put("thebar", "bar1");
    entries = dir.query(filter);
    assertEquals(1, entries.size());
    e = entries.get(0);
    assertEquals("1", e.getId());
    assertEquals("foo1", e.getProperty("schema3", "thefoo"));
    assertEquals("bar1", e.getProperty("schema3", "thebar"));

    // query not matching although each subdirectory in the source matches
    filter.put("thefoo", "foo1");
    filter.put("thebar", "bar2");
    entries = dir.query(filter);
    assertEquals(0, entries.size());

    // query matching two sources
    filter.clear();
    e = dir.getEntry("1");
    e.setProperty("schema3", "thefoo", "matchme");
    dir.updateEntry(e);
    e = dir.getEntry("3");
    e.setProperty("schema3", "thefoo", "matchme");
    dir.updateEntry(e);
    filter.put("thefoo", "matchme");
    entries = dir.query(filter);
    assertEquals(2, entries.size());
    e = entries.get(0);
    assertEquals("1", e.getId());
    assertEquals("bar1", e.getProperty("schema3", "thebar"));
    e = entries.get(1);
    assertEquals("3", e.getId());
    assertEquals("bar3", e.getProperty("schema3", "thebar"));
  }
  @Override
  @SuppressWarnings("boxing")
  public DocumentModelList query(
      Map<String, Serializable> filter,
      Set<String> fulltext,
      Map<String, String> orderBy,
      boolean fetchReferences) {
    // list of entries
    final DocumentModelList results = new DocumentModelListImpl();
    if (!isCurrentUserAllowed(SecurityConstants.READ)) {
      return results;
    }
    init();

    // entry ids already seen (mapped to the source name)
    final Map<String, String> seen = new HashMap<String, String>();
    if (fulltext == null) {
      fulltext = Collections.emptySet();
    }
    Set<String> readOnlyEntries = new HashSet<String>();

    for (SourceInfo sourceInfo : sourceInfos) {
      // accumulated map for each entry
      final Map<String, Map<String, Object>> maps = new HashMap<String, Map<String, Object>>();
      // number of dirs seen for each entry
      final Map<String, Integer> counts = new HashMap<String, Integer>();

      // list of optional dirs where filter matches default values
      List<SubDirectoryInfo> optionalDirsMatching = new ArrayList<SubDirectoryInfo>();
      for (SubDirectoryInfo dirInfo : sourceInfo.subDirectoryInfos) {
        // compute filter
        final Map<String, Serializable> dirFilter = new HashMap<String, Serializable>();
        for (Entry<String, Serializable> e : filter.entrySet()) {
          final String fieldName = dirInfo.fromSource.get(e.getKey());
          if (fieldName == null) {
            continue;
          }
          dirFilter.put(fieldName, e.getValue());
        }
        if (dirInfo.isOptional) {
          // check if filter matches directory default values
          boolean matches = true;
          for (Map.Entry<String, Serializable> dirFilterEntry : dirFilter.entrySet()) {
            Object defaultValue = dirInfo.defaultEntry.get(dirFilterEntry.getKey());
            Object filterValue = dirFilterEntry.getValue();
            if (defaultValue == null && filterValue != null) {
              matches = false;
            } else if (defaultValue != null && !defaultValue.equals(filterValue)) {
              matches = false;
            }
          }
          if (matches) {
            optionalDirsMatching.add(dirInfo);
          }
        }
        // compute fulltext
        Set<String> dirFulltext = new HashSet<String>();
        for (String sourceFieldName : fulltext) {
          final String fieldName = dirInfo.fromSource.get(sourceFieldName);
          if (fieldName != null) {
            dirFulltext.add(fieldName);
          }
        }
        // make query to subdirectory
        DocumentModelList l =
            dirInfo.getSession().query(dirFilter, dirFulltext, null, fetchReferences);
        for (DocumentModel entry : l) {
          final String id = entry.getId();
          Map<String, Object> map = maps.get(id);
          if (map == null) {
            map = new HashMap<String, Object>();
            maps.put(id, map);
            counts.put(id, 1);
          } else {
            counts.put(id, counts.get(id) + 1);
          }
          for (Entry<String, String> e : dirInfo.toSource.entrySet()) {
            map.put(e.getValue(), entry.getProperty(dirInfo.dirSchemaName, e.getKey()));
          }
          if (BaseSession.isReadOnlyEntry(entry)) {
            readOnlyEntries.add(id);
          }
        }
      }
      // add default entry values for optional dirs
      for (SubDirectoryInfo dirInfo : optionalDirsMatching) {
        // add entry for every data found in other dirs
        Set<String> existingIds =
            new HashSet<String>(
                dirInfo
                    .getSession()
                    .getProjection(Collections.<String, Serializable>emptyMap(), dirInfo.idField));
        for (Entry<String, Map<String, Object>> result : maps.entrySet()) {
          final String id = result.getKey();
          if (!existingIds.contains(id)) {
            counts.put(id, counts.get(id) + 1);
            final Map<String, Object> map = result.getValue();
            for (Entry<String, String> e : dirInfo.toSource.entrySet()) {
              String value = e.getValue();
              if (!map.containsKey(value)) {
                map.put(value, dirInfo.defaultEntry.get(e.getKey()));
              }
            }
          }
        }
      }
      // intersection, ignore entries not in all subdirectories
      final int numdirs = sourceInfo.subDirectoryInfos.size();
      for (Iterator<String> it = maps.keySet().iterator(); it.hasNext(); ) {
        final String id = it.next();
        if (counts.get(id) != numdirs) {
          it.remove();
        }
      }
      // now create entries
      ((ArrayList<?>) results).ensureCapacity(results.size() + maps.size());
      for (Entry<String, Map<String, Object>> e : maps.entrySet()) {
        final String id = e.getKey();
        if (seen.containsKey(id)) {
          log.warn(
              String.format(
                  "Entry '%s' is present in source '%s' but also in source '%s'. "
                      + "The second one will be ignored.",
                  id, seen.get(id), sourceInfo.source.name));
          continue;
        }
        final Map<String, Object> map = e.getValue();
        seen.put(id, sourceInfo.source.name);
        final DocumentModel entry =
            BaseSession.createEntryModel(null, schemaName, id, map, readOnlyEntries.contains(id));
        results.add(entry);
      }
    }
    if (orderBy != null && !orderBy.isEmpty()) {
      directory.orderEntries(results, orderBy);
    }
    return results;
  }
  @Override
  @SuppressWarnings("boxing")
  public DocumentModelList getEntries() {
    if (!isCurrentUserAllowed(SecurityConstants.READ)) {
      return null;
    }
    init();

    // list of entries
    final DocumentModelList results = new DocumentModelListImpl();
    // entry ids already seen (mapped to the source name)
    final Map<String, String> seen = new HashMap<String, String>();
    Set<String> readOnlyEntries = new HashSet<String>();

    for (SourceInfo sourceInfo : sourceInfos) {
      // accumulated map for each entry
      final Map<String, Map<String, Object>> maps = new HashMap<String, Map<String, Object>>();
      // number of dirs seen for each entry
      final Map<String, Integer> counts = new HashMap<String, Integer>();
      for (SubDirectoryInfo dirInfo : sourceInfo.requiredSubDirectoryInfos) {
        final DocumentModelList entries = dirInfo.getSession().getEntries();
        for (DocumentModel entry : entries) {
          final String id = entry.getId();
          // find or create map for this entry
          Map<String, Object> map = maps.get(id);
          if (map == null) {
            map = new HashMap<String, Object>();
            maps.put(id, map);
            counts.put(id, 1);
          } else {
            counts.put(id, counts.get(id) + 1);
          }
          // put entry data in map
          for (Entry<String, String> e : dirInfo.toSource.entrySet()) {
            map.put(e.getValue(), entry.getProperty(dirInfo.dirSchemaName, e.getKey()));
          }
          if (BaseSession.isReadOnlyEntry(entry)) {
            readOnlyEntries.add(id);
          }
        }
      }
      for (SubDirectoryInfo dirInfo : sourceInfo.optionalSubDirectoryInfos) {
        final DocumentModelList entries = dirInfo.getSession().getEntries();
        Set<String> existingIds = new HashSet<String>();
        for (DocumentModel entry : entries) {
          final String id = entry.getId();
          final Map<String, Object> map = maps.get(id);
          if (map != null) {
            existingIds.add(id);
            // put entry data in map
            for (Entry<String, String> e : dirInfo.toSource.entrySet()) {
              map.put(e.getValue(), entry.getProperty(dirInfo.dirSchemaName, e.getKey()));
            }
          } else {
            log.warn(
                String.format(
                    "Entry '%s' for source '%s' is present in optional directory '%s' "
                        + "but not in any required one. "
                        + "It will be skipped.",
                    id, sourceInfo.source.name, dirInfo.dirName));
          }
        }
        for (Entry<String, Map<String, Object>> mapEntry : maps.entrySet()) {
          if (!existingIds.contains(mapEntry.getKey())) {
            final Map<String, Object> map = mapEntry.getValue();
            // put entry data in map
            for (Entry<String, String> e : dirInfo.toSource.entrySet()) {
              // fill with default values for this directory
              if (!map.containsKey(e.getValue())) {
                map.put(e.getValue(), dirInfo.defaultEntry.get(e.getKey()));
              }
            }
          }
        }
      }
      // now create entries for all full maps
      int numdirs = sourceInfo.requiredSubDirectoryInfos.size();
      ((ArrayList<?>) results).ensureCapacity(results.size() + maps.size());
      for (Entry<String, Map<String, Object>> e : maps.entrySet()) {
        final String id = e.getKey();
        if (seen.containsKey(id)) {
          log.warn(
              String.format(
                  "Entry '%s' is present in source '%s' but also in source '%s'. "
                      + "The second one will be ignored.",
                  id, seen.get(id), sourceInfo.source.name));
          continue;
        }
        final Map<String, Object> map = e.getValue();
        if (counts.get(id) != numdirs) {
          log.warn(
              String.format(
                  "Entry '%s' for source '%s' is not present in all directories. "
                      + "It will be skipped.",
                  id, sourceInfo.source.name));
          continue;
        }
        seen.put(id, sourceInfo.source.name);
        final DocumentModel entry =
            BaseSession.createEntryModel(null, schemaName, id, map, readOnlyEntries.contains(id));
        results.add(entry);
      }
    }
    return results;
  }
  @Test
  public void testWriteOperations() throws Exception {

    // ------------------------------------------------------
    // Check #createFolder
    // ------------------------------------------------------
    // Not allowed to create a folder in a non FolderItem
    try {
      fileSystemItemManagerService.createFolder(
          DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId(), "A new folder", principal);
      fail("Folder creation in a non folder item should fail.");
    } catch (NuxeoException e) {
      assertEquals(
          String.format(
              "Cannot create a folder in file system item with id %s because it is not a folder but is: "
                  + "DocumentBackedFileItem(id=\"%s\", name=\"Joe.odt\")",
              DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId(),
              DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId()),
          e.getMessage());
    }

    // Folder creation
    FolderItem newFolderItem =
        fileSystemItemManagerService.createFolder(
            DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId(), "A new folder", principal);
    assertNotNull(newFolderItem);
    assertEquals(DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId(), newFolderItem.getParentId());
    assertEquals("A new folder", newFolderItem.getName());
    DocumentModelList folderChildren =
        session.query(
            String.format(
                "select * from Document where ecm:parentId = '%s' and ecm:primaryType = 'Folder' order by dc:title asc",
                folder.getId()));
    DocumentModel newFolder = folderChildren.get(0);
    assertTrue(newFolder.isFolder());
    assertEquals("A new folder", newFolder.getTitle());

    // Parent folder children check
    assertEquals(
        6,
        fileSystemItemManagerService
            .getChildren(DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId(), principal)
            .size());

    // ------------------------------------------------------
    // Check #createFile
    // ------------------------------------------------------
    // File creation
    Blob blob = new StringBlob("Content of a new file.");
    blob.setFilename("New file.odt");
    blob.setMimeType("application/vnd.oasis.opendocument.text");
    FileItem fileItem =
        fileSystemItemManagerService.createFile(newFolderItem.getId(), blob, principal);
    assertNotNull(fileItem);
    assertEquals(newFolderItem.getId(), fileItem.getParentId());
    assertEquals("New file.odt", fileItem.getName());
    folderChildren =
        session.query(
            String.format("select * from Document where ecm:parentId = '%s'", newFolder.getId()));
    assertEquals(1, folderChildren.size());
    DocumentModel newFile = folderChildren.get(0);
    assertEquals("File", newFile.getType());
    assertEquals("New file.odt", newFile.getTitle());
    assertEquals("/syncRoot1/aFolder/A new folder/New file.odt", newFile.getPathAsString());
    Blob newFileBlob = (Blob) newFile.getPropertyValue("file:content");
    assertEquals("New file.odt", newFileBlob.getFilename());
    assertEquals("Content of a new file.", newFileBlob.getString());
    assertEquals(
        "nxfile/test/" + newFile.getId() + "/blobholder:0/New%20file.odt",
        fileItem.getDownloadURL());
    assertEquals("MD5", fileItem.getDigestAlgorithm());
    assertEquals(newFileBlob.getDigest(), fileItem.getDigest());

    // Parent folder children check
    assertEquals(
        1, fileSystemItemManagerService.getChildren(newFolderItem.getId(), principal).size());

    // ------------------------------------------------------
    // Check #updateFile
    // ------------------------------------------------------
    String fileItemId = fileItem.getId();
    String fileItemParentId = fileItem.getParentId();
    blob = new StringBlob("Modified content of an existing file.");
    fileItem = fileSystemItemManagerService.updateFile(fileItemId, blob, principal);
    assertNotNull(fileItem);
    assertEquals(fileItemId, fileItem.getId());
    assertEquals(fileItemParentId, fileItem.getParentId());
    assertEquals("New file.odt", fileItem.getName());
    folderChildren =
        session.query(
            String.format("select * from Document where ecm:parentId = '%s'", newFolder.getId()));
    assertEquals(1, folderChildren.size());
    DocumentModel updatedFile = folderChildren.get(0);
    assertEquals("File", updatedFile.getType());
    assertEquals("New file.odt", updatedFile.getTitle());
    assertEquals("/syncRoot1/aFolder/A new folder/New file.odt", updatedFile.getPathAsString());
    Blob updatedFileBlob = (Blob) updatedFile.getPropertyValue("file:content");
    assertEquals("New file.odt", updatedFileBlob.getFilename());
    assertEquals("Modified content of an existing file.", updatedFileBlob.getString());
    assertEquals(
        "nxfile/test/" + updatedFile.getId() + "/blobholder:0/New%20file.odt",
        fileItem.getDownloadURL());
    assertEquals("MD5", fileItem.getDigestAlgorithm());
    assertEquals(updatedFileBlob.getDigest(), fileItem.getDigest());

    // ------------------------------------------------------
    // Check #delete
    // ------------------------------------------------------
    // File deletion
    fileSystemItemManagerService.delete(
        DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + updatedFile.getId(), principal);
    updatedFile = session.getDocument(new IdRef(updatedFile.getId()));
    assertEquals("deleted", updatedFile.getCurrentLifeCycleState());

    // Parent folder children check
    assertTrue(
        fileSystemItemManagerService.getChildren(newFolderItem.getId(), principal).isEmpty());

    // ------------------------------------------------------
    // Check #rename
    // ------------------------------------------------------
    // Folder rename
    String fsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId();
    FileSystemItem fsItem =
        fileSystemItemManagerService.rename(fsItemId, "Jack's folder has a new name", principal);
    assertEquals(fsItemId, fsItem.getId());
    String expectedSyncRoot1Id = DEFAULT_SYNC_ROOT_ITEM_ID_PREFIX + syncRoot1.getId();
    assertEquals(expectedSyncRoot1Id, fsItem.getParentId());
    assertEquals("Jack's folder has a new name", fsItem.getName());
    folder = session.getDocument(folder.getRef());
    assertEquals("Jack's folder has a new name", folder.getTitle());

    // File rename with title != filename
    // => should rename filename but not title
    assertEquals("aFile", file.getTitle());
    assertEquals("Joe.odt", ((Blob) file.getPropertyValue("file:content")).getFilename());
    fsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId();
    fsItem = fileSystemItemManagerService.rename(fsItemId, "File new name.odt", principal);
    assertEquals(fsItemId, fsItem.getId());
    assertEquals(DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + folder.getId(), fsItem.getParentId());
    assertEquals("File new name.odt", fsItem.getName());
    file = session.getDocument(file.getRef());
    assertEquals("aFile", file.getTitle());
    Blob fileBlob = (Blob) file.getPropertyValue("file:content");
    assertEquals("File new name.odt", fileBlob.getFilename());
    fileItem = (FileItem) fsItem;
    assertEquals(
        "nxfile/test/" + file.getId() + "/blobholder:0/File%20new%20name.odt",
        fileItem.getDownloadURL());
    assertEquals("MD5", fileItem.getDigestAlgorithm());
    assertEquals(fileBlob.getDigest(), fileItem.getDigest());

    // File rename with title == filename
    // => should rename filename and title
    blob = new StringBlob("File for a doc with title == filename.");
    blob.setFilename("Title-filename equality.odt");
    blob.setMimeType("application/vnd.oasis.opendocument.text");
    fileItem = fileSystemItemManagerService.createFile(newFolderItem.getId(), blob, principal);
    // Note that the PathSegmentService truncates doc title at 24 characters
    newFile =
        session.getDocument(
            new PathRef("/syncRoot1/aFolder/A new folder/Title-filename equality."));
    assertEquals("Title-filename equality.odt", newFile.getTitle());
    assertEquals(
        "Title-filename equality.odt",
        ((Blob) newFile.getPropertyValue("file:content")).getFilename());
    fileItem =
        (FileItem)
            fileSystemItemManagerService.rename(
                DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + newFile.getId(),
                "Renamed title-filename equality.odt",
                principal);
    assertEquals("Renamed title-filename equality.odt", fileItem.getName());
    newFile = session.getDocument(newFile.getRef());
    assertEquals("Renamed title-filename equality.odt", newFile.getTitle());
    newFileBlob = (Blob) newFile.getPropertyValue("file:content");
    assertEquals("Renamed title-filename equality.odt", newFileBlob.getFilename());
    assertEquals(
        "nxfile/test/" + newFile.getId() + "/blobholder:0/Renamed%20title-filename%20equality.odt",
        fileItem.getDownloadURL());
    assertEquals("MD5", fileItem.getDigestAlgorithm());
    assertEquals(newFileBlob.getDigest(), fileItem.getDigest());

    // ------------------------------------------------------
    // Check #move
    // ------------------------------------------------------
    // Not allowed to move a file system item to a non FolderItem
    String srcFsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + note.getId();
    String destFsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId();
    try {
      fileSystemItemManagerService.move(srcFsItemId, destFsItemId, principal);
      fail("Move to a non folder item should fail.");
    } catch (NuxeoException e) {
      assertEquals(
          String.format(
              "Cannot move a file system item to file system item with id %s because it is not a folder.",
              DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + file.getId()),
          e.getMessage());
    }

    // Move to a FolderItem
    destFsItemId = DEFAULT_FILE_SYSTEM_ITEM_ID_PREFIX + subFolder.getId();
    FileSystemItem movedFsItem =
        fileSystemItemManagerService.move(srcFsItemId, destFsItemId, principal);
    assertEquals(srcFsItemId, movedFsItem.getId());
    assertEquals(destFsItemId, movedFsItem.getParentId());
    assertEquals("aNote.txt", movedFsItem.getName());
    note = session.getDocument(note.getRef());
    assertEquals("/syncRoot1/aFolder/aSubFolder/aNote", note.getPathAsString());
    assertEquals("aNote", note.getTitle());
  }
  @Test
  public void documentManagementInTestCasesExample() throws ClientException {
    SchemaManager typeService = Framework.getLocalService(SchemaManager.class);

    DocumentType[] types = typeService.getDocumentTypes();
    for (DocumentType type : types) {
      System.out.println(type.getName());
    }

    DocumentModel mydoc = session.createDocumentModel("File");
    // DocumentModel mydoc = session.createDocumentModel("/", "toto",
    // "File");

    mydoc.setPathInfo("/", "toto");
    mydoc.setPropertyValue("dc:title", "Toto");
    mydoc = session.createDocument(mydoc);
    session.save();

    DocumentModelList docs = session.query("SELECT * FROM Document WHERE dc:title = 'Toto'");
    assertEquals(1, docs.size());
    mydoc = docs.get(0);
    assertEquals("toto", mydoc.getName());
    assertEquals("project", mydoc.getCurrentLifeCycleState());

    for (String state : mydoc.getAllowedStateTransitions()) {
      System.out.println("Transition : " + state);
    }

    // session.followTransition(mydoc.getRef(), "approve");
    mydoc.followTransition("approve");

    mydoc.setPropertyValue("dc:description", "My Description");
    mydoc = session.saveDocument(mydoc);
    session.save();

    assertEquals("approved", mydoc.getCurrentLifeCycleState());
    assertEquals("0.0", mydoc.getVersionLabel());
    assertEquals(0, session.getVersions(mydoc.getRef()).size());

    session.checkIn(mydoc.getRef(), VersioningOption.MINOR, "");
    mydoc = session.getDocument(mydoc.getRef());
    assertEquals("0.1", mydoc.getVersionLabel());
    assertEquals(1, session.getVersions(mydoc.getRef()).size());

    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder.setPropertyValue("dc:title", "Folder");
    folder = session.createDocument(folder);
    session.save();

    assertEquals(0, session.getChildren(folder.getRef()).size());
    session.publishDocument(mydoc, folder);
    assertEquals(1, session.getChildren(folder.getRef()).size());

    DocumentModel folder2 = session.createDocumentModel("/", "folder2", "Folder");
    folder2.setPropertyValue("dc:title", "Folder2");
    folder2 = session.createDocument(folder2);
    session.save();

    DocumentModel proxy = session.createProxy(mydoc.getRef(), folder2.getRef());

    assertEquals("Toto", proxy.getPropertyValue("dc:title"));
    mydoc.setPropertyValue("dc:title", "Tutu");
    session.saveDocument(mydoc);
    session.save();

    proxy = session.getDocument(proxy.getRef());
    assertEquals("Tutu", proxy.getPropertyValue("dc:title"));

    proxy.setPropertyValue("dc:title", "Tata");
    session.saveDocument(proxy);
    session.save();

    mydoc = session.getDocument(mydoc.getRef());
    assertEquals("Tata", mydoc.getPropertyValue("dc:title"));
  }
Example #28
0
  @Test
  public void shouldFilterTreeOnSecurity() throws Exception {

    buildAndIndexTree();

    DocumentModelList docs = ess.query(new NxQueryBuilder(session).nxql("select * from Document"));
    Assert.assertEquals(10, docs.totalSize());

    // check for user with no rights
    startTransaction();
    CoreSession restrictedSession = getRestrictedSession("toto");
    try {
      docs = ess.query(new NxQueryBuilder(restrictedSession).nxql("select * from Document"));
      Assert.assertEquals(0, docs.totalSize());

      // add READ rights and check that user now has access

      DocumentRef ref = new PathRef("/folder0/folder1/folder2");
      ACP acp = new ACPImpl();
      ACL acl = ACPImpl.newACL(ACL.LOCAL_ACL);
      acl.add(new ACE("toto", SecurityConstants.READ, true));
      acp.addACL(acl);
      session.setACP(ref, acp, true);

      TransactionHelper.commitOrRollbackTransaction();
      waitForCompletion();
      if (syncMode) {
        // in sync we split recursive update into 2 commands:
        // 1 sync non recurse + 1 async recursive
        assertNumberOfCommandProcessed(9);
      } else {
        assertNumberOfCommandProcessed(8);
      }

      startTransaction();
      docs = ess.query(new NxQueryBuilder(restrictedSession).nxql("select * from Document"));
      Assert.assertEquals(8, docs.totalSize());

      // block rights and check that blocking is taken into account

      ref = new PathRef("/folder0/folder1/folder2/folder3/folder4/folder5");
      acp = new ACPImpl();
      acl = ACPImpl.newACL(ACL.LOCAL_ACL);

      acl.add(new ACE(SecurityConstants.EVERYONE, SecurityConstants.EVERYTHING, false));
      acl.add(new ACE("Administrator", SecurityConstants.EVERYTHING, true));
      acp.addACL(acl);

      session.setACP(ref, acp, true);

      session.save();
      TransactionHelper.commitOrRollbackTransaction();
      waitForCompletion();
      if (syncMode) {
        assertNumberOfCommandProcessed(6);
      } else {
        assertNumberOfCommandProcessed(5);
      }
      startTransaction();
      docs = ess.query(new NxQueryBuilder(restrictedSession).nxql("select * from Document"));
      Assert.assertEquals(3, docs.totalSize());
    } finally {
      restrictedSession.close();
    }
  }
  @Test
  public void testReadAclAfterCreate() {
    DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
    folder = session.createDocument(folder);
    session.save();

    // folder can be seen by a member
    UserPrincipal joeMember =
        new UserPrincipal("joe", Arrays.asList("Everyone", "members"), false, false);
    try (CoreSession joeSession = openSessionAs(joeMember)) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
      assertEquals(folder.getId(), list.get(0).getId());
    }

    // but not as a non-member
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(0, list.size());
    }

    // set ACL on folder
    ACL acl = new ACLImpl();
    acl.add(new ACE("Everyone", "Read", true));
    ACP acp = new ACPImpl();
    acp.addACL(acl);
    folder.setACP(acp, true);
    session.save();

    // the folder can be seen by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM Folder");
      assertEquals(1, list.size());
      assertEquals(folder.getId(), list.get(0).getId());
    }

    // create a doc under the folder
    DocumentModel doc = new DocumentModelImpl("/folder", "doc", "File");
    doc = session.createDocument(doc);
    session.save();

    // the doc can be seen by joe
    try (CoreSession joeSession = openSessionAs("joe")) {
      DocumentModelList list = joeSession.query("SELECT * FROM File");
      assertEquals(1, list.size());
      assertEquals(doc.getId(), list.get(0).getId());
    }
  }
  @Test
  public void testReadAclSecurity() {
    // Check that all permissions that contain Browse enable to list a
    // document using aclOptimization
    SecurityService securityService = NXCore.getSecurityService();
    String[] browsePermissions = securityService.getPermissionsToCheck(BROWSE);
    // Check for test permission contribution
    assertTrue(Arrays.asList(browsePermissions).contains("ViewTest"));
    List<String> docNames = new ArrayList<String>(browsePermissions.length);
    DocumentModel root = session.getRootDocument();
    for (String permission : browsePermissions) {
      // Create a folder with only the browse permission
      String name = "joe-has-" + permission + "-permission";
      docNames.add(name);
      DocumentModel folder = new DocumentModelImpl(root.getPathAsString(), name, "Folder");
      folder = session.createDocument(folder);
      ACP acp = folder.getACP();
      assertNotNull(acp); // the acp inherited from root is returned
      acp = new ACPImpl();
      ACL acl = new ACLImpl();
      acl.add(new ACE("joe", permission, true));
      acp.addACL(acl);
      folder.setACP(acp, true);
    }
    session.save();
    CoreSession joeSession = openSessionAs("joe");
    try {
      DocumentModelList list;
      list = joeSession.query("SELECT * FROM Folder");
      List<String> names = new ArrayList<String>();
      for (DocumentModel doc : list) {
        names.add(doc.getName());
      }
      assertEquals(
          "Expecting " + docNames + " got " + names, browsePermissions.length, list.size());

      list = joeSession.query("SELECT * FROM Folder WHERE ecm:isProxy = 0");
      names.clear();
      for (DocumentModel doc : list) {
        names.add(doc.getName());
      }
      assertEquals(
          "Expecting " + docNames + " got " + names, browsePermissions.length, list.size());

      // Add a new folder to update the read acls
      DocumentModel folder = new DocumentModelImpl(root.getPathAsString(), "new-folder", "Folder");
      folder = session.createDocument(folder);
      ACP acp = folder.getACP();
      assertNotNull(acp); // the acp inherited from root is returned
      acp = new ACPImpl();
      ACL acl = new ACLImpl();
      acl.add(new ACE("joe", browsePermissions[0], true));
      acl.add(new ACE("bob", browsePermissions[0], true));
      acp.addACL(acl);
      folder.setACP(acp, true);
      session.save();

      list = joeSession.query("SELECT * FROM Folder");
      assertEquals(browsePermissions.length + 1, list.size());

    } finally {
      closeSession(joeSession);
    }
  }