RM-7051 resolving conflict

This commit is contained in:
Ross Gale
2019-11-25 08:31:09 +00:00
161 changed files with 5414 additions and 870 deletions

73
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,73 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at katalin.zanaty@alfresco.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org

140
README.md Normal file
View File

@@ -0,0 +1,140 @@
# Records Management: README
## Contributing
Please refer to our [How to contribute](/CONTRIBUTING.md) guide and our [Contributor Covenant Code of Conduct](/CODE_OF_CONDUCT.md).
## Configuring and starting Alfresco/Share
* Clone the project (e.g. `git clone git@gitlab.alfresco.com:records-management/records-management.git`)
* Import the project as a maven project
* Start the Alfresco/Share instances with the following commands:
```
mvn clean install -Pstart-repo
mvn clean install -Pstart-share
```
(these commands work best if run from the specific directories, e.g. start Share from
rm-community/rm-community-share/ or rm-enterprise/rm-enterprise-share/ )
## Configuring a different DB other than H2 (e.g. MySQL or PostgreSQL)
* Create a file called _local.properties_ under src/main/resources in alfresco-rm-enterprise-repo
* Add the following properties in this new file
```
my.db.name -> The name of the database schema
my.db.port -> The port number for your database (default port number for postgres is 5432 and for mysql it is 3306)
```
* Run the following commands to start your Alfresco instance:
to start Alfresco (using Postgres):
```
mvn clean install -Pstart-repo,use-postgres
```
to start Alfresco (using MySQL):
```
mvn clean install -Pstart-repo,use-mysql
```
## Technical documentation
Technical documentation is available at [rm-community/documentation/README.md](/rm-community/documentation/README.md) and [rm-enterprise/documentation/README.md](/rm-enterprise/documentation/README.md). This should be particularly useful for anyone wanting to integrate with or extend RM.
## Running integration test
In order to execute the integration tests run the following command (unit tests will be executed every time before you start Alfresco/Share):
```
mvn clean install -Dskip.integrationtests=false
```
## Running UI Automation tests
To run the automated UI tests, change to the rm-automation directory and run:
```
mvn clean install -Dskip.automationtests=false
```
Note: due to Selenium Firefox driver changes, the highest supported Firefox version for UI tests is 43.0.4 (with Selenium 2.52.0).
It is possible to have multiple versions of Firefox installed onto your workstation (e.g. one for running the UI tests and the other, kept
up to date, for everyday browsing) but beware Firefox auto-updates. In this scenario the best approach is to create a non-default profile
(default profiles will be shared between your Firefox installations!) for which auto-updates are disabled and forcing the use of this
profile in your tests (`-Dwebdriver.firefox.profile="ProfileName"`). If your Firefox 43 install isn't in your path, you can use the
`-Dwebdriver.firefox.profile` option set to the full path of its "firefox-bin" executable.
MacOS X Sierra users: if you experience by order of magnitude slower performance when connected to a WiFi network (e.g. office WiFi)
add your workstation to your local /etc/hosts file as described on https://github.com/SeleniumHQ/selenium/issues/2824.
To use Chrome instead of Firefox:
1. copy webdriver.properties from https://github.com/AlfrescoTestAutomation/selenium-grid/tree/master/src/main/resources
2. put it under src/test/resource in rm-automation-ui project
3. download the chrome driver from http://chromedriver.storage.googleapis.com and extract it
4. change the following properties in webdriver.properties: webdriver.browser (Chrome) and webdriver.chrome.server.path (path/to/chrome/driver)
5. run the tests as usual
## Updating License Headers
In order to refesh out of date license source headers run the following command:
```
mvn clean install -Dlicense.update.dryrun=false
```
## Running tests against latest Aikau snapshot
The latest Aikau snapshot can be pulled by running the following command in rm-community:
```
mvn clean install -DskipTests -Dalfresco.aikau.version=LATEST -U
```
Thereafter start the Share instance and run automation tests as described above.
## Configuring Outlook Integration
To download and run RM with the Outlook Integration AMPs installed on the repo and Share use the following commands:
```
mvn clean install -Pstart-repo,outlook-integration
mvn clean install -Pstart-share,outlook-integration
```
Follow these instructions to install licence and Outlook plugin:
* http://docs.alfresco.com/outlook2.1/tasks/Outlook-license.html
* http://docs.alfresco.com/outlook2.1/tasks/Outlook-install_v2.html
## SNAPSHOT dependencies
If you're building Enterprise RM, the base project (Community) is pulled in via a snapshot dependency configured in maven.
This dependency will either be loaded from your local .m2 cache, or from Nexus if the version in your .m2 doesn't exist or is old
('old' in maven terms is anything over 24 hours old). If maven fetches community dependencies from Nexus, then it's unlikely to contain your changes.
You want to always use the version in your local cache - this means either doing a daily build at the root project level
that pushes a new copy of the correct version into your cache, or alternatively you could run mvn with the
`--no-snapshot-dependency` (or `-nsu`) option, which won't try to download a newer version.
## Code Formatting
This project follows the usual Alfresco Coding Standards. If you use Eclipse or IntelliJ, there are settings inside the ide-config directory for you to import.
## Surf build errors
If you get:
```
[ERROR] Failed to execute goal on project alfresco-rm-community-share: Could not resolve dependencies for project org.alfresco:alfresco-rm-community-share:amp:2.6-SNAPSHOT: Failed to collect dependencies at org.alfresco.surf:spring-surf-api:jar:6.3 -> org.alfresco.surf:spring-surf:jar:${dependency.surf.version}: Failed to read artifact descriptor for org.alfresco.surf:spring-surf:jar:${dependency.surf.version}: Could not transfer artifact org.alfresco.surf:spring-surf:pom:${dependency.surf.version} from/to alfresco-internal (https://artifacts.alfresco.com/nexus/content/groups/private): Not authorized , ReasonPhrase:Unauthorized. -> [Help 1]
```
then please re-run with `-Ddependency.surf.version=6.3`
## Install lombok plugin for IDEs
To allow automation and benchmark projects to be built within an IDE the lombok 'plugin' needs to be installed.
Execute lombok.jar (doubleclick it, or run `java -jar lombok.jar`). Follow the instructions.
## Use Solr 6 with Alfresco 5.2.x
In alfresco-global.properties (depending on the RM edition `/records-management/rm-community/rm-community-repo/src/test/properties/local` or `/records-management/rm-enterprise/rm-enterprise-repo/src/test/properties/local`)
change the value for "index.subsystem.name" from "solr4" to "solr6".
Add also the following property "solr.port=8983".
Download the latest Alfresco Search Services from
[https://nexus.alfresco.com/nexus/#nexus-search;gav\~\~alfresco-search-services\~\~\~](https://nexus.alfresco.com/nexus/#nexus-search;gav~~alfresco-search-services~~~)
Currently it's 1.0.0 (alfresco-search-services-1.0.0.zip)
Unzip it and change to the "solr" folder within it. Start the Solr server using the following command:
```
solr start -a "-Dcreate.alfresco.defaults=alfresco,archive"
```
Start your repository

View File

@@ -1,155 +0,0 @@
Configuring and starting Alfresco/Share:
----------------------------------------
- Clone the project (e.g. git clone git@gitlab.alfresco.com:records-management/records-management.git)
- Import the project as a maven project
- Start the Alfresco/Share instances with the following commands:
mvn clean install -Pstart-repo
mvn clean install -Pstart-share
(these commands work best if run from the specific directories, e.g. start share from
rm-enterprise/rm-enterprise-share/ or rm-community/rm-community-share/ )
Configuring a different DB other than H2 (e.g. MySQL or PostgreSQL):
--------------------------------------------------------------------
- Create a file called "local.properties" under src/main/resources in alfresco-rm-enterprise-repo
- Add the following properties in this new file
my.db.name -> The name of the database schema
my.db.port -> The port number for your database (default port number for postgres is 5432 and for mysql it is 3306)
- Run the following commands to start your Alfresco instance:
to start Alfresco (using Postgres):
mvn clean install -Pstart-repo,use-postgres
to start Alfresco (using MySQL):
mvn clean install -Pstart-repo,use-mysql
Technical documentation:
------------------------
Technical documentation is available at rm-community/documentation/README.md and rm-enterprise/documentation/README.md.
This should be particularly useful for anyone wanting to integrate with or extend RM.
Running integration test:
-------------------------
In order to execute the integration tests run the following command (unit tests will be executed every time before you start Alfresco/Share):
mvn clean install -Dskip.integrationtests=false
Running UI Automation tests:
----------------------------
To run the automated UI tests, change to the rm-automation directory and run:
mvn clean install -Dskip.automationtests=false
Note: due to Selenium Firefox driver changes, the highest supported Firefox version for UI tests is 43.0.4 (with Selenium 2.52.0).
It is possible to have multiple versions of Firefox installed onto your workstation (e.g. one for running the UI tests and the other, kept
up to date, for everyday browsing) but beware Firefox auto-updates. In this scenario the best approach is to create a non-default profile
(default profiles will be shared between your Firefox installations!) for which auto-updates are disabled and forcing the use of this
profile in your tests (-Dwebdriver.firefox.profile="ProfileName"). If your Firefox 43 install isn't in your path, you can use the
-Dwebdriver.firefox.profile option set to the full path of its "firefox-bin" executable.
MacOS X Sierra users: if you experience by order of magnitude slower performance when connected to a WiFi network (e.g. office WiFi)
add your workstation to your local /etc/hosts file as described on https://github.com/SeleniumHQ/selenium/issues/2824.
To use Chrome instead of Firefox:
- copy webdriver.properties from https://github.com/AlfrescoTestAutomation/selenium-grid/tree/master/src/main/resources
- put it under src/test/resource in rm-automation-ui project
- download the chrome driver from http://chromedriver.storage.googleapis.com/ and extract it
- change the following properties in webdriver.properties: webdriver.browser (Chrome) and webdriver.chrome.server.path (path/to/chrome/driver)
- run the tests as usual
Updating License Headers:
-------------------------
In order to refesh out of date license source headers run the following command:
mvn clean install -Dlicense.update.dryrun=false
Running tests against latest Aikau snapshot:
--------------------------------------------
The latest Aikau snapshot can be pulled by running the following command in rm-community:
mvn clean install -DskipTests -Dalfresco.aikau.version=LATEST -U
Thereafter start the Share instance and run automation tests as described above.
Configuring Outlook Integration:
-------------------------------
To download and run RM with the Outlook Integration AMPs installed on the repo and Share use the following commands:
mvn clean install -Pstart-repo,outlook-integration
mvn clean install -Pstart-share,outlook-integration
Follow these instructions install licence and Outlook plugin:
- http://docs.alfresco.com/outlook2.1/tasks/Outlook-license.html
- http://docs.alfresco.com/outlook2.1/tasks/Outlook-install_v2.html
SNAPSHOT dependencies:
----------------------
If you're building Enterprise RM, the base project (Community) is pulled in via a snapshot dependency configured in maven.
This dependency will either be loaded from your local .m2 cache or from Nexus if the version in your .m2 doesn't exist or is old
(Old in maven terms is anything over 24hrs old). If maven fetches it from Nexus, your code it's unlikely to be the correct version.
You want to always use the version in your local cache - this means either doing a daily build at the root project level
that pushes a new copy of the correct version into your cache, or alternatively you could run mvn with the
--no-snapshot-dependency (or -nsu) option, which won't try to download a newer version.
Code Formatting:
----------------
This project follows the usual Alfresco Coding Standards. If you use Eclipse or IntelliJ, there are settings inside the ide-config directory for you to import.
Surf build errors:
------------------
If you get:
[ERROR] Failed to execute goal on project alfresco-rm-community-share: Could not resolve dependencies for project org.alfresco:alfresco-rm-community-share:amp:2.6-SNAPSHOT: Failed to collect dependencies at org.alfresco.surf:spring-surf-api:jar:6.3 -> org.alfresco.surf:spring-surf:jar:${dependency.surf.version}: Failed to read artifact descriptor for org.alfresco.surf:spring-surf:jar:${dependency.surf.version}: Could not transfer artifact org.alfresco.surf:spring-surf:pom:${dependency.surf.version} from/to alfresco-internal (https://artifacts.alfresco.com/nexus/content/groups/private): Not authorized , ReasonPhrase:Unauthorized. -> [Help 1]
then please re-run with -Ddependency.surf.version=6.3
Install lombok plugin for IDEs:
-------------------------------
To allow automation and benchmark projects to be built within an IDE the lombok 'plugin' needs to be installed.
Execute lombok.jar (doubleclick it, or run java -jar lombok.jar). Follow instructions.
Use Solr 6 with Alfresco 5.2.x:
-------------------------------
In alfresco-global.properties (depending on the RM edition /records-management/rm-community/rm-community-repo/src/test/properties/local or /records-management/rm-enterprise/rm-enterprise-repo/src/test/properties/local)
change the value for "index.subsystem.name" from "solr4" to "solr6".
Add also the following property "solr.port=8983".
Download the latest Alfresco Search Services from
https://nexus.alfresco.com/nexus/#nexus-search;gav~~alfresco-search-services~~~
Currently it's 1.0.0 (alfresco-search-services-1.0.0.zip)
Unzip it and change to the "solr" folder within it. Start the Solr server using the following command:
solr start -a "-Dcreate.alfresco.defaults=alfresco,archive"
Start your repository

View File

@@ -4,7 +4,7 @@
<groupId>org.alfresco</groupId>
<artifactId>alfresco-rm</artifactId>
<packaging>pom</packaging>
<version>2.6.3-SNAPSHOT</version>
<version>2.7.3-SNAPSHOT</version>
<name>Alfresco Records Management</name>
<parent>
@@ -24,7 +24,7 @@
<connection>scm:git:https://git.alfresco.com/records-management/records-management.git</connection>
<developerConnection>scm:git:https://git.alfresco.com/records-management/records-management.git</developerConnection>
<url>https://git.alfresco.com/records-management/records-management</url>
<tag>HEAD</tag>
<tag>HEAD</tag>
</scm>
<issueManagement>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-rm</artifactId>
<version>2.6.3-SNAPSHOT</version>
<version>2.7.3-SNAPSHOT</version>
</parent>
<licenses>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-rm-automation</artifactId>
<version>2.6.3-SNAPSHOT</version>
<version>2.7.3-SNAPSHOT</version>
</parent>
<properties>

View File

@@ -121,6 +121,37 @@ public abstract class BaseAPI
return results;
}
/**
* Helper method to extract the property value for the given nodeRef and property name
*
* @param result
* @param nodeRef
* @param propertyName
* @return
*/
protected String getPropertyValue(JSONObject result, String nodeRef, String propertyName)
{
String propertyValue = "";
try
{
JSONArray items = result.getJSONArray("items");
for (int i = 0; i < items.length(); i++)
{
JSONObject item = items.getJSONObject(i);
if(nodeRef.equals(item.getString("nodeRef")))
{
propertyValue = item.getJSONObject("properties").getString(propertyName);
}
}
}
catch (JSONException error)
{
throw new RuntimeException("Unable to parse result", error);
}
return propertyValue;
}
/**
* Helper method to extract property values from request result and put them in map as a list that corresponds to a unique property value.
*
@@ -310,6 +341,78 @@ public abstract class BaseAPI
}
}
/**
* Helper method for PUT requests
*
* @param adminUser user with administrative privileges
* @param adminPassword password for adminUser
* @param expectedStatusCode The expected return status code.
* @param requestParams zero or more endpoint specific request parameters
* @param urlTemplate request URL template
* @param urlTemplateParams zero or more parameters used with <i>urlTemplate</i>
*/
protected HttpResponse doPutJsonRequest(String adminUser,
String adminPassword,
int expectedStatusCode,
JSONObject requestParams,
String urlTemplate,
String... urlTemplateParams)
{
AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject();
return doPutJsonRequest(adminUser, adminPassword, expectedStatusCode, client.getApiUrl(), requestParams, urlTemplate, urlTemplateParams);
}
/**
* Helper method for PUT requests
*
* @param adminUser user with administrative privileges
* @param adminPassword password for adminUser
* @param expectedStatusCode The expected return status code.
* @param urlStart the start of the URL (for example "alfresco/s/slingshot").
* @param requestParams zero or more endpoint specific request parameters
* @param urlTemplate request URL template
* @param urlTemplateParams zero or more parameters used with <i>urlTemplate</i>
* @throws AssertionError if the returned status code is not as expected.
*/
private HttpResponse doPutJsonRequest(String adminUser,
String adminPassword,
int expectedStatusCode,
String urlStart,
JSONObject requestParams,
String urlTemplate,
String... urlTemplateParams)
{
String requestUrl = formatRequestUrl(urlStart, urlTemplate, urlTemplateParams);
try
{
HttpResponse httpResponse = doRequestJson(HttpPut.class, requestUrl, adminUser, adminPassword, requestParams);
assertEquals("PUT request to " + requestUrl + " was not successful.", expectedStatusCode, httpResponse.getStatusLine().getStatusCode());
return httpResponse;
}
catch (InstantiationException | IllegalAccessException error)
{
throw new IllegalArgumentException("doPutRequest failed", error);
}
}
/**
* Fill in the parameters for a URL template.
*
* @param urlStart The start of the URL.
* @param urlTemplate The template.
* @param urlTemplateParams Any parameters that need to be filled into the URL template.
* @return The resultant URL.
*/
private String formatRequestUrl(String urlStart, String urlTemplate, String[] urlTemplateParams)
{
if (urlTemplateParams.length == 1)
{
// The format method needs some help to know not to use the whole array object.
return MessageFormat.format(urlTemplate, urlStart, urlTemplateParams[0]);
}
return MessageFormat.format(urlTemplate, urlStart, urlTemplateParams);
}
/**
* Helper method for POST requests
* @param adminUser user with administrative privileges
@@ -403,15 +506,12 @@ public abstract class BaseAPI
String urlTemplate,
String... urlTemplateParams)
{
// Ensure the host is part of the request URL.
String requestUrl = MessageFormat.format(
urlTemplate,
urlStart,
urlTemplateParams);
String requestUrl;
requestUrl = formatRequestUrl(urlStart, urlTemplate, urlTemplateParams);
try
{
HttpResponse httpResponse = doRequestJson(HttpPost.class, requestUrl, adminUser, adminPassword, requestParams);
assertEquals("POST request to " + requestUrl + " was not successful.", httpResponse.getStatusLine().getStatusCode(), expectedStatusCode);
assertEquals("POST request to " + requestUrl + " was not successful.", expectedStatusCode, httpResponse.getStatusLine().getStatusCode());
return httpResponse;
}
catch (InstantiationException | IllegalAccessException error)
@@ -453,7 +553,10 @@ public abstract class BaseAPI
{
((HttpEntityEnclosingRequestBase) request).setEntity(new StringEntity(requestParams.toString()));
}
LOGGER.info("Sending {} request to {}", requestType.getSimpleName(), requestUrl);
LOGGER.info("Request body: {}", requestParams);
response = client.execute(adminUser, adminPassword, request);
LOGGER.info("Response: {}", response.getStatusLine());
try
{
@@ -573,6 +676,9 @@ public abstract class BaseAPI
SHELF,
BOX,
FILE,
ORIGINATOR,
ORIGINATING_ORGANIZATION,
PUBLICATION_DATE
}
public enum RETENTION_SCHEDULE
@@ -587,7 +693,7 @@ public abstract class BaseAPI
RETENTION_GHOST,
RETENTION_ELIGIBLE_FIRST_EVENT,
RETENTION_EVENTS,
COMBINE_DISPOSITION_STEP_CONDITIONS
}
/**
@@ -599,6 +705,8 @@ public abstract class BaseAPI
CUT_OFF("cutoff"),
UNDO_CUT_OFF("undoCutoff"),
TRANSFER("transfer"),
COMPLETE_EVENT("completeEvent"),
UNDO_EVENT("undoEvent"),
DESTROY("destroy");
String action;

View File

@@ -0,0 +1,49 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.core.v0;
public enum RMEvents
{
ABOLISHED("abolished"),
ALL_ALLOWANCES_GRANTED_ARE_TERMINATED("all_allowances_granted_are_terminated"),
CASE_CLOSED("case_closed"),
DECLASSIFICATION_REVIEW("declassification_review"),
OBSOLETE("obsolete"),
NO_LONGER_NEEDED("no_longer_needed"),
STUDY_COMPLETE("study_complete");
private String eventName;
RMEvents(String eventName)
{
this.eventName = eventName;
}
public String getEventName()
{
return eventName;
}
}

View File

@@ -0,0 +1,89 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.model.audit;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.utility.model.TestModel;
/**
* POJO for audit entry
*
* @author Rodica Sutu
* @since 2.7
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties (ignoreUnknown = true)
public class AuditEntry extends TestModel
{
@JsonProperty (required = true)
private String nodeName;
@JsonProperty (required = true)
private List<Object> changedValues;
@JsonProperty (required = true)
private String identifier;
@JsonProperty (required = true)
private String path;
@JsonProperty (required = true)
private String nodeRef;
@JsonProperty (required = true)
private String fullName;
@JsonProperty
private String createPerson;
@JsonProperty (required = true)
private String userName;
@JsonProperty (required = true)
private String userRole;
@JsonProperty (required = true)
private String nodeType;
@JsonProperty (required = true)
private String event;
@JsonProperty (required = true)
private String timestamp;
}

View File

@@ -0,0 +1,57 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.model.audit;
/**
* Enumerates the list of events audited
*
* @author Rodica Sutu
* @since 2.7
*
*/
public enum AuditEvents
{
CREATE_PERSON("Create Person", "Create User"),
DELETE_PERSON("Delete Person", "Delete User"),
CREATE_USER_GROUP("Create User Group", "Create User Group"),
DELETE_USER_GROUP("Delete User Group", "Delete User Group"),
ADD_TO_USER_GROUP("Add To User Group", "Add To User Group"),
REMOVE_FROM_USER_GROUP("Remove From User Group", "Remove From User Group"),
LOGIN_UNSUCCESSFUL("Login.Failure", "Login Unsuccessful");
/** event audited */
public final String event;
/** display name for the event audited */
public final String eventDisplayName;
AuditEvents(String event, String displayName)
{
this.event = event;
this.eventDisplayName = displayName;
}
}

View File

@@ -58,6 +58,8 @@ public class FilePlanComponentFields
public static final String PROPERTIES_RECORD_SEARCH_DISPOSITION_ACTION_NAME = "rma:recordSearchDispositionActionName";
public static final String PROPERTIES_RECORD_SEARCH_DISPOSITION_EVENTS_ELIGIBLE = "rma:recordSearchDispositionEventsEligible";
public static final String PROPERTIES_RECORD_SEARCH_DISPOSITION_INSTRUCTIONS = "rma:recordSearchDispositionInstructions";
public static final String PROPERTIES_DECLASSIFICATION_REVIEW_COMPLETED_BY = "rma:declassificationReviewCompletedBy";
public static final String PROPERTIES_DECLASSIFICATION_REVIEW_COMPLETED_AT = "rma:declassificationReviewCompletedAt";
/** File plan properties */
@@ -74,7 +76,9 @@ public class FilePlanComponentFields
public static final String PROPERTIES_RECORD_SEARCH_VITAL_RECORD_REVIEW_PERIOD = "rma:recordSearchVitalRecordReviewPeriod";
public static final String PROPERTIES_RECORD_SEARCH_VITAL_RECORD_REVIEW_PERIOD_EXPRESSION = "rma:recordSearchVitalRecordReviewPeriodExpression";
/** Record properties */
/**
* Record properties
*/
public static final String PROPERTIES_CLASSIFICATION = "sc:classification";
public static final String PROPERTIES_DATE_FILED = "rma:dateFiled";
public static final String PROPERTIES_ORIGINAL_NAME = "rma:origionalName";

View File

@@ -42,7 +42,6 @@ import lombok.NoArgsConstructor;
* @author Rodica Sutu
* @since 2.6
*/
@Builder
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@@ -51,4 +50,13 @@ public class RMSite extends RestSiteModel
{
@JsonProperty (required = true)
private RMSiteCompliance compliance;
/** Private constructor allowing Lombok to include superclass fields in the builder. */
@Builder
private RMSite(String title, String description, RMSiteCompliance compliance)
{
this.setTitle(title);
this.setDescription(description);
this.compliance = compliance;
}
}

View File

@@ -0,0 +1,42 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.model.user;
/**
* Constants for RM user capabilities
*
* @author Rodica Sutu
* @since 2.7
*/
public class UserCapabilities
{
/** The id of the view records capability. */
public static final String VIEW_RECORDS_CAP = "ViewRecords";
/** The id of the declare records capability. */
public static final String DECLARE_RECORDS_CAP = "DeclareRecords";
}

View File

@@ -24,19 +24,32 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.model.user;
/**
* Constants for RM user roles
*
*
* @author Kristijan Conkas
* @since 2.6
*/
public class UserRoles
public enum UserRoles
{
public static final String ROLE_RM_ADMIN = "Administrator";
public static final String ROLE_RM_MANAGER = "RecordsManager";
public static final String ROLE_RM_POWER_USER = "PowerUser";
public static final String ROLE_RM_SECURITY_OFFICER = "SecurityOfficer";
public static final String ROLE_RM_USER = "User";
IN_PLACE_WRITERS("ExtendedWriters", "In-Place Writers"),
ROLE_RM_ADMIN("Administrator", "Records Management Administrator"),
ROLE_RM_MANAGER("RecordsManager", "Records Management Manager"),
ROLE_RM_POWER_USER("PowerUser", "Records Management Power User"),
ROLE_RM_SECURITY_OFFICER("SecurityOfficer", "Records Management Security Officer"),
ROLE_RM_USER("User", "Records Management User");
public final String roleId;
public final String displayName;
UserRoles(String roleId, String displayName)
{
this.roleId = roleId;
this.displayName = displayName;
}
}

View File

@@ -28,9 +28,18 @@ package org.alfresco.rest.rm.community.util;
import static org.alfresco.rest.rm.community.util.ParameterCheck.mandatoryObject;
import java.io.IOException;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility class for creating the json object
@@ -40,6 +49,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
*/
public class PojoUtility
{
/**
* Logger for the class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(PojoUtility.class);
/**
* see {@link #toJson(Object, Class, Class)}
*/
@@ -85,4 +99,64 @@ public class PojoUtility
return error.toString();
}
}
/**
* Converting json to java object
*
* @param json The json object to convert
* @param classz Class for the java object
* @return The converted java object
* @throws JsonProcessingException Throws exceptions if the given object doesn't match to the POJO class model
*/
public static <T> T jsonToObject(JSONObject json, Class<T> classz)
{
mandatoryObject("model", classz);
mandatoryObject("jsonObject", json);
ObjectMapper mapper = new ObjectMapper();
T obj = null;
try
{
obj = mapper.readValue(json.toString(), classz);
}
catch (IOException e)
{
LOGGER.error("Unable to convert the json into a java object.", e.toString());
}
return obj;
}
/**
* Converting json array into a list of java objects
*
* @param json The json array to convert
* @param classz Class for the java object
* @return The list of converted java objects
* @throws JsonProcessingException Throws exceptions if the given object doesn't match to the POJO class model
*/
public static <T> List<T> jsonToObject(JSONArray json, Class<T> classz)
{
mandatoryObject("model", classz);
mandatoryObject("jsonObject", json);
ObjectMapper mapper = new ObjectMapper();
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, classz);
List<T> asList = null;
try
{
asList = mapper.readValue(json.toString(), collectionType);
}
catch (IOException e)
{
LOGGER.error("Unable to convert the json array into a java collection.", e.toString());
}
return asList;
}
}

View File

@@ -0,0 +1,74 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.v0;
import java.text.MessageFormat;
import org.alfresco.dataprep.AlfrescoHttpClient;
import org.alfresco.dataprep.AlfrescoHttpClientFactory;
import org.alfresco.rest.core.v0.BaseAPI;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* The v0 REST API for nodes
*
* @author jcule
* @since 2.7EA1
*/
@Component
public class NodeAPI extends BaseAPI
{
/** Logger for the class. */
private static final Logger LOGGER = LoggerFactory.getLogger(NodeAPI.class);
/** The URI for the get node API. */
private static final String GET_NODE_API = "{0}alfresco/s/slingshot/doclib2/node/{1}";
@Autowired
private AlfrescoHttpClientFactory alfrescoHttpClientFactory;
/**
* Get the node metadata using the using the node data webscript: Document List v2 Component
*
* @param username
* @param password
* @param nodeId
* @return
*/
public JSONObject getNode(String username, String password, String nodeId)
{
String requestURL;
AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject();
requestURL = MessageFormat.format(GET_NODE_API, client.getAlfrescoUrl(), NODE_PREFIX + nodeId);
client.close();
return doGetRequest(username, password, requestURL);
}
}

View File

@@ -0,0 +1,104 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.v0;
import static org.testng.Assert.assertTrue;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.List;
import org.alfresco.rest.core.v0.BaseAPI;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
import org.alfresco.rest.rm.community.util.PojoUtility;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* The v0 REST API for rm audit logs
*
* @author Rodica Sutu
* @since 2.7
*/
@Component
public class RMAuditAPI extends BaseAPI
{
/** Logger for the class. */
private static final Logger LOGGER = LoggerFactory.getLogger(RMAuditAPI.class);
/** The URI for the audit API. */
private static final String RM_AUDIT_API = "{0}rma/admin/rmauditlog";
private static final String RM_AUDIT_LOG_API = RM_AUDIT_API + "?{1}";
/**
* Returns a list of rm audit entries .
*
* @param user The username of the user to use.
* @param password The password of the user.
* @param size Maximum number of log entries to return
* @param event The name of audit event to be retrieved
* @return return Only return log entries matching this event
*/
public List<AuditEntry> getRMAuditLog(String user, String password, final int size, final String event)
{
String parameters = null;
try
{
parameters = "size=" + size + (event != null ? "&event=" + URLEncoder.encode(event, "UTF-8"):"");
}
catch (UnsupportedEncodingException e)
{
LOGGER.error("Unable to encode the event name" + e.getMessage());
}
JSONArray auditEntries = doGetRequest(user, password,
MessageFormat.format(RM_AUDIT_LOG_API,"{0}", parameters)).getJSONObject("data").getJSONArray("entries");
return PojoUtility.jsonToObject(auditEntries, AuditEntry.class);
}
/**
* Clear the list of audit entries.
*
* @param username The username of the user to use.
* @param password The password of the user.
* @throws AssertionError If the API call didn't clear the audit log.
*/
public void clearAuditLog(String username, String password)
{
JSONObject deleteStatus = doDeleteRequest(username, password, RM_AUDIT_API);
assertTrue(deleteStatus != null
//audit clear and login events are returned
&& getRMAuditLog(username, password, 100, null).size() == 2);
}
}

View File

@@ -35,16 +35,19 @@ import static org.testng.AssertJUnit.fail;
import java.io.IOException;
import java.text.MessageFormat;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import org.alfresco.dataprep.AlfrescoHttpClient;
import org.alfresco.dataprep.AlfrescoHttpClientFactory;
import org.alfresco.dataprep.ContentService;
import org.alfresco.dataprep.UserService;
import org.alfresco.rest.core.v0.BaseAPI;
import org.alfresco.rest.core.v0.RMEvents;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpResponse;
@@ -70,6 +73,10 @@ import org.springframework.stereotype.Component;
@Component
public class RMRolesAndActionsAPI extends BaseAPI
{
/** The URI to view the configured roles and capabilities. */
private static final String RM_ROLES = "{0}rma/admin/rmroles";
/** The URI for REST requests about a particular configured role. */
private static final String RM_ROLES_ROLE = RM_ROLES + "/{1}";
private static final String RM_ROLES_AUTHORITIES = "{0}rm/roles/{1}/authorities/{2}?alf_ticket={3}";
// logger
@@ -88,6 +95,89 @@ public class RMRolesAndActionsAPI extends BaseAPI
@Autowired
private ContentService contentService;
/**
* Get all the configured RM roles.
*
* @param adminUser The RM admin user.
* @param adminPassword The password of the user.
* @return The RM roles in the system (Note that this will be the internal names, not the display labels).
*/
public Set<String> getConfiguredRoles(String adminUser, String adminPassword)
{
// Using "is=true" includes the in-place readers and writers.
JSONObject jsonObject = doGetRequest(adminUser, adminPassword, RM_ROLES + "?is=true").getJSONObject("data");
return jsonObject.toMap().keySet();
}
/**
* Get the capabilities for a given role.
*
* @param adminUser The RM admin user.
* @param adminPassword The password of the user.
* @param role The role to get capabilities for.
* @return The set of system names for the capabilities.
*/
public Set<String> getCapabilitiesForRole(String adminUser, String adminPassword, String role)
{
JSONObject jsonObject = doGetRequest(adminUser, adminPassword, RM_ROLES + "?is=true").getJSONObject("data");
assertTrue("Could not find role '" + role + "' in " + jsonObject.keySet(), jsonObject.has(role));
return jsonObject.getJSONObject(role).getJSONObject("capabilities").keySet();
}
/**
* Create a new RM role.
*
* @param adminUser The username of the admin user.
* @param adminPassword The password for the admin user.
* @param roleName The name of the new role.
* @param roleDisplayLabel A human-readable label for the role.
* @param capabilities A list of capabilities for the role.
*/
public void createRole(String adminUser, String adminPassword, String roleName, String roleDisplayLabel, Set<String> capabilities)
{
JSONObject requestBody = new JSONObject();
requestBody.put("name", roleName);
requestBody.put("displayLabel", roleDisplayLabel);
JSONArray capabilitiesArray = new JSONArray();
capabilities.forEach(capabilitiesArray::put);
requestBody.put("capabilities", capabilitiesArray);
doPostJsonRequest(adminUser, adminPassword, HttpStatus.SC_OK, requestBody, RM_ROLES);
}
/**
* Update an existing RM role.
*
* @param adminUser The username of the admin user.
* @param adminPassword The password for the admin user.
* @param roleName The name of the new role.
* @param roleDisplayLabel A human-readable label for the role.
* @param capabilities A list of capabilities for the role.
*/
public void updateRole(String adminUser, String adminPassword, String roleName, String roleDisplayLabel, Set<String> capabilities)
{
JSONObject requestBody = new JSONObject();
requestBody.put("name", roleName);
requestBody.put("displayLabel", roleDisplayLabel);
JSONArray capabilitiesArray = new JSONArray();
capabilities.forEach(capabilitiesArray::put);
requestBody.put("capabilities", capabilitiesArray);
doPutJsonRequest(adminUser, adminPassword, HttpStatus.SC_OK, requestBody, RM_ROLES_ROLE, roleName);
}
/**
* Delete a created RM role.
*
* @param adminUser The username of the admin user.
* @param adminPassword The password for the admin user.
* @param roleName The name of the role to be deleted.
*/
public void deleteRole(String adminUser, String adminPassword, String roleName)
{
doDeleteRequest(adminUser, adminPassword, MessageFormat.format(RM_ROLES_ROLE, "{0}", roleName));
boolean success = !getConfiguredRoles(adminUser, adminPassword).contains(roleName);
assertTrue("Failed to delete role " + roleName + " with " + adminUser, success);
}
/**
* create user and assign to records management role
*/
@@ -237,9 +327,9 @@ public class RMRolesAndActionsAPI extends BaseAPI
/**
* Perform an action on the record folder
*
* @param user the user closing the folder
* @param user the user executing the action
* @param password the user's password
* @param contentName the record folder name
* @param contentName the content name
* @param date the date to be updated
* @return The HTTP response.
*/
@@ -261,6 +351,56 @@ public class RMRolesAndActionsAPI extends BaseAPI
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
}
/**
* Complete an event on the record/record folder
*
* @param user the user executing the action
* @param password the user's password
* @param nodeName the node name
* @param event the event to be completed
* @param date the date to be updated
* @return The HTTP response.
*/
public HttpResponse completeEvent(String user, String password, String nodeName, RMEvents event, Instant date)
{
String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, nodeName);
JSONObject requestParams = new JSONObject();
requestParams.put("name", RM_ACTIONS.COMPLETE_EVENT.getAction());
requestParams.put("nodeRef", recNodeRef);
date = (date != null) ? date : Instant.now();
String formattedDate = DateTimeFormatter.ISO_INSTANT.format(date);
requestParams.put("params", new JSONObject()
.put("eventName", event.getEventName())
.put("eventCompletedBy", user)
.put("eventCompletedAt", new JSONObject()
.put("iso8601", formattedDate)
)
);
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
}
/**
* Undo an event on the record/record folder
*
* @param user the user executing the action
* @param password the user's password
* @param contentName the content name
* @param event the event to be undone
* @return The HTTP response.
*/
public HttpResponse undoEvent(String user, String password, String contentName, RMEvents event)
{
String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName);
JSONObject requestParams = new JSONObject();
requestParams.put("name", RM_ACTIONS.UNDO_EVENT.getAction());
requestParams.put("nodeRef", recNodeRef);
requestParams.put("params", new JSONObject()
.put("eventName", event.getEventName()));
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
}
/**
* Deletes every item in the given container
*
@@ -345,6 +485,10 @@ public class RMRolesAndActionsAPI extends BaseAPI
addPropertyToRequest(requestParams, "prop_cm_title", properties, RMProperty.TITLE);
addPropertyToRequest(requestParams, "prop_cm_description", properties, RMProperty.DESCRIPTION);
addPropertyToRequest(requestParams, "prop_cm_author", properties, RMProperty.AUTHOR);
addPropertyToRequest(requestParams, "prop_dod_originator", properties, RMProperty.ORIGINATOR);
addPropertyToRequest(requestParams, "prop_dod_originatingOrganization", properties, RMProperty
.ORIGINATING_ORGANIZATION);
addPropertyToRequest(requestParams, "prop_dod_publicationDate", properties, RMProperty.PUBLICATION_DATE);
return doPostJsonRequest(username, password, SC_OK, requestParams, MessageFormat.format(UPDATE_METADATA_API, "{0}", itemNodeRef));
}

View File

@@ -130,6 +130,7 @@ public class RecordCategoriesAPI extends BaseAPI
{
requestParams.append("events", events);
}
addPropertyToRequest(requestParams, "combineDispositionStepConditions", properties, RETENTION_SCHEDULE.COMBINE_DISPOSITION_STEP_CONDITIONS);
addPropertyToRequest(requestParams, "eligibleOnFirstCompleteEvent", properties, RETENTION_SCHEDULE.RETENTION_ELIGIBLE_FIRST_EVENT);
return doPostJsonRequest(user, password, SC_OK, requestParams, MessageFormat.format(DISPOSITION_ACTIONS_API, "{0}", catNodeRef));

View File

@@ -36,6 +36,7 @@ import org.alfresco.dataprep.CMISUtil.DocumentType;
import org.alfresco.dataprep.ContentService;
import org.alfresco.rest.core.v0.BaseAPI;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.http.HttpResponse;
import org.json.JSONException;
import org.json.JSONObject;
@@ -44,8 +45,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javafx.util.Pair;
/**
* Methods to make API requests using v0 API on records
*
@@ -322,13 +321,13 @@ public class RecordsAPI extends BaseAPI
{
if (response.has("sharedId"))
{
return new Pair<>(true, response.getString("sharedId"));
return Pair.of(true, response.getString("sharedId"));
}
} catch (JSONException e)
{
LOGGER.info("Unable to extract response parameter", e);
}
return new Pair<>(false, String.valueOf(response.getJSONObject("status").getInt("code")));
return Pair.of(false, String.valueOf(response.getJSONObject("status").getInt("code")));
}
/**

View File

@@ -63,9 +63,9 @@ public class SearchAPI extends BaseAPI
/** RM search URL template */
private static final String RM_SEARCH_ENDPOINT = "{0}alfresco/s/slingshot/rmsearch/{1}?{2}";
/** RM document search filters */
private static final String RM_DEFAULT_RECORD_FILTERS =
"records/true,undeclared/true,vital/false,folders/false,categories/false,frozen/false,cutoff/false";
/** RM all nodes search filters */
private static final String RM_DEFAULT_NODES_FILTERS =
"records/true,undeclared/true,vital/false,folders/{0},categories/{1},frozen/false,cutoff/false";
/**
* Perform search request on search endpoint as a user.
@@ -91,6 +91,7 @@ public class SearchAPI extends BaseAPI
* @param site
* @param query
* @param filters
* @param sortby
* @return search results (see API reference for more details), null for any errors
*/
public JSONObject rmSearch(
@@ -98,11 +99,16 @@ public class SearchAPI extends BaseAPI
String password,
String site,
String query,
String filters)
String filters,
String sortby)
{
List<BasicNameValuePair> searchParameters = new ArrayList<BasicNameValuePair>();
searchParameters.add(new BasicNameValuePair("query", query));
searchParameters.add(new BasicNameValuePair("filters", filters));
if (sortby != null)
{
searchParameters.add(new BasicNameValuePair("sortby", sortby));
}
String requestURL = MessageFormat.format(
RM_SEARCH_ENDPOINT,
@@ -114,22 +120,45 @@ public class SearchAPI extends BaseAPI
}
/**
* Search as a user for records on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS
* Search as a user for nodes on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS and sorted
* by sortby
* <br>
* If more fine-grained control of search parameters is required, use rmSearch() directly.
*
* @param username
* @param password
* @param query
* @return list of record names
* @param sortby
* @return list of node names
*/
public List<String> searchForRecordsAsUser(
String username,
String password,
String query)
public List<String> searchForNodeNamesAsUser(String username, String password, String query, String sortby,
boolean includeCategories, boolean includeFolders)
{
return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_RECORD_FILTERS));
String searchFilterParamaters = MessageFormat.format(RM_DEFAULT_NODES_FILTERS, Boolean.toString(includeFolders),
Boolean.toString(includeCategories));
return getItemNames(rmSearch(username, password, "rm", query, searchFilterParamaters, sortby));
}
/**
* Search as a user for nodes on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS and sorted
* by sortby and returns the property value for the given nodeRef and property name
*
* @param username
* @param password
* @param query
* @param sortby
* @param includeCategories
* @param includeFolders
* @return list of node properties
*/
public String searchForNodePropertyAsUser(String username, String password, String nodeRef, String propertyName, String query, String sortby,
boolean includeCategories, boolean includeFolders)
{
String searchFilterParamaters = MessageFormat.format(RM_DEFAULT_NODES_FILTERS, Boolean.toString(includeFolders),
Boolean.toString(includeCategories));
return getItemProperty(rmSearch(username, password, "rm", query, searchFilterParamaters, sortby), nodeRef, propertyName);
}
/**
* Generic faceted search.
* @param username
@@ -199,12 +228,35 @@ public class SearchAPI extends BaseAPI
/**
* Helper method to extract list of names from search result.
*
* @param searchResult
* @return list of document or record names in search result
* @throws FileNotFoundException
* @throws JsonSyntaxException
* @throws JsonIOException
* @throws RuntimeException for malformed search response
*/
/**
* Helper method to extract list of names from search result.
*
* @param searchResult
* @param getProperties
* @return
*/
private List<String> getItemNames(JSONObject searchResult)
{
return getPropertyValues(searchResult, "name");
}
/**
* Helper method to extract list of property values from search result for the given nodeRef.
*
* @param searchResult
* @param getProperties
* @return
*/
private String getItemProperty(JSONObject searchResult, String nodeRef, String propertyName)
{
return getPropertyValue(searchResult, nodeRef, propertyName);
}
}

View File

@@ -116,6 +116,34 @@ public class DispositionScheduleService extends BaseAPI
dataUser.getAdminUser().getPassword(), categoryName, cutOffStep);
}
/**
* Helper method for adding an accession step
*
* @param timeOrEvent
* @param events
* @param period
* @param periodProperty
* @param combineConditions
* @return
*/
public void addAccessionStep(String categoryName, Boolean timeOrEvent, String events, String period, String
periodProperty, Boolean combineConditions)
{
HashMap<RETENTION_SCHEDULE, String> accessionStep = new HashMap<>();
accessionStep.put(RETENTION_SCHEDULE.NAME, "accession");
accessionStep.put(RETENTION_SCHEDULE.COMBINE_DISPOSITION_STEP_CONDITIONS, Boolean.toString(combineConditions));
accessionStep.put(RETENTION_SCHEDULE.RETENTION_PERIOD, period);
accessionStep.put(RETENTION_SCHEDULE.RETENTION_PERIOD_PROPERTY, periodProperty);
if (!timeOrEvent)
{
accessionStep.put(RETENTION_SCHEDULE.RETENTION_ELIGIBLE_FIRST_EVENT, Boolean.toString(timeOrEvent));
}
accessionStep.put(RETENTION_SCHEDULE.RETENTION_EVENTS, events);
accessionStep.put(RETENTION_SCHEDULE.DESCRIPTION,
"Accession step with time and event conditions.");
recordCategoriesAPI.addDispositionScheduleSteps(dataUser.getAdminUser().getUsername(),
dataUser.getAdminUser().getPassword(), categoryName, accessionStep);
}
/**
* Helper method to create retention schedule with general fields for the given category as admin

View File

@@ -0,0 +1,84 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.v0.service;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.utility.data.DataUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Produces processed results from roles API calls
*
* @author Rodica Sutu
* @since 2.6
*/
@Service
public class RoleService
{
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired
private DataUser dataUser;
/**
* Add capabilities to a role
*
* @param role role to be updated
* @param capabilities list of capabilities to be added
*/
public void addCapabilitiesToRole(UserRoles role, Set<String> capabilities)
{
Set<String> roleCapabilities = new HashSet<>();
roleCapabilities.addAll(rmRolesAndActionsAPI.getCapabilitiesForRole(dataUser.getAdminUser().getUsername(),
dataUser.getAdminUser().getPassword(), role.roleId));
capabilities.stream().forEach(cap -> roleCapabilities.add(cap));
rmRolesAndActionsAPI.updateRole(dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword(),
role.roleId, role.displayName, roleCapabilities);
}
/**
* Remove capabilities from a role
*
* @param role role to be updated
* @param capabilities list of capabilities to be removed
*/
public void removeCapabilitiesFromRole(UserRoles role, Set<String> capabilities)
{
Set<String> roleCapabilities = rmRolesAndActionsAPI.getCapabilitiesForRole(dataUser.getAdminUser().getUsername(),
dataUser.getAdminUser().getPassword(), role.roleId);
roleCapabilities.removeAll(capabilities);
rmRolesAndActionsAPI.updateRole(dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword(),
role.roleId, role.displayName, roleCapabilities);
}
}

View File

@@ -0,0 +1,174 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.audit;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.ADD_TO_USER_GROUP;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.CREATE_USER_GROUP;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.DELETE_USER_GROUP;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.REMOVE_FROM_USER_GROUP;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.testng.AssertJUnit.assertTrue;
import java.util.List;
import com.google.common.collect.ImmutableMap;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
import org.alfresco.rest.v0.RMAuditAPI;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.model.GroupModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* This class contains the tests that check the group events are audited
*
* @author Claudia Agache
* @since 2.7
*/
@AlfrescoTest (jira = "RM-5236")
public class AuditGroupEventsTests extends BaseRMRestTest
{
@Autowired
private RMAuditAPI rmAuditAPI;
private GroupModel testGroup;
private UserModel testUser;
@BeforeClass (alwaysRun = true)
public void cleanAuditLogs()
{
//clean audit logs
rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword());
}
/**
* Given I have created a new group
* When I view the RM audit
* Then there is an entry showing that I created a group
*/
@Test
public void createGroupEventIsAudited()
{
testGroup = dataGroup.createRandomGroup();
STEP("Get the list of audit entries for the create group event.");
List<AuditEntry> auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(),
getAdminUser().getPassword(), 100, CREATE_USER_GROUP.event);
STEP("Check the audit log contains only the entries for the created group.");
assertTrue("The list of events is not filtered by " + CREATE_USER_GROUP.event,
auditEntries.stream().allMatch(auditEntry -> auditEntry.getEvent().equals(CREATE_USER_GROUP.eventDisplayName)));
assertTrue("The group name for the new group created is not audited.",
auditEntries.stream().filter(auditEntry -> auditEntry.getEvent().equals(CREATE_USER_GROUP.eventDisplayName))
.anyMatch(auditEntry -> auditEntry.getNodeName().equals(testGroup.getGroupIdentifier())));
}
/**
* Given I have added a user to a group
* When I view the RM audit
* Then there is an entry showing that I have added a user to a group
*/
@Test
public void addUserToGroupEventIsAudited()
{
testGroup = dataGroup.createRandomGroup();
testUser = getDataUser().createRandomTestUser();
dataGroup.usingUser(testUser).addUserToGroup(testGroup);
STEP("Get the list of audit entries for the add user to group event.");
List<AuditEntry> auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(),
getAdminUser().getPassword(), 100, ADD_TO_USER_GROUP.event);
STEP("Check the audit log contains only the entries for the add user to group event.");
assertTrue("The list of events is not filtered by " + ADD_TO_USER_GROUP.event,
auditEntries.stream().allMatch(auditEntry -> auditEntry.getEvent().equals(ADD_TO_USER_GROUP.eventDisplayName)));
assertTrue("The username and destination group are not audited.",
auditEntries.stream().filter(auditEntry -> auditEntry.getEvent().equals(ADD_TO_USER_GROUP.eventDisplayName))
.anyMatch(auditEntry -> auditEntry.getNodeName().equals(testGroup.getGroupIdentifier())
&& auditEntry.getChangedValues().contains(ImmutableMap.of("new", testUser.getUsername(), "previous", "", "name", "User Name"))
&& auditEntry.getChangedValues().contains(ImmutableMap.of("new", testGroup.getGroupIdentifier(), "previous", "", "name", "Parent Group"))));
}
/**
* Given I have removed a user from a group
* When I view the RM audit
* Then there is an entry showing that I have removed a user from a group
*/
@Test
public void removeUserFromGroupEventIsAudited()
{
testGroup = dataGroup.createRandomGroup();
testUser = getDataUser().createRandomTestUser();
dataGroup.usingUser(testUser).addUserToGroup(testGroup);
dataGroup.removeUserFromGroup(testGroup, testUser);
STEP("Get the list of audit entries for the add user to group event.");
List<AuditEntry> auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(),
getAdminUser().getPassword(), 100, REMOVE_FROM_USER_GROUP.event);
STEP("Check the audit log contains only the entries for the remove user from group event.");
assertTrue("The list of events is not filtered by " + REMOVE_FROM_USER_GROUP.event,
auditEntries.stream().allMatch(auditEntry -> auditEntry.getEvent().equals(REMOVE_FROM_USER_GROUP.eventDisplayName)));
assertTrue("The username and previous parent group are not audited.",
auditEntries.stream().filter(auditEntry -> auditEntry.getEvent().equals(REMOVE_FROM_USER_GROUP.eventDisplayName))
.anyMatch(auditEntry -> auditEntry.getNodeName().equals(testGroup.getGroupIdentifier())
&& auditEntry.getChangedValues().contains(ImmutableMap.of("new", "", "previous", testUser.getUsername(), "name", "User Name"))
&& auditEntry.getChangedValues().contains(ImmutableMap.of("new", "","previous", testGroup.getGroupIdentifier(), "name", "Parent Group"))));
}
/**
* Given I have deleted a group
* When I view the RM audit
* Then there is an entry showing that I have deleted a group
*/
@Test
public void deleteGroupEventIsAudited()
{
testGroup = dataGroup.createRandomGroup();
dataGroup.deleteGroup(testGroup);
STEP("Get the list of audit entries for the delete group event.");
List<AuditEntry> auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(),
getAdminUser().getPassword(), 100, DELETE_USER_GROUP.event);
STEP("Check the audit log contains only the entries for the created group.");
assertTrue("The list of events is not filtered by " + DELETE_USER_GROUP.event,
auditEntries.stream().allMatch(auditEntry -> auditEntry.getEvent().equals(DELETE_USER_GROUP.eventDisplayName)));
assertTrue("The group name for the deleted group is not audited.",
auditEntries.stream().filter(auditEntry -> auditEntry.getEvent().equals(DELETE_USER_GROUP.eventDisplayName))
.anyMatch(auditEntry -> auditEntry.getNodeName().equals(testGroup.getGroupIdentifier())
&& auditEntry.getChangedValues().contains(ImmutableMap.of("new", "", "previous", testGroup.getGroupIdentifier(), "name", "authorityDisplayName"))));
}
}

View File

@@ -0,0 +1,82 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.audit;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.LOGIN_UNSUCCESSFUL;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.testng.AssertJUnit.assertTrue;
import java.util.List;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
import org.alfresco.rest.v0.RMAuditAPI;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* This class contains the tests that check the login events are audited
*
* @author Claudia Agache
* @since 2.7
*/
@AlfrescoTest (jira = "RM-5234")
public class AuditLoginEvents extends BaseRMRestTest
{
@Autowired
private RMAuditAPI rmAuditAPI;
@BeforeClass (alwaysRun = true)
public void cleanAuditLogs()
{
//clean audit logs
rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword());
}
/**
* Given I have tried to login using invalid credentials
* When I view the RM audit filtered by Login unsuccessful event
* Then the audit log contains only the entries for the Login unsuccessful event
*/
@Test
public void filterByLoginUnsuccessful() throws Exception
{
restClient.authenticateUser(new UserModel(getAdminUser().getUsername(), "InvalidPassword"));
restClient.withCoreAPI().getSites();
STEP("Get the list of audit entries for the login unsuccessful event.");
List<AuditEntry> auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(),
getAdminUser().getPassword(), 100, LOGIN_UNSUCCESSFUL.event);
STEP("Check the audit log contains only the entries for the login unsuccessful event.");
assertTrue("The list of events is not filtered by " + LOGIN_UNSUCCESSFUL.event,
auditEntries.stream().allMatch(auditEntry -> auditEntry.getEvent().equals(LOGIN_UNSUCCESSFUL.eventDisplayName)));
}
}

View File

@@ -0,0 +1,101 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.audit;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.CREATE_PERSON;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.testng.AssertJUnit.assertTrue;
import java.util.List;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
import org.alfresco.rest.v0.RMAuditAPI;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* This class contains the tests that check the user events are audited
*
* @author Rodica Sutu
* @since 2.7
*/
public class AuditUserEventsTests extends BaseRMRestTest
{
private final String PREFIX = generateTestPrefix(AuditUserEventsTests.class);
private UserModel createUser;
@Autowired
private RMAuditAPI rmAuditAPI;
/**
* Given I have created a new user
* When I view the RM audit
* Then there is an entry showing that I created a user
*
* @throws Exception
*/
@Test
@AlfrescoTest(jira = "RM-6223")
public void createUserEventIsAudited() throws Exception
{
STEP("Create a new user.");
String userName = "auditCreateUser" + PREFIX;
createUser = getDataUser().createUser(userName);
STEP("Get the list of audit entries for the create person event.");
List<AuditEntry> auditEntries = rmAuditAPI.getRMAuditLog(getAdminUser().getUsername(),
getAdminUser().getPassword(), 100, CREATE_PERSON.event);
STEP("Check the audit log contains only the entries for the created user.");
assertTrue("The list of events is not filtered by " + CREATE_PERSON.event,
auditEntries.stream().allMatch(auditEntry -> auditEntry.getEvent().equals(CREATE_PERSON.eventDisplayName)));
assertTrue("The username value for the user created is not audited.",
auditEntries.stream().filter(auditEntry -> auditEntry.getEvent().equals(CREATE_PERSON.eventDisplayName))
.allMatch(auditEntry -> auditEntry.getNodeName().equals(userName)));
}
@BeforeClass (alwaysRun = true)
public void cleanAuditLogs()
{
//clean audit logs
rmAuditAPI.clearAuditLog(getAdminUser().getUsername(), getAdminUser().getPassword());
}
@AfterClass (alwaysRun = true)
public void cleanUp()
{
//delete the created user
getDataUser().deleteUser(createUser);
}
}

View File

@@ -65,6 +65,7 @@ import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolder;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolderProperties;
import org.alfresco.rest.rm.community.model.site.RMSite;
import org.alfresco.rest.rm.community.model.transfercontainer.TransferContainer;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainer;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChild;
@@ -76,6 +77,7 @@ import org.alfresco.rest.search.RestRequestQueryModel;
import org.alfresco.rest.search.SearchNodeModel;
import org.alfresco.rest.search.SearchRequest;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.SearchAPI;
import org.alfresco.utility.data.DataUser;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FolderModel;
@@ -112,7 +114,11 @@ public class BaseRMRestTest extends RestTest
@Autowired
@Getter(value = PROTECTED)
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired
@Getter(value = PROTECTED)
private SearchAPI searchApi;
/**
* Asserts the given status code
*
@@ -178,6 +184,21 @@ public class BaseRMRestTest extends RestTest
}
}
/**
* Helper method to delete the RM site if exists and to create a new one
*/
public void createRMSite(RMSite rmSiteModel) throws Exception
{
RMSiteAPI rmSiteAPI = getRestAPIFactory().getRMSiteAPI();
if (rmSiteAPI.existsRMSite())
{
rmSiteAPI.deleteRMSite();
}
rmSiteAPI.createRMSite(rmSiteModel);
assertStatusCode(CREATED);
}
/**
* Helper method to create root category as the admin user
*
@@ -489,7 +510,7 @@ public class BaseRMRestTest extends RestTest
{
return getFilePlanAsUser(getAdminUser(), componentId);
}
/**
* Recursively delete a folder
*
@@ -570,6 +591,17 @@ public class BaseRMRestTest extends RestTest
RecordFolderAPI recordFolderAPI = restAPIFactory.getRecordFolderAPI();
recordFolderAPI.deleteRecordFolder(recordFolderId);
}
/**
* Delete a record
*
* @param recordId the id of the record to delete
*/
public void deleteRecord(String recordId)
{
RecordsAPI recordsAPI = restAPIFactory.getRecordsAPI();
recordsAPI.deleteRecord(recordId);
}
/**
* Delete a record category
@@ -637,7 +669,8 @@ public class BaseRMRestTest extends RestTest
names.add(childNode.onModel().getName());
});
break;
} else
}
else
{
counter++;
}
@@ -647,6 +680,100 @@ public class BaseRMRestTest extends RestTest
return names;
}
/**
* Returns the list of node names returned by search results for the given search term
*
* @param user
* @param term
* @param sortby
* @param includeFolders
* @param includeCategories
* @param expectedResults
* @return List<String>
*/
public List<String> searchForRMContentAsUser(UserModel user, String term, String sortby, boolean includeFolders,
boolean includeCategories, List<String> expectedResults)
{
List<String> results = new ArrayList<>();
// wait for solr indexing
int counter = 0;
int waitInMilliSeconds = 6000;
while (counter < 3)
{
synchronized (this)
{
try
{
this.wait(waitInMilliSeconds);
}
catch (InterruptedException e)
{
}
}
results = searchApi.searchForNodeNamesAsUser(user.getUsername(), user.getPassword(), term, sortby,
includeFolders, includeCategories);
if (!results.isEmpty() && results.containsAll(expectedResults))
{
break;
}
else
{
counter++;
}
// double wait time to not overdo solr search
waitInMilliSeconds = (waitInMilliSeconds * 2);
}
return results;
}
/**
* Returns the property value for the given property name and nodeRef of the search results
*
* @param user
* @param term
* @param nodeRef
* @param propertyName
* @param sortby
* @param includeFolders
* @param includeCategories
* @param expectedResults
* @return String
*/
public String searchForRMContentAsUser(UserModel user, String term, String nodeRef, String propertyName,
String sortby, boolean includeFolders, boolean includeCategories, String expectedResults)
{
String result = "";
// wait for solr indexing
int counter = 0;
int waitInMilliSeconds = 6000;
while (counter < 3)
{
synchronized (this)
{
try
{
this.wait(waitInMilliSeconds);
}
catch (InterruptedException e)
{
}
}
result = searchApi.searchForNodePropertyAsUser(user.getUsername(), user.getPassword(), nodeRef,
propertyName, term, sortby, includeFolders, includeCategories);
if (!result.isEmpty() && result.contains(expectedResults))
{
break;
}
else
{
counter++;
}
// double wait time to not overdo solr search
waitInMilliSeconds = (waitInMilliSeconds * 2);
}
return result;
}
/**
* Helper method to return site document library content model
*
@@ -668,17 +795,4 @@ public class BaseRMRestTest extends RestTest
return documentLibrary;
}
/**
* Helper method to create a Content Model
*
* @return ContentModel
* @throws Exception
*/
public ContentModel toContentModel(String nodeId)
{
ContentModel node = new ContentModel();
node.setNodeRef(nodeId);
return node;
}
}

View File

@@ -26,8 +26,17 @@
*/
package org.alfresco.rest.rm.community.base;
import static com.google.common.collect.Sets.newHashSet;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_ADMIN;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_MANAGER;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_POWER_USER;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_SECURITY_OFFICER;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_USER;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import java.util.Set;
/**
* Test data used in tests
*
@@ -83,4 +92,9 @@ public interface TestData
public static String NONELECTRONIC_RECORD_NAME = "Record nonelectronic" + getRandomAlphanumeric();
public static final String ALFRESCO_ADMINISTRATORS = "ALFRESCO_ADMINISTRATORS";
/**
* The ids of the default RM roles.
*/
public static final Set<String> RM_ROLES = newHashSet(ROLE_RM_ADMIN.roleId, ROLE_RM_MANAGER.roleId,
ROLE_RM_POWER_USER.roleId, ROLE_RM_SECURITY_OFFICER.roleId, ROLE_RM_USER.roleId);
}

View File

@@ -488,7 +488,7 @@ public class FilePlanTests extends BaseRMRestTest
children.add(recordCategory);
}
getRestAPIFactory().getRMUserAPI().assignRoleToUser(managerUser.getUsername(), ROLE_RM_MANAGER);
getRestAPIFactory().getRMUserAPI().assignRoleToUser(managerUser.getUsername(), ROLE_RM_MANAGER.roleId);
// Get record category children from API
getRestAPIFactory().getFilePlansAPI(managerUser).getRootRecordCategories(FILE_PLAN_ALIAS)
.assertThat().entriesListIsEmpty().assertThat().paginationExist();

View File

@@ -28,6 +28,7 @@ package org.alfresco.rest.rm.community.files;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.NON_ELECTRONIC_RECORD_TYPE;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
@@ -45,6 +46,7 @@ import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.record.RecordProperties;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildEntry;
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledContainerAPI;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.FileModel;
@@ -54,6 +56,7 @@ import org.alfresco.utility.model.UserModel;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.SecondaryType;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -69,6 +72,9 @@ public class DeclareDocumentAsRecordTests extends BaseRMRestTest
private SiteModel testSite;
private FolderModel testFolder;
@Autowired
RecordsAPI recordsAPI;
@BeforeClass(alwaysRun=true)
public void declareDocumentAsRecordSetup() throws Exception
{
@@ -239,6 +245,27 @@ public class DeclareDocumentAsRecordTests extends BaseRMRestTest
assertStatusCode(UNPROCESSABLE_ENTITY);
}
/**
* Given a file that has version declared as record
* When the file is declared as record
* Then the action is successful
*/
@Test (description = "Declaring as record a file that already has its version declared as record is successful")
@AlfrescoTest (jira = "RM-6786")
public void declareAsRecordAFileWithARecordVersion() throws Exception
{
STEP("Create a file.");
FileModel testFile = dataContent.usingSite(testSite).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Declare file version as record and check that record is successfully created.");
recordsAPI.declareDocumentVersionAsRecord(getAdminUser().getUsername(), getAdminUser().getPassword(), testSite.getId(),
testFile.getName());
STEP("Declare file as record and check that record is successfully created.");
getRestAPIFactory().getFilesAPI().declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(CREATED);
}
// @Test(description = "Create 500 documents and declare them ass records concurently.")
// public void declare500DocumentsAsRecordsConcurrently() throws Exception
// {

View File

@@ -221,17 +221,6 @@ public class CompleteRecordTests extends BaseRMRestTest
}
}
/**
* Helper method to create an RM site and assert successful creation
*/
private void createRMSite(RMSite rmSiteModel) throws Exception
{
RMSiteAPI rmSiteAPI = getRestAPIFactory().getRMSiteAPI();
rmSiteAPI.deleteRMSite();
rmSiteAPI.createRMSite(rmSiteModel);
assertStatusCode(CREATED);
}
/**
* Helper method to create records and and assert successful creation
*/

View File

@@ -211,7 +211,7 @@ public class DeleteRecordTests extends BaseRMRestTest
getDataUser().addUserToSite(deleteUser, new SiteModel(getRestAPIFactory().getRMSiteAPI().getSite().getId()), SiteCollaborator);
// Add RM role to user
getRestAPIFactory().getRMUserAPI().assignRoleToUser(username, ROLE_RM_POWER_USER);
getRestAPIFactory().getRMUserAPI().assignRoleToUser(username, ROLE_RM_POWER_USER.roleId);
assertStatusCode(OK);
// Try to delete newRecord
@@ -242,7 +242,7 @@ public class DeleteRecordTests extends BaseRMRestTest
logger.info("Test user: " + username);
// Add RM role to user, RM Power User doesn't have the "Delete Record" capabilities
getRestAPIFactory().getRMUserAPI().assignRoleToUser(username, ROLE_RM_POWER_USER);
getRestAPIFactory().getRMUserAPI().assignRoleToUser(username, ROLE_RM_POWER_USER.roleId);
assertStatusCode(OK);
// Create random folder

View File

@@ -32,6 +32,7 @@ import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanCo
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.NON_ELECTRONIC_RECORD_TYPE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_SECURITY_OFFICER;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.IMAGE_FILE;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicRecordModel;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicUnfiledContainerChildModel;
@@ -58,7 +59,6 @@ import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChi
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildCollection;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildProperties;
import org.alfresco.rest.rm.community.model.user.UserPermissions;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RMUserAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI;
@@ -240,7 +240,7 @@ public class UpdateRecordsTests extends BaseRMRestTest
getDataUser().addUserToSite(updateUser, new SiteModel(getRestAPIFactory().getRMSiteAPI().getSite().getId()), UserRole.SiteCollaborator);
// RM Security Officer is the lowest role with Edit Record Metadata capabilities
rmUserAPI.assignRoleToUser(updateUser.getUsername(), UserRoles.ROLE_RM_SECURITY_OFFICER);
rmUserAPI.assignRoleToUser(updateUser.getUsername(), ROLE_RM_SECURITY_OFFICER.roleId);
assertStatusCode(OK);
// Create random folder

View File

@@ -0,0 +1,112 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco 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 Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.rmroles;
import static java.util.Collections.singleton;
import static com.google.common.collect.Sets.newHashSet;
import static org.alfresco.rest.rm.community.base.TestData.RM_ROLES;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_USER;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Set;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.user.UserCapabilities;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
/**
* API tests of RM roles.
*
* @author Tom Page
* @since 2.7
*/
public class RMRolesTests extends BaseRMRestTest
{
/** A list of capabilities. */
private static final java.util.HashSet<String> CAPABILITIES = newHashSet(UserCapabilities.VIEW_RECORDS_CAP, UserCapabilities.DECLARE_RECORDS_CAP);
/** The API for managing RM roles and capabilities. */
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
/** Check that the roles API returns the default RM roles. */
@Test(description = "Check the default RM roles exist.")
public void checkRMRolesExist()
{
Set<String> configuredRoles = rmRolesAndActionsAPI
.getConfiguredRoles(getAdminUser().getUsername(), getAdminUser().getPassword());
RM_ROLES.forEach(role -> assertTrue("Could not found role " + role, configuredRoles.contains(role)));
}
/** Check that the RM user has the capability to view and declare records. */
@Test(description = "Check the capabilities for the RM user.")
public void checkCapabilitiesForUser()
{
Set<String> capabilities = rmRolesAndActionsAPI
.getCapabilitiesForRole(getAdminUser().getUsername(), getAdminUser().getPassword(), ROLE_RM_USER
.roleId);
assertEquals("Unexpected capabilities found for RM User.", capabilities, CAPABILITIES);
}
/** Check that a new role can be created and retrieved. */
@Test(description = "Create a new role.")
public void createNewRole()
{
String roleName = generateTestPrefix(RMRolesTests.class) + "newName";
// Call the endpoint under test.
rmRolesAndActionsAPI.createRole(getAdminUser().getUsername(), getAdminUser().getPassword(), roleName,
"New Role Label", CAPABILITIES);
Set<String> actualCapabilities = rmRolesAndActionsAPI
.getCapabilitiesForRole(getAdminUser().getUsername(), getAdminUser().getPassword(), roleName);
assertEquals("Unexpected capabilities found for RM User.", actualCapabilities, CAPABILITIES);
}
/** Check that a role can be edited. */
@Test(description = "Update a role.")
public void updateRole()
{
String roleName = generateTestPrefix(RMRolesTests.class) + "Name";
rmRolesAndActionsAPI.createRole(getAdminUser().getUsername(), getAdminUser().getPassword(), roleName, "Label",
singleton(UserCapabilities.VIEW_RECORDS_CAP));
// Call the endpoint under test.
rmRolesAndActionsAPI.updateRole(getAdminUser().getUsername(), getAdminUser().getPassword(), roleName,
"Updated Label", singleton(UserCapabilities.DECLARE_RECORDS_CAP));
Set<String> actualCapabilities = rmRolesAndActionsAPI
.getCapabilitiesForRole(getAdminUser().getUsername(), getAdminUser().getPassword(), roleName);
assertEquals("Unexpected capabilities for edited RM User.", actualCapabilities, singleton(UserCapabilities.DECLARE_RECORDS_CAP));
}
}

View File

@@ -238,9 +238,7 @@ public class RMSiteTests extends BaseRMRestTest
createRMSiteIfNotExists();
// Create RM site model
RMSite rmSiteToUpdate = RMSite.builder().build();
rmSiteToUpdate.setTitle(NEW_TITLE);
rmSiteToUpdate.setDescription(NEW_DESCRIPTION);
RMSite rmSiteToUpdate = RMSite.builder().title(NEW_TITLE).description(NEW_DESCRIPTION).build();
// Create the RM site
getRestAPIFactory().getRMSiteAPI(getDataUser().createRandomTestUser("testUser")).updateRMSite(rmSiteToUpdate);

View File

@@ -27,6 +27,7 @@
package org.alfresco.rest.rm.community.utils;
import org.alfresco.rest.model.RestNodeBodyMoveCopyModel;
import org.alfresco.utility.model.ContentModel;
/**
* Utility class for core components models
@@ -53,4 +54,17 @@ public class CoreUtil
moveDestinationInfo.setTargetParentId(nodeId);
return moveDestinationInfo;
}
/**
* Helper method to create a Content Model
*
* @return ContentModel
* @throws Exception
*/
public static ContentModel toContentModel(String nodeId)
{
ContentModel node = new ContentModel();
node.setNodeRef(nodeId);
return node;
}
}

View File

@@ -60,10 +60,7 @@ public class RMSiteUtil
*/
public static RMSite createRMSiteModel(RMSiteCompliance compliance, String title, String description)
{
RMSite rmSiteModel = RMSite.builder().compliance(compliance).build();
rmSiteModel.setTitle(title);
rmSiteModel.setDescription(description);
return rmSiteModel;
return RMSite.builder().compliance(compliance).title(title).description(description).build();
}
/**

View File

@@ -0,0 +1,14 @@
# RM Patch Service
The RM Patch service operates independently of the Core Patch service & behaves differently.
Schema numbering is sequential, its a 4 digit number, prefixed with the major/minor version number, e.g. schema from a 2.4 version will be 24xx. This is a different policy to the core numbering (which bumps the schema number by 10 for each release).
Patches run in a single transaction. They may process data in batches, but its all wrapped in a single transaction, which is rolled back if the patch fails or is interrupted. AbstractModulePatch#245. When we implement applyInternal within a patch, that whole method runs inside a transaction.
DB Schema numbers update only after every patch runs. This means if a patch fails, earlier patches will re run. (see: ModulePatchExecuterImpl.executeInternal#140). This behaviour is different than cores behaviour, which updates the schema number after each successful patch.
DB Schema number is stored in the attribute service (key: “module-schema”) against the RMs module ID. This is not exposed in the UI. Nor in a REST API. The attribute service stores it directly in the DB, so isnt even accessible via the node browser.
If a customer wants to determine the schema number for a running system, theyll need to execute a DB query.
It's possible to configure a patch not to run if being upgraded from a earlier schema version by setting `fixesFromSchema` in the patch config xml.

View File

@@ -2,3 +2,28 @@
* [Enterprise Technical Documentation](../../rm-enterprise/documentation/README.md) (the link will only work if this repository contains the enterprise code)
* [Overview of the design of RM](overview.md)
* Records Management
* File Plan
* List of Values
* Records
* EMail Records
* Filed and Unfiled Records
* Easy Access Records
* Physical Records
* Record Import and Export
* Version Records
* Retention
* [Destruction](./destruction)
* Retention Schedules and Events
* Transfer and Accession
* Security
* [Extended permission service](extendedPermissionService.md)
* Roles, Capabilities and Permissions
* Discovery
* Governance Search
* Legal Holds
* Compliance
* Governance Audit
* Governance Rules
* Core Module Services
* [RM Patch Service](./PatchService.md)

View File

@@ -0,0 +1,60 @@
## Destruction
### Purpose
Ensure the immediate and permanent destruction of sensitive content.
This includes:
* Records
* Classified content
### Overview
Sensitive content is immediately deleted from the content store. It does not get added to the trashcan or any other recoverable location and as such should not be recoverable.
It is possible to configure the component to include a cleansing step prior to content deletion. This allows the binary content to be repeatedly overwritten prior to deletion to make it harder to forensically recover the binary data.
Recorded content can be explicitly destroyed whilst maintaining the original node and associated meta-data. This is configured as a characteristic of the destruction step within a retention schedule.
### Artifacts and Guidance
* Source Code Link: [GitLab](https://gitlab.alfresco.com/records-management/records-management/tree/master)
* License: Alfresco Community
* Issue Tracker Link: [JIRA RM](https://issues.alfresco.com/jira/projects/RM/summary)
* Contribution Model: Alfresco Closed Source
* Documentation: [docs.alfresco.com (Records Management)](http://docs.alfresco.com/rm2.4/concepts/welcome-rm.html)
***
### Design
#### Component Model
#### Content Model
* uri - http://www.alfresco.org/model/recordsmanagement/1.0
* prefix - rma
* rma:ghosted - aspect that indicates that a records content has been destroyed, but the records meta-data is still available.
#### Flows
![Alfresco Destruction Flow Diagram](./resource/sequence/destruction-sequence.png)
#### Class Diagram
![Alfresco Destruction Class Diagram](./resource/class/destruction-class.png)
***
### Interfaces and APIs
***
### Configuration
***
### Considerations
***

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -0,0 +1,43 @@
@startuml
DestroyAction --> ContentDestructionComponent
ContentDestructionComponent <|-- ExtendedContentDestructionComponent
ContentDestructionComponent --> EagerContentStoreCleaner
EagerContentStoreCleaner --> ContentCleanser
ContentCleanser <|-- ContentCleanser522022M
ContentCleanser +-- OverwriteOperation
class DestroyAction {
+ boolean ghostingEnabled
}
class ContentDestructionComponent {
+ boolean cleansingEnabled
+ void destroyContent(NodeRef nodeRef)
+ void destroyContent(NodeRef nodeRef, boolean includeRenditions)
+ void registerAllContentForDestruction(NodeRef nodeRef, boolean clearContentProperty)
}
class ExtendedContentDestructionComponent {
+ void onBeforeNodeDelete(NodeRef nodeRef)
}
class EagerContentStoreCleaner {
+ void registerOrphanedContentUrlForCleansing(String contentUrl)
# boolean deleteFromStore(String contentUrl, ContentStore store)
}
abstract class ContentCleanser {
# OverwriteOperation overwriteZeros
# OverwriteOperation overwriteOnes
# OverwriteOperation overwriteRandom
+ {abstract} void cleanse(File file)
# void overwrite(File file, OverwriteOperation overwriteOperation)
}
abstract class OverwriteOperation {
+ {abstract} void operation(OutputStream os) throws IOException
}
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,40 @@
@startuml
Title: Content Destruction and Cleansing Flow
participant "Repository" as R
participant "Behaviour" as B
participant "ContentDestructionComponent" as CDC
participant "EagerContentStoreCleaner" as ECSC
participant ConentCleanser as CC
participant ContentStore as CS
R->B:beforeNodeDelete
activate B
note right of B: sensitive content
B->CDC:registerAllContentForDestruction
deactivate B
activate CDC
note right of CDC: cleansing enabled
CDC->ECSC:registerOrphanedContentUrlForCleansing
deactivate CDC
activate ECSC
ECSC->ECSC: registerOrphanedContentUrl
R->ECSC:afterCommit
ECSC->CC:cleanse
activate CC
CC->ECSC
deactivate CC
ECSC->CS:delete
activate CS
CS->ECSC
deactivate CS
deactivate ECSC
@enduml

View File

@@ -0,0 +1,68 @@
## Alfresco Governance Services' Extended Permission Service
![Completeness Badge](https://img.shields.io/badge/Document_Level-Complete-green.svg?style=flat-square)
![Version Badge](https://img.shields.io/badge/Version-Current-blue.svg?style=flat-square)
### Purpose
When working on the Records Management module, we needed additional functionality around permissions, and therefore
introduced the [ExtendedPermissionService](../../rm-community/rm-community-repo/source/java/org/alfresco/repo/security/permissions/impl/ExtendedPermissionServiceImpl.java).
### Overview
The ExtendedPermissionService is wired in, via [Spring config](../../rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/extended-repository-context.xml),
to extend Alfresco's core PermissionService, and adds support for:
* the [RMPermissionModel](../../rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMPermissionModel.java), which defines the available permissions capabilities.
* the [PermissionProcessorRegistry](../../rm-community/rm-community-repo/source/java/org/alfresco/repo/security/permissions/processor/PermissionProcessorRegistry.java), which introduces pre- and post- processors.
* other minor method extensions (e.g. to setInheritParentPermissions)
### Permission Processor Registry
This was added in RM 2.4 to support the requirements around the additional security classifications and markings.
The registry is simply two array lists, one for pre-processors and one for post-processors, which are iterated around
before / after (respectively) the wrapped call PermissionService.hasPermission
Out of the box, a system with the RM module installed will have the following permissions processors defined:
#### Community:
##### Pre-processors:
* None.
##### Post-processors:
* [RecordsManagementPermissionPostProcessor](../../rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/permission/RecordsManagementPermissionPostProcessor.java)
* If the node is an RM node (i.e. it has the [RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT](../../rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/model/RecordsManagementModel.java) marker aspect) and the
core permissions evaluates to DENIED, then this post processor allows read/writes if the appropriate read/file
permissions are present.
#### Enterprise:
(links only work in clones of Enterprise repos)
##### Pre-processors:
* [SecurityMarksPermissionPreProcessor](../../rm-enterprise/rm-enterprise-repo/src/main/java/org/alfresco/module/org_alfresco_module_rm/securitymarks/permission/SecurityMarksPermissionPreProcessor.java)
* For all content: denies the result if the required security clearance rules (for classification or marks) are not satisfied. (uses
[securityClearanceService.isClearedFor](../../rm-enterprise/rm-enterprise-repo/src/main/java/org/alfresco/module/org_alfresco_module_rm/securitymarks/SecurityClearanceServiceImpl.java))
##### Post-processors:
* None.
### Configuration and Extension points
Additional processors can be defined by extending either [PermissionPreProcessorBaseImpl](../../rm-community/rm-community-repo/source/java/org/alfresco/repo/security/permissions/processor/impl/PermissionPreProcessorBaseImpl.java)
or [PermissionPostProcessorBaseImpl](../../rm-community/rm-community-repo/source/java/org/alfresco/repo/security/permissions/processor/impl/PermissionPostProcessorBaseImpl.java)
which call the add method on the appropriate list during init.
### Performance Implications
There is certainly a performance overhead when adding additional processing to permission checks. This is most noticeable
in the SecurityMarksPermissionPreProcessor where we need to call out to an external service. This has been profiled
heavily and optimised during 2.5 and 2.6 development.
###TODO:
Not yet documented (in related areas of the code) are:
* Capabilities (see rm-capabilities-*.xml, declarativeCapability.java and DeclarativeCompositeCapability.java)
* RM's permission system has an any allow allows policy unlike alfresco which policy is any deny denies

View File

@@ -65,6 +65,11 @@ We use standard Alfresco [data modelling](http://docs.alfresco.com/5.2/reference
***
### Component Overview
![Information Governance Component Overview](./resource/component/ig-component.png)
***
### Design Decisions
| Decision | Rationale | Date |

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -0,0 +1,58 @@
@startuml
skinparam componentArrowColor white
' IG Component Breakdown
rectangle "Information Governance" as IG {
rectangle "Records Management" as RM {
component "File Plan" as FP
rectangle "Records" as Rec {
component "Filed and Unfiled Records"
component "Easy Access Records"
component "Version Records"
component "Physical Records"
component "Email Records"
component "Record Import and Export"
}
rectangle "Retention" as Ret {
component "Retention Schedules and Events"
component "Transfer and Accession"
component "Destruction"
}
component "List of Values" as LOV
}
rectangle "Security" as Sec {
component "Roles, Capabilities and Permissions"
component "Security Marks"
component "Content Classification"
}
rectangle "Discovery" as Dis {
component "Search"
component "Legal Holds"
}
rectangle "Compliance" as Comp {
component "Audit"
component "DoD 5015.2"
}
rectangle "Automation" as Auto {
component "Rules"
}
}
' Fomatting
RM -[hidden]---- Sec
RM -[hidden]---- Dis
Dis -[hidden]- Comp
Rec -[hidden]-- Ret
FP -[hidden]- LOV
Sec -[hidden]-- Auto
@enduml

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-rm</artifactId>
<version>2.6.3-SNAPSHOT</version>
<version>2.7.3-SNAPSHOT</version>
</parent>
<licenses>

View File

@@ -17,6 +17,7 @@ imap.server.attachments.extraction.enabled=false
#
audit.enabled=true
audit.rm.enabled=true
audit.rm.viewLog.maxSize=100
#audit.rm.runas=admin
#audit.filter.alfresco-access.transaction.user=~null;.*

View File

@@ -70,7 +70,12 @@
"eventType" : "rmEventType.simple",
"eventName" : "case_complete",
"eventDisplayLabel" : "rmevent.case_complete"
}
},
{
"eventType": "rmEventType.simple",
"eventName": "declassification_review",
"eventDisplayLabel": "rmevent.declassification_review"
}
]
}

View File

@@ -18,6 +18,7 @@
<property name="nodeService" ref="nodeService" />
<property name="behaviourFilter" ref="policyBehaviourFilter" />
<property name="cleansingEnabled" value="${rm.content.cleansing.enabled}" />
<property name="contentBinDuplicationUtility" ref="contentBinDuplicationUtility"/>
</bean>
<!-- extended eager content store cleaner -->

View File

@@ -3,8 +3,8 @@ dod_dod5015.description=Modelo de contenido de DOD5015
dod_dod5015.type.dod_site.title=Sitio de DOD5015
dod_dod5015.type.dod_site.description=Sitio de DOD5015
dod_dod5015.type.dod_filePlan.title=Plan de ficheros DOD5015
dod_dod5015.type.dod_filePlan.description=Plan de ficheros DOD5015
dod_dod5015.type.dod_filePlan.title=Cuadro de clasificaci\u00f3n DOD5015
dod_dod5015.type.dod_filePlan.description=Cuadro de clasificaci\u00f3n DOD5015
dod_dod5015.type.dod_recordSeries.title=Serie de documentos de archivo (depreciada)
dod_dod5015.type.dod_recordSeries.description=Serie de documentos de archivo (depreciada)
@@ -95,3 +95,4 @@ dod_dod5015.property.dod_contact.title=Contacto
dod_dod5015.property.dod_contact.description=Contacto
dod_dod5015.property.dod_contentManagementSystem.title=Sistema de gesti\u00f3n de contenidos
dod_dod5015.property.dod_contentManagementSystem.description=Sistema de gesti\u00f3n de contenidos

View File

@@ -11,8 +11,8 @@ dod_dod5015.type.dod_recordSeries.description=\u30ec\u30b3\u30fc\u30c9\u30b7\u30
dod_dod5015.aspect.dod_dod5015record.title=DOD5015\u30ec\u30b3\u30fc\u30c9
dod_dod5015.aspect.dod_dod5015record.description=DOD5015\u30ec\u30b3\u30fc\u30c9
dod_dod5015.property.dod_publicationDate.title=\u767a\u884c\u65e5
dod_dod5015.property.dod_publicationDate.decription=\u767a\u884c\u65e5
dod_dod5015.property.dod_publicationDate.title=\u516c\u958b\u65e5
dod_dod5015.property.dod_publicationDate.decription=\u516c\u958b\u65e5
dod_dod5015.property.dod_originator.title=\u767a\u4fe1\u5143
dod_dod5015.property.dod_originator.decription=\u767a\u4fe1\u5143
dod_dod5015.property.dod_originatingOrganization.title=\u767a\u4fe1\u5143\u7d44\u7e54

View File

@@ -5,4 +5,4 @@ capability.CreateModifyDestroyClassificationGuides.title=\u5206\u985e\u30ac\u30a
capability.UpgradeDowngradeAndDeclassifyRecords.title=\u30c0\u30a6\u30f3\u30b0\u30ec\u30fc\u30c9\u306e\u66f4\u65b0\u3068\u30ec\u30b3\u30fc\u30c9\u306e\u5206\u985e\u89e3\u9664
capability.UpdateExemptionCategories.title=\u9664\u5916\u30ab\u30c6\u30b4\u30ea\u306e\u66f4\u65b0
capability.MapClassificationGuideMetadata.title=\u5206\u985e\u30ac\u30a4\u30c9\u30e1\u30bf\u30c7\u30fc\u30bf\u306e\u30de\u30c3\u30d4\u30f3\u30b0
capability.CreateModifyDestroyTimeframes.title=\u30bf\u30a4\u30e0\u30d5\u30ec\u30fc\u30e0\u306e\u4f5c\u6210/\u5909\u66f4/\u7834\u68c4
capability.CreateModifyDestroyTimeframes.title=\u671f\u9593\u306e\u4f5c\u6210/\u5909\u66f4/\u7834\u68c4

View File

@@ -56,4 +56,5 @@ log4j.logger.org.alfresco.module.org_alfresco_module_rm.patch=info
# Job debug
#
#log4j.logger.org.alfresco.module.org_alfresco_module_rm.job=debug
log4j.logger.org.alfresco.repo.web.scripts.roles.DynamicAuthoritiesGet=info
log4j.logger.org.alfresco.repo.web.scripts.roles.DynamicAuthoritiesGet=info
log4j.logger.org.alfresco.module.org_alfresco_module_rm.query.RecordsManagementQueryDAOImpl=info

View File

@@ -37,7 +37,7 @@ rm.action.event-not-undone=No puede deshacer el evento {0} porque no se ha defin
rm.action.node-not-record-category=No puede crear una planificaci\u00f3n de retenci\u00f3n para ({0}) porque no es una categor\u00eda de documento de archivo.
rm.action.parameter-not-supplied=A\u00f1ada un ''{0}'' para continuar.
rm.action.delete-not-hold-type=No se pudo eliminar el bloqueo porque {1} no es del tipo {0}.
rm.action.cast-to-rm-type=No puede cargar un tipo de carpeta personalizada al plan de ficheros de Records Management.
rm.action.cast-to-rm-type=No puede cargar un tipo de carpeta personalizada al cuadro de clasificaci\u00f3n de Records Management.
rm.action.record-folder-create=No puede crear una carpeta de documentos de archivo en otra carpeta de documentos de archivo.
rm.action.unique.child.type-error-message=No puede crear elementos m\u00faltiples de este tipo aqu\u00ed.
rm.action.multiple.children.type-error-message=No puede crear {0} aqu\u00ed.

View File

@@ -36,7 +36,7 @@ rm.action.records_only_undeclared=\u5b8c\u4e86\u3067\u304d\u308b\u306e\u306f\u30
rm.action.event-not-undone=\u30a4\u30d9\u30f3\u30c8 ''{0}'' \u306f\u4fdd\u7ba1\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u305f\u3081\u3001\u5143\u306b\u623b\u3059\u64cd\u4f5c\u306f\u884c\u3048\u307e\u305b\u3093\u3002
rm.action.node-not-record-category=''{0}'' \u306f\u30ec\u30b3\u30fc\u30c9\u30ab\u30c6\u30b4\u30ea\u3067\u306f\u306a\u3044\u305f\u3081\u3001\u4fdd\u7ba1\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3002
rm.action.parameter-not-supplied=''{0}'' \u3092\u8ffd\u52a0\u3057\u3066\u304f\u3060\u3055\u3044\u3002
rm.action.delete-not-hold-type=''{1}'' \u306f\u30bf\u30a4\u30d7 ''{0}'' \u3067\u306f\u306a\u3044\u305f\u3081\u3001\u30db\u30fc\u30eb\u30c9\u3092\u524a\u9664\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f.
rm.action.delete-not-hold-type=''{1}'' \u306f\u30bf\u30a4\u30d7 ''{0}'' \u3067\u306f\u306a\u3044\u305f\u3081\u3001\u30db\u30fc\u30eb\u30c9\u3092\u524a\u9664\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
rm.action.cast-to-rm-type=\u30ab\u30b9\u30bf\u30e0\u306e\u30d5\u30a9\u30eb\u30c0\u30bf\u30a4\u30d7\u306f\u3001\u30ec\u30b3\u30fc\u30c9\u7ba1\u7406\u306e\u6574\u7406\u4fdd\u7ba1\u30d7\u30e9\u30f3\u306b\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093\u3002
rm.action.record-folder-create=\u5225\u306e\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0\u5185\u306b\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0\u3092\u4f5c\u6210\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093\u3002
rm.action.unique.child.type-error-message=\u3053\u3053\u3067\u306f\u3001\u3053\u306e\u30bf\u30a4\u30d7\u306e\u30a2\u30a4\u30c6\u30e0\u3092\u8907\u6570\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3002

View File

@@ -35,7 +35,7 @@ hasDispositionAction.description=Los documentos de archivo y las carpetas tienen
# Are kind
isKind.title=Tipo de elemento de Records Management
isKind.description=Los elementos son una clase de componente del plan de ficheros
isKind.description=Los elementos son una clase de componente del cuadro de clasificaci\u00f3n
isKind.kind.display-label=Clase
# Are Record Type
@@ -49,12 +49,12 @@ isRecordType.description=Los documentos de archivo tienen un tipo de documento d
# Declare As Record
create-record.title=Declarar como documento de archivo
create-record.description=Declara el fichero como un documento de archivo
create-record.file-plan.display-label=Plan de ficheros
create-record.file-plan.display-label=Cuadro de clasificaci\u00f3n
create-record.hide-record.display-label=Ocultar documento de archivo
# Declare As Version Record
declare-as-version-record.title=Declarar la versi\u00f3n como documento de archivo
declare-as-version-record.description=Declara esta versi\u00f3n del fichero como un documento de archivo
declare-as-version-record.file-plan.display-label=Plan de ficheros
declare-as-version-record.file-plan.display-label=Cuadro de clasificaci\u00f3n
# Complete record
declareRecord.title=Documento de archivo completo
declareRecord.description=Completa un documento de archivo

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=Delete Object
rm.audit.login-succeeded=Login Successful
rm.audit.login-failed=Login Unsuccessful
rm.audit.create-person=Create User
rm.audit.delete-person=Delete User
rm.audit.create-userGroup=Create User Group
rm.audit.delete-userGroup=Delete User Group
rm.audit.addMember=Add To User Group
rm.audit.removeMember=Remove From User Group
rm.audit.linkTo=Link to
rm.audit.moveTo=Move to
rm.audit.copyTo=Copy to

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=Objekt gel\u00f6scht
rm.audit.login-succeeded=Anmeldung erfolgreich
rm.audit.login-failed=Anmeldung fehlgeschlagen
rm.audit.create-person=Benutzer anlegen
rm.audit.delete-person=Benutzer l\u00f6schen
rm.audit.create-userGroup=Benutzergruppe erstellen
rm.audit.delete-userGroup=Benutzergruppe l\u00f6schen
rm.audit.addMember=Zu Benutzergruppe hinzuf\u00fcgen
rm.audit.removeMember=Von Benutzergruppe entfernen
rm.audit.linkTo=Link zu
rm.audit.moveTo=Verschieben nach
rm.audit.copyTo=Kopieren nach

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=Eliminar objeto
rm.audit.login-succeeded=Inicio de sesi\u00f3n correcto
rm.audit.login-failed=Error de inicio de sesi\u00f3n
rm.audit.create-person=Crear usuario
rm.audit.delete-person=Eliminar usuario
rm.audit.create-userGroup=Crear grupo de usuarios
rm.audit.delete-userGroup=Eliminar grupo de usuarios
rm.audit.addMember=A\u00f1adir a grupo de usuarios
rm.audit.removeMember=Eliminar de grupo de usuarios
rm.audit.linkTo=Enlace a
rm.audit.moveTo=Mover a
rm.audit.copyTo=Copiar a

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=Supprimer l'objet
rm.audit.login-succeeded=La connexion a abouti
rm.audit.login-failed=La connexion a \u00e9chou\u00e9
rm.audit.create-person=Cr\u00e9er un utilisateur
rm.audit.delete-person=Supprimer un utilisateur
rm.audit.create-userGroup=Cr\u00e9er un groupe d'utilisateur
rm.audit.delete-userGroup=Supprimer le groupe d'utilisateur
rm.audit.addMember=Ajouter au groupe d'utilisateur
rm.audit.removeMember=Supprimer du groupe d'utilisateur
rm.audit.linkTo=Lier \u00e0
rm.audit.moveTo=D\u00e9placer vers...
rm.audit.copyTo=Copier vers...

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=Elimina oggetto
rm.audit.login-succeeded=Login riuscito
rm.audit.login-failed=Login non riuscito
rm.audit.create-person=Crea utente
rm.audit.delete-person=Elimina utente
rm.audit.create-userGroup=Crea gruppo utenti
rm.audit.delete-userGroup=Elimina gruppo utenti
rm.audit.addMember=Aggiungi al gruppo utenti
rm.audit.removeMember=Rimuovi dal gruppo utenti
rm.audit.linkTo=Collega a
rm.audit.moveTo=Sposta in
rm.audit.copyTo=Copia in

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u524a\u9664
rm.audit.login-succeeded=\u30ed\u30b0\u30a4\u30f3\u6210\u529f
rm.audit.login-failed=\u30ed\u30b0\u30a4\u30f3\u5931\u6557
rm.audit.create-person=\u30e6\u30fc\u30b6\u30fc\u306e\u4f5c\u6210
rm.audit.delete-person=\u30e6\u30fc\u30b6\u30fc\u306e\u524a\u9664
rm.audit.create-userGroup=\u30e6\u30fc\u30b6\u30fc\u30b0\u30eb\u30fc\u30d7\u306e\u4f5c\u6210
rm.audit.delete-userGroup=\u30e6\u30fc\u30b6\u30fc\u30b0\u30eb\u30fc\u30d7\u306e\u524a\u9664
rm.audit.addMember=\u30e6\u30fc\u30b6\u30fc\u30b0\u30eb\u30fc\u30d7\u306b\u8ffd\u52a0
rm.audit.removeMember=\u30e6\u30fc\u30b6\u30fc\u30b0\u30eb\u30fc\u30d7\u304b\u3089\u524a\u9664
rm.audit.linkTo=\u30ea\u30f3\u30af\u5148
rm.audit.moveTo=\u79fb\u52d5\u5148
rm.audit.copyTo=\u30b3\u30d4\u30fc\u5148

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=Slett element
rm.audit.login-succeeded=Vellykket p\u00e5logging
rm.audit.login-failed=Mislykket p\u00e5logging
rm.audit.create-person=Opprett bruker
rm.audit.delete-person=Slett bruker
rm.audit.create-userGroup=Opprett brukergruppe
rm.audit.delete-userGroup=Slett brukergruppe
rm.audit.addMember=Legg til i brukergruppe
rm.audit.removeMember=Fjern fra brukergruppe
rm.audit.linkTo=Koble til
rm.audit.moveTo=Flytt til
rm.audit.copyTo=Kopier til

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=Object verwijderen
rm.audit.login-succeeded=Aanmelden geslaagd
rm.audit.login-failed=Aanmelden niet geslaagd
rm.audit.create-person=Gebruiker maken
rm.audit.delete-person=Gebruiker verwijderen
rm.audit.create-userGroup=Gebruikersgroep maken
rm.audit.delete-userGroup=Gebruikersgroep verwijderen
rm.audit.addMember=Toevoegen aan gebruikersgroep
rm.audit.removeMember=Verwijderen uit gebruikersgroep
rm.audit.linkTo=Koppelen naar
rm.audit.moveTo=Verplaatsen naar
rm.audit.copyTo=Kopi\u00ebren naar

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=Excluir objeto
rm.audit.login-succeeded=Login bem-sucedido
rm.audit.login-failed=Login malsucedido
rm.audit.create-person=Criar usu\u00e1rio
rm.audit.delete-person=Excluir usu\u00e1rio
rm.audit.create-userGroup=Criar grupo de usu\u00e1rios
rm.audit.delete-userGroup=Excluir grupo de usu\u00e1rios
rm.audit.addMember=Adicionar ao grupo de usu\u00e1rios
rm.audit.removeMember=Remover do grupo de usu\u00e1rios
rm.audit.linkTo=Vincular a
rm.audit.moveTo=Mover para
rm.audit.copyTo=Copiar para

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043e\u0431\u
rm.audit.login-succeeded=\u0412\u0445\u043e\u0434 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d
rm.audit.login-failed=\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u0445\u043e\u0434\u0430
rm.audit.create-person=\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f
rm.audit.delete-person=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f
rm.audit.create-userGroup=\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0433\u0440\u0443\u043f\u043f\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439
rm.audit.delete-userGroup=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0433\u0440\u0443\u043f\u043f\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439
rm.audit.addMember=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0433\u0440\u0443\u043f\u043f\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439
rm.audit.removeMember=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437 \u0433\u0440\u0443\u043f\u043f\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439
rm.audit.linkTo=\u0421\u0432\u044f\u0437\u0430\u0442\u044c \u0441
rm.audit.moveTo=\u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432
rm.audit.copyTo=\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432

View File

@@ -4,6 +4,11 @@ rm.audit.delete-object=\u5220\u9664\u5bf9\u8c61
rm.audit.login-succeeded=\u767b\u5f55\u6210\u529f
rm.audit.login-failed=\u767b\u5f55\u5931\u8d25
rm.audit.create-person=\u521b\u5efa\u7528\u6237
rm.audit.delete-person=\u5220\u9664\u7528\u6237
rm.audit.create-userGroup=\u521b\u5efa\u7528\u6237\u7ec4
rm.audit.delete-userGroup=\u5220\u9664\u7528\u6237\u7ec4
rm.audit.addMember=\u52a0\u5230\u7528\u6237\u7ec4
rm.audit.removeMember=\u4ece\u7528\u6237\u7ec4\u79fb\u9664
rm.audit.linkTo=\u94fe\u63a5\u5230
rm.audit.moveTo=\u79fb\u52a8\u5230
rm.audit.copyTo=\u590d\u5236\u5230

View File

@@ -90,8 +90,8 @@ capability.ManageAccessRights.title=Administrar permisos
# Configuration
capability.group.config.title=Configuraci\u00f3n
capability.CreateModifyDestroyFileplanMetadata.title=Crear Modificar Destruir metadatos de plan de ficheros
capability.CreateModifyDestroyFileplanTypes.title=Crear Modificar Destruir tipos de plan de ficheros
capability.CreateModifyDestroyFileplanMetadata.title=Crear Modificar Destruir metadatos del cuadro de clasificaci\u00f3n
capability.CreateModifyDestroyFileplanTypes.title=Crear Modificar Destruir tipos del cuadro de clasificaci\u00f3n
capability.CreateModifyDestroyRecordTypes.title=Crear Modificar Destruir tipos de documento de archivo
capability.CreateAndAssociateSelectionLists.title=Crear y asociar listas de selecci\u00f3n
capability.EditSelectionLists.title=Editar listas de selecci\u00f3n

View File

@@ -4,10 +4,10 @@ rm.service.set-id=No puede cambiar el ID de {0} porque es de solo lectura.
rm.service.path-node=No se pudo encontrar {0}. Trate de actualizar el navegador o p\u00f3ngase en contacto con el dep. de TI.
rm.service.invalid-rm-node=El nodo de Records Management no es v\u00e1lido porque el aspecto {0} no est\u00e1 presente.
rm.service.no-root=No se pudo encontrar la ra\u00edz de Records Management. Trate de archivar el documento de archivo de nuevo.
rm.service.dup-root=No puede crear un plan de ficheros aqu\u00ed porque ya hay uno creado en esta jerarqu\u00eda de carpetas.
rm.service.root-type=No se puede crear el plan de ficheros porque el tipo {0} no es un subtipo de rma:filePlan. Vuelva a intentarlo usando un tipo diferente.
rm.service.container-parent-type=Solo puede crear una categor\u00eda de documentos de archivo en el nivel superior del plan de ficheros o en otra categor\u00eda de documentos de archivo (rma:recordCategory).
rm.service.container-type=Solo puede crear una categor\u00eda de documentos de archivo en el nivel superior del plan de ficheros o en otra categor\u00eda de documentos de archivo (rma:recordsManagementContainer o subtipo).
rm.service.dup-root=No puede crear un cuadro de clasificaci\u00f3n aqu\u00ed porque ya hay uno creado en esta jerarqu\u00eda de carpetas.
rm.service.root-type=No se puede crear el cuadro de clasificaci\u00f3n porque el tipo {0} no es un subtipo de rma:filePlan. Vuelva a intentarlo usando un tipo diferente.
rm.service.container-parent-type=Solo puede crear una categor\u00eda de documentos de archivo en el nivel superior del cuadro de clasificaci\u00f3n o en otra categor\u00eda de documentos de archivo (rma:recordCategory).
rm.service.container-type=Solo puede crear una categor\u00eda de documentos de archivo en el nivel superior del cuadro de clasificaci\u00f3n o en otra categor\u00eda de documentos de archivo (rma:recordsManagementContainer o subtipo).
rm.service.container-expected=Solo puede encontrar contenidos de categor\u00eda de documentos de archivo en una categor\u00eda de documentos de archivo (rma:recordCategory o subtipo).
rm.service.record-folder-expected=La acci\u00f3n solo puede completarse usando una carpeta de documentos de archivo del tipo rma:recordFolder.
rm.service.parent-record-folder-root=No puede crear una carpeta de documentos de archivo aqu\u00ed. Trate de crearla en una categor\u00eda de documentos de archivo.

View File

@@ -122,8 +122,8 @@ rma_recordsmanagement.property.rma_transferLocation.decription=Transferencia de
rma_recordsmanagement.association.rma_transferred.title=Transferido
rma_recordsmanagement.association.rma_transferred.decription=Transferido
rma_recordsmanagement.aspect.rma_filePlanComponent.title=Componente del plan de ficheros
rma_recordsmanagement.aspect.rma_filePlanComponent.decription=Componente del plan de ficheros
rma_recordsmanagement.aspect.rma_filePlanComponent.title=Componente del cuadro de clasificaci\u00f3n
rma_recordsmanagement.aspect.rma_filePlanComponent.decription=Componente del cuadro de clasificaci\u00f3n
rma_recordsmanagement.property.rma_rootNodeRef.title=Nodo ra\u00edz
rma_recordsmanagement.property.rma_rootNodeRef.decription=Nodo ra\u00edz

View File

@@ -19,4 +19,5 @@ rmevent.obsolete=Obsolete
rmevent.all_allowances_granted_are_terminated=All Allowances Granted are Terminated
rmevent.WGI_action_complete=WGI Action Complete
rmevent.separation=Separation
rmevent.case_complete=Case Complete
rmevent.case_complete=Case Complete
rmevent.declassification_review=Declassification Review

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=Alle einger\u00e4umten Berechtigun
rmevent.WGI_action_complete=WGI-Aktion abschlie\u00dfen
rmevent.separation=Trennung
rmevent.case_complete=Fall abgeschlossen
rmevent.declassification_review=Deklassifizierungs\u00fcberpr\u00fcfung

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=Todas las provisiones otorgadas ha
rmevent.WGI_action_complete=Acci\u00f3n WGI completa
rmevent.separation=Separaci\u00f3n
rmevent.case_complete=Caso completo
rmevent.declassification_review=Revisi\u00f3n de la desclasificaci\u00f3n

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=Toutes les autorisations accord\u0
rmevent.WGI_action_complete=Action WGI termin\u00e9e
rmevent.separation=S\u00e9paration
rmevent.case_complete=Cas termin\u00e9
rmevent.declassification_review=V\u00e9rification de d\u00e9classification

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=Tutte le concessioni sono state te
rmevent.WGI_action_complete=Azione WGI completata
rmevent.separation=Separazione
rmevent.case_complete=Caso completato
rmevent.declassification_review=Esame di declassificazione

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=\u8a31\u53ef\u3055\u308c\u3066\u30
rmevent.WGI_action_complete=WGI \u51e6\u7406\u5b8c\u4e86
rmevent.separation=\u5206\u96e2
rmevent.case_complete=\u30b1\u30fc\u30b9\u5b8c\u4e86
rmevent.declassification_review=\u5206\u985e\u89e3\u9664\u306e\u30ec\u30d3\u30e5\u30fc

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=Alle tillatelser som er gitt, er a
rmevent.WGI_action_complete=WGI-handling fullf\u00f8rt
rmevent.separation=Separasjon
rmevent.case_complete=Sak fullf\u00f8rt
rmevent.declassification_review=Gjennomgang av deklassifisering

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=Alle toegekende rechten zijn be\u0
rmevent.WGI_action_complete=WGI-actie afgerond
rmevent.separation=Scheiding
rmevent.case_complete=Geval afgerond
rmevent.declassification_review=Classificatieopheffingsrevisie

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=Todas as bonifica\u00e7\u00f5es co
rmevent.WGI_action_complete=A\u00e7\u00e3o de WGI conclu\u00edda
rmevent.separation=Separa\u00e7\u00e3o
rmevent.case_complete=Caso conclu\u00eddo
rmevent.declassification_review=Revis\u00e3o de desclassifica\u00e7\u00e3o

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=\u0412\u0441\u0435 \u043f\u0440\u0
rmevent.WGI_action_complete=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 WGI \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e
rmevent.separation=\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435
rmevent.case_complete=\u0421\u043b\u0443\u0447\u0430\u0439 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d
rmevent.declassification_review=\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0440\u0430\u0441\u0441\u0435\u043a\u0440\u0435\u0447\u0438\u0432\u0430\u043d\u0438\u044f

View File

@@ -20,3 +20,4 @@ rmevent.all_allowances_granted_are_terminated=\u6240\u6709\u6388\u4e88\u7684\u96
rmevent.WGI_action_complete=WGI \u64cd\u4f5c\u5b8c\u6210
rmevent.separation=\u5206\u79bb
rmevent.case_complete=\u6848\u4f8b\u5b8c\u6210
rmevent.declassification_review=\u53d6\u6d88\u5206\u7c7b\u7684\u5ba1\u67e5

View File

@@ -19,7 +19,7 @@ rm.savedsearch.cutoffRecordsName=\u30ab\u30c3\u30c8\u30aa\u30d5\u5bfe\u8c61\u306
rm.savedsearch.cutoffRecordsDesc=\u73fe\u5728\u30ab\u30c3\u30c8\u30aa\u30d5\u306e\u6761\u4ef6\u3092\u6e80\u305f\u3057\u3066\u3044\u308b\u3059\u3079\u3066\u306e\u30ec\u30b3\u30fc\u30c9\u3068\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0\u3002
rm.savedsearch.transferRecordsName=\u8ee2\u9001\u6761\u4ef6\u3092\u6e80\u305f\u3057\u3066\u3044\u308b\u30ec\u30b3\u30fc\u30c9\u304a\u3088\u3073\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0
rm.savedsearch.transferRecordsDesc=\u73fe\u5728\u8ee2\u9001\u6761\u4ef6\u3092\u6e80\u305f\u3057\u3066\u3044\u308b\u3059\u3079\u3066\u306e\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0\u3068\u30ec\u30b3\u30fc\u30c9\u3002
rm.savedsearch.destructionRecordsName=\u5ec3\u68c4\u6761\u4ef6\u3092\u6e80\u305f\u3057\u3066\u3044\u308b\u30ec\u30b3\u30fc\u30c9\u3068\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0
rm.savedsearch.destructionRecordsDesc=\u73fe\u5728\u5ec3\u68c4\u6761\u4ef6\u3092\u6e80\u305f\u3057\u3066\u3044\u308b\u3059\u3079\u3066\u306e\u30ec\u30b3\u30fc\u30c9\u3002
rm.savedsearch.destructionRecordsName=\u7834\u68c4\u53ef\u80fd\u306a\u30ec\u30b3\u30fc\u30c9\u3068\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0
rm.savedsearch.destructionRecordsDesc=\u73fe\u5728\u7834\u68c4\u6761\u4ef6\u3092\u6e80\u305f\u3057\u3066\u3044\u308b\u3059\u3079\u3066\u306e\u30ec\u30b3\u30fc\u30c9\u3002
rm.savedsearch.frozenRecordsName=\u30db\u30fc\u30eb\u30c9\u4e2d\u306e\u30ec\u30b3\u30fc\u30c9\u304a\u3088\u3073\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0
rm.savedsearch.frozenRecordsDesc=\u73fe\u5728\u30db\u30fc\u30eb\u30c9\u4e2d\u306e\u3059\u3079\u3066\u306e\u30ec\u30b3\u30fc\u30c9\u3068\u30ec\u30b3\u30fc\u30c9\u30d5\u30a9\u30eb\u30c0\u3002

View File

@@ -242,6 +242,12 @@
</index>
</property>
<property name="rma:combineDispositionStepConditions">
<title>Disposition Evaluator Combination</title>
<type>d:boolean</type>
<mandatory>false</mandatory>
</property>
</properties>
<mandatory-aspects>
<aspect>rma:filePlanComponent</aspect>
@@ -1130,6 +1136,19 @@
<tokenised>false</tokenised>
</index>
</property>
<property name="rma:declassificationReviewCompletedAt">
<type>d:date</type>
<protected>true</protected>
</property>
<property name="rma:declassificationReviewCompletedBy">
<type>d:text</type>
<protected>true</protected>
<index enabled="true">
<atomic>true</atomic>
<stored>false</stored>
<tokenised>false</tokenised>
</index>
</property>
</properties>
</aspect>

View File

@@ -490,8 +490,8 @@
<permission name="_EndRetention" expose="false">
<grantedToGroup permissionGroup="EndRetention"/>
</permission>
</permission>
</permissionSet>
</permissions>

View File

@@ -248,6 +248,12 @@
</property>
</bean>
<bean name="contentBinDuplicationUtility" class="org.alfresco.module.org_alfresco_module_rm.util.ContentBinDuplicationUtility" parent="baseService">
<property name="behaviourFilter" ref="policyBehaviourFilter"/>
<property name="contentService" ref="contentService"/>
<property name="recordsManagementQueryDAO" ref="recordsManagementQueryDAO"/>
</bean>
<!-- Prevent ghosted records being renditioned -->
<bean id="noRenditionsForGhosts" parent="baseRenditionPreventionClass">
<constructor-arg value="rma:ghosted"/>

View File

@@ -46,6 +46,7 @@
<property name="retryingTransactionHelper" ref="retryingTransactionHelper"/>
<property name="behaviourFilter" ref="policyBehaviourFilter" />
<property name="modulePatchExecuter" ref="rm.modulePatchExecuter" />
<property name="registryService" ref="registryService" />
</bean>
</beans>

View File

@@ -3,10 +3,10 @@
<mapper namespace="alfresco.query.rm">
<parameterMap id="parameter_CountRMIndentifier" type="map">
<parameter property="qnameId" jdbcType="BIGINT" javaType="java.lang.Long"/>
<parameter property="idValue" jdbcType="BIGINT" javaType="java.lang.String"/>
</parameterMap>
<parameterMap id="parameter_CountRMIndentifier" type="map">
<parameter property="qnameId" jdbcType="BIGINT" javaType="java.lang.Long"/>
<parameter property="idValue" jdbcType="BIGINT" javaType="java.lang.String"/>
</parameterMap>
<parameterMap id="parameter_folderPatchPaging" type="map">
<parameter property="processed" jdbcType="BIGINT" javaType="java.lang.Long"/>
@@ -17,11 +17,14 @@
<resultMap id="result_NodeRefEntity" type="org.alfresco.module.org_alfresco_module_rm.query.NodeRefEntity">
<result property="row" column="row" jdbcType="BIGINT" javaType="java.lang.Long"/>
<result property="protocol" column="protocol" jdbcType="VARCHAR" javaType="java.lang.String" />
<result property="identifier" column="identifier" jdbcType="VARCHAR" javaType="java.lang.String" />
<result property="uuid" column="uuid" jdbcType="VARCHAR" javaType="java.lang.String" />
<result property="protocol" column="protocol" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="identifier" column="identifier" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="uuid" column="uuid" jdbcType="VARCHAR" javaType="java.lang.String"/>
</resultMap>
<resultMap id="result_NodeIds" type="java.lang.Long">
<result property="node.id" column="node_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
</resultMap>
<select id="select_CountRMIndentifier" parameterMap="parameter_CountRMIndentifier" resultType="java.lang.Integer">
select
@@ -32,9 +35,39 @@
where
prop.qname_id = ? and
prop.string_value = ?
</select>
<!-- Get distinct property values of children for a given property qname -->
<select id="select_GetStringPropertyValuesOfChildren"
parameterType="org.alfresco.module.org_alfresco_module_rm.query.PropertyValuesOfChildrenQueryParams"
resultType="java.lang.String">
select
distinct childProp.string_value
from
alf_child_assoc assoc
left join alf_node_properties childProp on assoc.child_node_id = childProp.node_id
where
assoc.parent_node_id = #{parentId} and
childProp.qname_id = #{propertyQnameId}
</select>
<!-- Get list of node ids which reference given content url -->
<select id="select_NodeIdsWhichReferenceContentUrl"
parameterType="ContentUrl"
resultMap="result_NodeIds">
select
p.node_id
from
alf_content_url cu
LEFT OUTER JOIN alf_content_data cd ON (cd.content_url_id = cu.id)
LEFT OUTER JOIN alf_node_properties p ON (p.long_value = cd.id)
WHERE
content_url_short = #{contentUrlShort} and
content_url_crc = #{contentUrlCrc}
</select>
<select id="select_RecordFoldersWithSchedules"
parameterMap="parameter_folderPatchPaging"
@@ -50,23 +83,5 @@
and alfn.id between ? and ?
</select>
<!-- Counts the children that have at least one of the provided property values for a given property qname -->
<select id="select_CountChildrenWithPropertyValues"
parameterType="org.alfresco.module.org_alfresco_module_rm.query.ChildrenWithPropertyValuesQueryParams"
resultType="java.lang.Long">
select
count( distinct assoc.child_node_id )
from
alf_child_assoc assoc
left join alf_node_properties childProp on assoc.child_node_id = childProp.node_id
where
assoc.parent_node_id = #{parentId}
and childProp.qname_id = #{propertyQnameId}
and childProp.string_value in
<foreach item="item" index="index" collection="propertyValues" open="(" separator="," close=")">
'${item}'
</foreach>
</select>
</mapper>
</mapper>

View File

@@ -2,6 +2,11 @@
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<!-- Content -->
<typeAlias alias="ContentUrl" type="org.alfresco.repo.domain.contentdata.ContentUrlEntity"/>
</typeAliases>
<typeHandlers>
<typeHandler javaType="java.io.Serializable" handler="org.alfresco.ibatis.SerializableTypeHandler"/>
</typeHandlers>

View File

@@ -53,10 +53,43 @@
</bean>
<bean id="audit-event.create-person" parent="audit-event" class="org.alfresco.module.org_alfresco_module_rm.audit.event.CreatePersonAuditEvent">
<property name="nodeService" ref="nodeService" />
<property name="name" value="Create Person"/>
<property name="label" value="rm.audit.create-person"/>
</bean>
<bean id="audit-event.delete-person" parent="audit-event"
class="org.alfresco.module.org_alfresco_module_rm.audit.event.DeletePersonAuditEvent">
<property name="nodeService" ref="nodeService" />
<property name="name" value="Delete Person" />
<property name="label" value="rm.audit.delete-person" />
</bean>
<bean id="audit-event.create-userGroup" parent="audit-event" class="org.alfresco.module.org_alfresco_module_rm.audit.event.CreateUserGroupAuditEvent">
<property name="nodeService" ref="nodeService" />
<property name="name" value="Create User Group"/>
<property name="label" value="rm.audit.create-userGroup"/>
</bean>
<bean id="audit-event.delete-userGroup" parent="audit-event"
class="org.alfresco.module.org_alfresco_module_rm.audit.event.DeleteUserGroupAuditEvent">
<property name="nodeService" ref="nodeService" />
<property name="name" value="Delete User Group" />
<property name="label" value="rm.audit.delete-userGroup" />
</bean>
<bean id="audit-event.addMember" parent="audit-event" class="org.alfresco.module.org_alfresco_module_rm.audit.event.AddToUserGroupAuditEvent">
<property name="nodeService" ref="nodeService" />
<property name="name" value="Add To User Group"/>
<property name="label" value="rm.audit.addMember"/>
</bean>
<bean id="audit-event.removeMember" parent="audit-event" class="org.alfresco.module.org_alfresco_module_rm.audit.event.RemoveFromUserGroupAuditEvent">
<property name="nodeService" ref="nodeService" />
<property name="name" value="Remove From User Group"/>
<property name="label" value="rm.audit.removeMember"/>
</bean>
<bean id="audit-event.login-success" parent="audit-event" class="org.alfresco.module.org_alfresco_module_rm.audit.event.AuditEvent">
<property name="name" value="Login.Success"/>
<property name="label" value="rm.audit.login-succeeded"/>

View File

@@ -143,6 +143,7 @@
<property name="recordService" ref="RecordService" />
<property name="dispositionService" ref="DispositionService" />
<property name="quickShareService" ref="QuickShareService"/>
<property name="contentBinDuplicationUtility" ref="contentBinDuplicationUtility"/>
</bean>
<bean id="rma.recordComponentIdentifier" class="org.alfresco.module.org_alfresco_module_rm.model.rma.aspect.RecordComponentIdentifierAspect" parent="rm.baseBehaviour">

View File

@@ -933,6 +933,7 @@
<property name="dictionaryService" ref="dictionaryService" />
<property name="transactionService" ref="transactionService" />
<property name="nodeService" ref="nodeService" />
<property name="siteService" ref="siteService" />
<property name="auditComponent" ref="auditComponent" />
<property name="auditService" ref="auditService" />
<property name="contentService" ref="ContentService" />

View File

@@ -20,6 +20,7 @@
<property name="policyComponent" ref="policyComponent" />
<property name="jsonConversionComponentCache" ref="jsonConversionComponentCache" />
<property name="mimetypeService" ref="MimetypeService" />
<property name="dispositionService" ref="dispositionService" />
</bean>
<!-- extends core bean with RM extensions -->

View File

@@ -16,6 +16,7 @@
<bean id="rmv.versionRecord" class="org.alfresco.module.org_alfresco_module_rm.model.rma.aspect.VersionRecordAspect" parent="rm.baseBehaviour">
<property name="recordableVersionService" ref="RecordableVersionService" />
<property name="relationshipService" ref="RelationshipService" />
<property name="contentBinDuplicationUtility" ref="contentBinDuplicationUtility"/>
</bean>
<!-- extended version service bean definition -->

View File

@@ -466,8 +466,19 @@
<property name="dictionaryService" ref="DictionaryService" />
<property name="permissionService" ref="PermissionService" />
<property name="personService" ref="PersonService" />
<property name="recordCategoryUtil" ref="RecordCategoryUtil" />
<property name="classificationReasonsUtil" ref="ClassificationReasonsUtil" />
</bean>
<bean id="RecordCategoryUtil" class="org.alfresco.module.org_alfresco_module_rm.script.slingshot.RecordCategoryUtil">
<property name="nodeService" ref="NodeService"/>
</bean>
<bean id="ClassificationReasonsUtil" class="org.alfresco.module.org_alfresco_module_rm.script.slingshot.ClassificationReasonsUtil">
<property name="nodeService" ref="NodeService" />
</bean>
<bean
id="webscript.org.alfresco.slingshot.rmsearch.rmsearchproperties.get"
class="org.alfresco.module.org_alfresco_module_rm.script.slingshot.RMSearchPropertiesGet"
@@ -537,6 +548,9 @@
<property name="namespaceService" ref="namespaceService" />
<property name="capabilityService" ref="CapabilityService" />
<property name="filePlanService" ref="FilePlanService" />
<property name="viewLogMaxSize">
<value>${audit.rm.viewLog.maxSize}</value>
</property>
</bean>
<!-- REST impl for GET Class Definitions for RM/DM -->

View File

@@ -37,6 +37,7 @@
<#if action.period??>"period": "${action.period}",</#if>
<#if action.periodProperty??>"periodProperty": "${action.periodProperty}",</#if>
<#if action.location??>"location": "${action.location}",</#if>
<#if action.combineDispositionStepConditions??>"combineDispositionStepConditions": "${action.combineDispositionStepConditions?string}",</#if>
<#if action.events??>"events": [<#list action.events as event>"${event}"<#if event_has_next>,</#if></#list>],</#if>
"eligibleOnFirstCompleteEvent": ${action.eligibleOnFirstCompleteEvent?string}
}

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-rm-community</artifactId>
<version>2.6.3-SNAPSHOT</version>
<version>2.7.3-SNAPSHOT</version>
</parent>
<properties>
@@ -25,8 +25,6 @@
<alfresco.rm.artifactId>alfresco-rm-community-repo</alfresco.rm.artifactId>
<skip.integrationtests>true</skip.integrationtests>
<alfresco.solr.home>${project.build.directory}/solr/home</alfresco.solr.home>
<!-- FIXME: Cannot set it to the Alfresco version as some SQL Mapping files are missing in 5.2-SNAPSHOT. See BDE-843 -->
<alfresco.h2scripts.version>5.1.1</alfresco.h2scripts.version>
<api.explorer.version>1.4</api.explorer.version>
</properties>
@@ -364,7 +362,7 @@
<dependency>
<groupId>${alfresco.groupId}</groupId>
<artifactId>alfresco-repository</artifactId>
<version>${alfresco.h2scripts.version}</version>
<version>${alfresco.version}</version>
<classifier>h2scripts</classifier>
<exclusions>
<exclusion>
@@ -615,7 +613,7 @@
<dependency>
<groupId>${alfresco.groupId}</groupId>
<artifactId>alfresco-repository</artifactId>
<version>${alfresco.h2scripts.version}</version>
<version>${alfresco.version}</version>
<classifier>h2scripts</classifier>
<exclusions>
<exclusion>

View File

@@ -253,7 +253,7 @@ public class BroadcastDispositionActionDefinitionUpdateAction extends RMActionEx
{
NodeRef dispositionedNode = getNodeService().getPrimaryParent(nextAction.getNodeRef()).getParentRef();
DispositionActionDefinition definition = nextAction.getDispositionActionDefinition();
Date newAsOfDate = getDispositionService().calculateAsOfDate(dispositionedNode, definition, false);
Date newAsOfDate = getDispositionService().calculateAsOfDate(dispositionedNode, definition);
if (logger.isDebugEnabled())
{

Some files were not shown because too many files have changed in this diff Show More