mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-10 14:11:58 +00:00
Compare commits
53 Commits
tas-restap
...
tas-restap
Author | SHA1 | Date | |
---|---|---|---|
|
2733ece40f | ||
|
f01204bf0a | ||
|
add073938a | ||
|
472becd973 | ||
|
d9293fff27 | ||
|
361e6b0221 | ||
|
3aec98cb92 | ||
|
cfd0dd388e | ||
|
8aadb2baf1 | ||
|
ca6b4cce24 | ||
|
eb2c76f600 | ||
|
fa910faea6 | ||
|
d428c542fc | ||
|
d0d5ce8d9d | ||
|
3e4a3a0a31 | ||
|
7d5f01f3d5 | ||
|
1ae1f87cdf | ||
|
a5ceb3df00 | ||
|
18dc254813 | ||
|
b737775fd3 | ||
|
175a525b64 | ||
|
8dba7f9468 | ||
|
838794f274 | ||
|
917961569d | ||
|
8e1c10aae0 | ||
|
580dda50e6 | ||
|
d0bc3f1ece | ||
|
a05f2eb20f | ||
|
51029868a9 | ||
|
e0b1c6f776 | ||
|
9930f18291 | ||
|
ca785cda74 | ||
|
308a60dcfa | ||
|
2518910fe1 | ||
|
4ddfb16bff | ||
|
ffb4df068b | ||
|
7fdb040b50 | ||
|
c2e587d640 | ||
|
bed12e40ca | ||
|
a53daf152f | ||
|
cc03aaf92f | ||
|
f9102eae0d | ||
|
8f252b69f1 | ||
|
50f884556c | ||
|
b1ad95a756 | ||
|
581f82f332 | ||
|
80fda4ed56 | ||
|
086ca9229e | ||
|
6d84baa34e | ||
|
d048054903 | ||
|
faf6cafe5a | ||
|
13a134da27 | ||
|
5e93e937f9 |
@@ -4,7 +4,7 @@
|
||||
<groupId>org.alfresco.tas</groupId>
|
||||
<artifactId>restapi</artifactId>
|
||||
<name>alfresco-tas-restapi</name>
|
||||
<version>1.26</version>
|
||||
<version>1.43</version>
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-super-pom</artifactId>
|
||||
@@ -28,7 +28,7 @@
|
||||
<suiteXmlFile>src/main/resources/shared-resources/testCount.xml</suiteXmlFile>
|
||||
<maven.build.sourceVersion>11</maven.build.sourceVersion>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<tas.utility.version>3.0.17</tas.utility.version>
|
||||
<tas.utility.version>3.0.21</tas.utility.version>
|
||||
<rest-assured.version>3.3.0</rest-assured.version>
|
||||
<httpclient-osgi-version>4.5.3</httpclient-osgi-version>
|
||||
<json-path.version>3.3.0</json-path.version>
|
||||
@@ -37,7 +37,7 @@
|
||||
<jackson-databind.version>2.9.8</jackson-databind.version>
|
||||
<maven-release.version>2.5.3</maven-release.version>
|
||||
<org.glassfish.version>1.1.4</org.glassfish.version>
|
||||
<commons-lang3.version>3.9</commons-lang3.version>
|
||||
<commons-lang3.version>3.10</commons-lang3.version>
|
||||
<scribejava-apis.version>6.9.0</scribejava-apis.version>
|
||||
<test.exclude />
|
||||
<test.include />
|
||||
@@ -48,7 +48,7 @@
|
||||
<connection>scm:git:https://github.com/Alfresco/alfresco-tas-restapi.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-tas-restapi.git</developerConnection>
|
||||
<url>https://github.com/Alfresco/alfresco-tas-restapi</url>
|
||||
<tag>v1.26</tag>
|
||||
<tag>v1.43</tag>
|
||||
</scm>
|
||||
|
||||
<issueManagement>
|
||||
@@ -282,14 +282,14 @@
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
<version>2.5.8</version>
|
||||
<version>2.5.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-json-->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-json</artifactId>
|
||||
<version>2.5.8</version>
|
||||
<version>2.5.9</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
@@ -299,7 +299,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.1.0</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
|
@@ -166,6 +166,19 @@ public class JsonBodyGenerator
|
||||
.add("title", title).build();
|
||||
return value.toString();
|
||||
}
|
||||
/**
|
||||
* Method to create a Json object for SiteBody with site title, description, visibility
|
||||
* @param siteModel
|
||||
* @return String
|
||||
*/
|
||||
public static String updateSiteRequest(SiteModel siteModel)
|
||||
{
|
||||
JsonObject value = defineJSON()
|
||||
.add("title", siteModel.getTitle())
|
||||
.add("description", siteModel.getDescription())
|
||||
.add("visibility", siteModel.getVisibility().toString()).build();
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
public static String process(String processDefinitionKey, UserModel assignee, boolean sendEmailNotifications, Priority priority)
|
||||
{
|
||||
|
@@ -42,6 +42,7 @@ import org.alfresco.rest.requests.search.SearchSQLAPI;
|
||||
import org.alfresco.rest.requests.search.SearchSQLJDBC;
|
||||
import org.alfresco.rest.requests.search.ShardInfoAPI;
|
||||
import org.alfresco.rest.requests.search.SolrAPI;
|
||||
import org.alfresco.rest.requests.search.SolrAdminAPI;
|
||||
import org.alfresco.rest.requests.workflowAPI.RestWorkflowAPI;
|
||||
import org.alfresco.utility.LogFactory;
|
||||
import org.alfresco.utility.Utility;
|
||||
@@ -955,6 +956,11 @@ public class RestWrapper extends DSLWrapper<RestWrapper>
|
||||
{
|
||||
return new SolrAPI(this);
|
||||
}
|
||||
|
||||
public SolrAdminAPI withSolrAdminAPI()
|
||||
{
|
||||
return new SolrAdminAPI(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link RestDiscoveryAPI} using the rest Discovery API as prefix: {@link /alfresco/api/discovery}
|
||||
@@ -1134,4 +1140,15 @@ public class RestWrapper extends DSLWrapper<RestWrapper>
|
||||
configureRequestSpec().setBaseUri(this.serverURI);
|
||||
configureRequestSpec().setPort(this.serverPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding new method to configure Alfresco Endpoint.
|
||||
* Reconfiguration is required when restClient is used to executed apis on different <host>:<port> e.g. solr api followed by search api
|
||||
*/
|
||||
public void configureAlfrescoEndpoint()
|
||||
{
|
||||
this.serverURI = restProperties.envProperty().getTestServerUrl();
|
||||
this.serverPort = restProperties.envProperty().getPort();
|
||||
configureServerEndpoint();
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
package org.alfresco.rest.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.alfresco.rest.core.IRestModel;
|
||||
import org.alfresco.rest.core.assertion.ModelAssertion;
|
||||
import org.alfresco.utility.model.CustomAspectPropertiesModel;
|
||||
import org.alfresco.utility.model.TestModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Bogdan Bocancea
|
||||
*/
|
||||
public class RestCustomTypeModel extends TestModel implements IRestModel<RestCustomTypeModel>
|
||||
{
|
||||
@JsonProperty(value = "entry")
|
||||
RestCustomTypeModel model;
|
||||
|
||||
@JsonProperty(required = true)
|
||||
private String name;
|
||||
|
||||
@JsonProperty(required = true)
|
||||
private String parentName;
|
||||
|
||||
@JsonProperty
|
||||
private String title;
|
||||
|
||||
@JsonProperty
|
||||
private String description;
|
||||
|
||||
@JsonProperty
|
||||
private List<CustomAspectPropertiesModel> properties;
|
||||
|
||||
public RestCustomTypeModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public RestCustomTypeModel(String name, String parentName)
|
||||
{
|
||||
this.name = name;
|
||||
this.parentName = parentName;
|
||||
}
|
||||
|
||||
public RestCustomTypeModel(String name, String parentName, String title)
|
||||
{
|
||||
this.name = name;
|
||||
this.parentName = parentName;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestCustomTypeModel onModel()
|
||||
{
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAssertion<RestCustomTypeModel> and()
|
||||
{
|
||||
return assertThat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAssertion<RestCustomTypeModel> assertThat()
|
||||
{
|
||||
return new ModelAssertion<RestCustomTypeModel>(this);
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getParentName()
|
||||
{
|
||||
return parentName;
|
||||
}
|
||||
|
||||
public void setParentName(String parentName)
|
||||
{
|
||||
this.parentName = parentName;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title)
|
||||
{
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDescription()
|
||||
|
||||
{
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description)
|
||||
{
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public List<CustomAspectPropertiesModel> getProperties()
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(List<CustomAspectPropertiesModel> properties)
|
||||
{
|
||||
this.properties = properties;
|
||||
}
|
||||
}
|
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2020 Alfresco Software, Ltd. All rights reserved.
|
||||
* License rights for this program may be obtained from Alfresco Software, Ltd.
|
||||
* pursuant to a written agreement and any use of this program without such an
|
||||
* agreement is prohibited.
|
||||
*/
|
||||
|
||||
package org.alfresco.rest.model;
|
||||
|
||||
import org.alfresco.utility.model.TestModel;
|
||||
|
||||
public class RestIdentityServiceConfigurationModel extends TestModel{
|
||||
|
||||
public RestIdentityServiceConfigurationModel() {
|
||||
|
||||
}
|
||||
|
||||
private String authenticationChain;
|
||||
|
||||
private String authenticationEnabled;
|
||||
|
||||
private String enableBasicAuth;
|
||||
|
||||
private String authServerUrl;
|
||||
|
||||
private String realm;
|
||||
|
||||
private String resource;
|
||||
|
||||
private String publicClient;
|
||||
|
||||
private String sslRequired;
|
||||
|
||||
private String enablePkce;
|
||||
|
||||
private String credentialsSecret;
|
||||
|
||||
private String credentialsProvider;
|
||||
|
||||
public String getAuthenticationChain() {
|
||||
return authenticationChain;
|
||||
}
|
||||
|
||||
public void setAuthenticationChain(String authenticationChain) {
|
||||
this.authenticationChain = authenticationChain;
|
||||
}
|
||||
|
||||
public String getAuthenticationEnabled() {
|
||||
return authenticationEnabled;
|
||||
}
|
||||
|
||||
public void setAuthenticationEnabled(String authenticationEnabled) {
|
||||
this.authenticationEnabled = authenticationEnabled;
|
||||
}
|
||||
|
||||
public String getEnableBasicAuth() {
|
||||
return enableBasicAuth;
|
||||
}
|
||||
|
||||
public void setEnableBasicAuth(String enableBasicAuth) {
|
||||
this.enableBasicAuth = enableBasicAuth;
|
||||
}
|
||||
|
||||
public String getAuthServerUrl() {
|
||||
return authServerUrl;
|
||||
}
|
||||
|
||||
public void setAuthServerUrl(String authServerUrl) {
|
||||
this.authServerUrl = authServerUrl;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public void setRealm(String realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public String getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public String getPublicClient() {
|
||||
return publicClient;
|
||||
}
|
||||
|
||||
public void setPublicClient(String publicClient) {
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
|
||||
public String getSslRequired() {
|
||||
return sslRequired;
|
||||
}
|
||||
|
||||
public void setSslRequired(String sslRequired) {
|
||||
this.sslRequired = sslRequired;
|
||||
}
|
||||
|
||||
public String getEnablePkce() {
|
||||
return enablePkce;
|
||||
}
|
||||
|
||||
public void setEnablePkce(String enablePkce) {
|
||||
this.enablePkce = enablePkce;
|
||||
}
|
||||
|
||||
public String getCredentialsSecret() {
|
||||
return credentialsSecret;
|
||||
}
|
||||
|
||||
public void setCredentialsSecret(String credentialsSecret) {
|
||||
this.credentialsSecret = credentialsSecret;
|
||||
}
|
||||
|
||||
public String getCredentialsProvider() {
|
||||
return credentialsProvider;
|
||||
}
|
||||
|
||||
public void setCredentialsProvider(String credentialsProvider) {
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
}
|
||||
}
|
@@ -71,6 +71,8 @@ public class RestPersonModel extends TestModel implements IModelAssertion<RestPe
|
||||
private String userStatus;
|
||||
private String password;
|
||||
private Object properties;
|
||||
private String quotaUsed;
|
||||
private String quota;
|
||||
private Map<String, Boolean> capabilities;
|
||||
|
||||
public RestPersonModel()
|
||||
@@ -319,7 +321,25 @@ public class RestPersonModel extends TestModel implements IModelAssertion<RestPe
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
public String getQuotaUsed() {
|
||||
return quotaUsed;
|
||||
}
|
||||
|
||||
|
||||
public void setQuotaUsed(String quotaUsed) {
|
||||
this.quotaUsed = quotaUsed;
|
||||
}
|
||||
|
||||
public String getQuota() {
|
||||
return quota;
|
||||
}
|
||||
|
||||
public void setQuota(String quota) {
|
||||
this.quota = quota;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a PersonModel with random values for all existing fields excluding fields specified as ingnoredFields
|
||||
*
|
||||
* @param ignoredFields field to be excluded when generating a random model
|
||||
|
@@ -63,6 +63,8 @@ public class RestSyncServiceConfigModel extends TestModel
|
||||
@JsonProperty(required = true)
|
||||
private RestSyncServiceRepoInfoModel repoInfo;
|
||||
|
||||
private RestIdentityServiceConfigurationModel identityServiceConfig;
|
||||
|
||||
public String getDsyncClientVersionMin()
|
||||
{
|
||||
return dsyncClientVersionMin;
|
||||
@@ -77,5 +79,8 @@ public class RestSyncServiceConfigModel extends TestModel
|
||||
{
|
||||
return repoInfo;
|
||||
}
|
||||
|
||||
|
||||
public RestIdentityServiceConfigurationModel getIdentityServiceConfig() {
|
||||
return identityServiceConfig;
|
||||
}
|
||||
}
|
||||
|
@@ -67,6 +67,8 @@ public class RestSyncServiceModel extends TestModel
|
||||
@JsonProperty(required = true)
|
||||
private RestSyncServiceConfigModel config;
|
||||
|
||||
private RestIdentityServiceConfigurationModel identityServiceConfig;
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
@@ -81,5 +83,12 @@ public class RestSyncServiceModel extends TestModel
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
public RestIdentityServiceConfigurationModel getIdentityServiceConfig() {
|
||||
return identityServiceConfig;
|
||||
}
|
||||
|
||||
public void setIdentityServiceConfig(RestIdentityServiceConfigurationModel identityServiceConfig) {
|
||||
this.identityServiceConfig = identityServiceConfig;
|
||||
}
|
||||
}
|
||||
|
@@ -56,6 +56,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
"async": false,
|
||||
"authority": null,
|
||||
"cascade": false
|
||||
"folderChange": false
|
||||
}
|
||||
]
|
||||
*/
|
||||
@@ -147,6 +148,9 @@ public class RestSyncSetChangesModel extends TestModel
|
||||
|
||||
@JsonProperty(required = true)
|
||||
private int numberOfSecondaryAssocs;
|
||||
|
||||
@JsonProperty(required = true)
|
||||
private boolean folderChange;
|
||||
|
||||
|
||||
|
||||
@@ -294,4 +298,12 @@ public class RestSyncSetChangesModel extends TestModel
|
||||
{
|
||||
this.numberOfSecondaryAssocs = numberOfSecondaryAssocs;
|
||||
}
|
||||
|
||||
public boolean isFolderChange() {
|
||||
return folderChange;
|
||||
}
|
||||
|
||||
public void setFolderChange(boolean folderChange) {
|
||||
this.folderChange = folderChange;
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,5 @@
|
||||
package org.alfresco.rest.requests;
|
||||
|
||||
import javax.json.JsonArrayBuilder;
|
||||
|
||||
import org.alfresco.rest.core.JsonBodyGenerator;
|
||||
import org.alfresco.rest.core.RestRequest;
|
||||
import org.alfresco.rest.core.RestWrapper;
|
||||
@@ -18,7 +16,9 @@ public class CustomAspectModelManager extends ModelRequest<CustomAspectModelMana
|
||||
{
|
||||
private CustomContentModel customContentModel;
|
||||
private CustomAspectModel customAspectModel;
|
||||
|
||||
private CustomModelProperties customProperties = new CustomModelProperties(restWrapper);
|
||||
|
||||
|
||||
public CustomAspectModelManager(CustomContentModel customContentModel, CustomAspectModel aspectModel, RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
@@ -29,41 +29,58 @@ public class CustomAspectModelManager extends ModelRequest<CustomAspectModelMana
|
||||
public RestCustomAspectModel getAspect()
|
||||
{
|
||||
RestRequest request = RestRequest.simpleRequest(HttpMethod.GET, "cmm/{modelName}/aspects/{aspectName}?{parameters}",
|
||||
this.customContentModel.getName(), this.customAspectModel.getName(), restWrapper.getParameters());
|
||||
this.customContentModel.getName(), this.customAspectModel.getName(), restWrapper.getParameters());
|
||||
return restWrapper.processModel(RestCustomAspectModel.class, request);
|
||||
}
|
||||
|
||||
public void addProperty(CustomAspectPropertiesModel propertyModel)
|
||||
{
|
||||
JsonArrayBuilder array = JsonBodyGenerator.defineJSONArray();
|
||||
array.add(JsonBodyGenerator.defineJSON()
|
||||
.add("name", propertyModel.getName())
|
||||
.add("title", propertyModel.getTitle())
|
||||
.add("description", propertyModel.getDescription())
|
||||
.add("dataType", propertyModel.getDataType())
|
||||
.add("multiValued", propertyModel.isMultiValued())
|
||||
.add("mandatory", propertyModel.isMandatory())
|
||||
.add("mandatoryEnforced", propertyModel.isMandatoryEnforced()));
|
||||
|
||||
String body = JsonBodyGenerator.defineJSON().add("name", this.customAspectModel.getName()).add("properties", array).build().toString();
|
||||
RestRequest request = RestRequest.requestWithBody(HttpMethod.PUT, body, "cmm/{modelName}/aspects/{aspectName}?select=props",
|
||||
this.customContentModel.getName(), this.customAspectModel.getName());
|
||||
restWrapper.processEmptyModel(request);
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, true,
|
||||
this.customAspectModel.getName(), false, null);
|
||||
}
|
||||
|
||||
|
||||
public void addPropertyWithMinMaxValueConstraint(CustomAspectPropertiesModel propertyModel, int minValue, int maxValue)
|
||||
{
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, true, this.customAspectModel.getName(),
|
||||
true, customProperties.createMinMaxValueConstraintArray(minValue, maxValue));
|
||||
}
|
||||
|
||||
public void addPropertyWithMinMaxLengthConstraint(CustomAspectPropertiesModel propertyModel, int minLength, int maxLength)
|
||||
{
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, true, this.customAspectModel.getName(),
|
||||
true, customProperties.createMinMaxLengthConstraint(minLength, maxLength));
|
||||
}
|
||||
|
||||
public void addPropertyWithListOfValues(CustomAspectPropertiesModel propertyModel, boolean sorted, String... listOfValues)
|
||||
{
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, true, this.customAspectModel.getName(),
|
||||
true, customProperties.createListOfValuesConstraint(sorted, listOfValues));
|
||||
}
|
||||
|
||||
public void addPropertyWithRegularExpression(CustomAspectPropertiesModel propertyModel, String regex)
|
||||
{
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, true, this.customAspectModel.getName(),
|
||||
true, customProperties.createRegexConstraint(regex));
|
||||
}
|
||||
|
||||
public void deleteAspectProperty(CustomAspectPropertiesModel propertyModel)
|
||||
{
|
||||
String body = JsonBodyGenerator.defineJSON()
|
||||
.add("name", this.customAspectModel.getName()).build().toString();
|
||||
RestRequest request = RestRequest.requestWithBody(HttpMethod.PUT, body, "cmm/{modelName}/aspects/{aspectName}?select=props&delete={propertyName}",
|
||||
this.customContentModel.getName(), this.customAspectModel.getName(), propertyModel.getName());
|
||||
.add("name", this.customAspectModel.getName()).build().toString();
|
||||
RestRequest request = RestRequest.requestWithBody(HttpMethod.PUT, body,
|
||||
"cmm/{modelName}/aspects/{aspectName}?select=props&delete={propertyName}",
|
||||
this.customContentModel.getName(),
|
||||
this.customAspectModel.getName(),
|
||||
propertyModel.getName());
|
||||
restWrapper.processEmptyModel(request);
|
||||
}
|
||||
|
||||
public void deleteAspect()
|
||||
{
|
||||
RestRequest request = RestRequest.simpleRequest(HttpMethod.DELETE, "cmm/{modelName}/aspects/{aspectName}",
|
||||
this.customContentModel.getName(), this.customAspectModel.getName());
|
||||
RestRequest request = RestRequest.simpleRequest(HttpMethod.DELETE,
|
||||
"cmm/{modelName}/aspects/{aspectName}",
|
||||
this.customContentModel.getName(),
|
||||
this.customAspectModel.getName());
|
||||
restWrapper.processEmptyModel(request);
|
||||
}
|
||||
}
|
||||
|
@@ -3,10 +3,19 @@ package org.alfresco.rest.requests;
|
||||
import org.alfresco.rest.core.JsonBodyGenerator;
|
||||
import org.alfresco.rest.core.RestRequest;
|
||||
import org.alfresco.rest.core.RestWrapper;
|
||||
import org.alfresco.rest.model.RestCustomAspectModel;
|
||||
import org.alfresco.rest.model.RestCustomModel;
|
||||
import org.alfresco.rest.model.RestCustomTypeModel;
|
||||
import org.alfresco.rest.model.RestGroupsModelsCollection;
|
||||
import org.alfresco.utility.model.CustomAspectModel;
|
||||
import org.alfresco.utility.model.CustomAspectPropertiesModel;
|
||||
import org.alfresco.utility.model.CustomContentModel;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonArrayBuilder;
|
||||
import javax.json.JsonObject;
|
||||
|
||||
/**
|
||||
* @author Bogdan Bocancea
|
||||
*/
|
||||
@@ -14,12 +23,30 @@ public class CustomModelManager extends ModelRequest<CustomModelManager>
|
||||
{
|
||||
private CustomContentModel customContentModel;
|
||||
|
||||
public CustomModelManager(RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
}
|
||||
|
||||
public CustomModelManager(CustomContentModel customContentModel, RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
this.customContentModel = customContentModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new custom model
|
||||
*
|
||||
* @param customContentModel
|
||||
* @return {@link RestCustomModel}
|
||||
*/
|
||||
public RestCustomModel createCustomModel(CustomContentModel customContentModel)
|
||||
{
|
||||
RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, customContentModel.toJson(),
|
||||
"cmm?{parameters}", restWrapper.getParameters());
|
||||
return restWrapper.processModel(RestCustomModel.class, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve one model using GET call on "cmm/{modelName}"
|
||||
*
|
||||
@@ -51,4 +78,18 @@ public class CustomModelManager extends ModelRequest<CustomModelManager>
|
||||
RestRequest request = RestRequest.simpleRequest(HttpMethod.DELETE, "cmm/{modelName}", this.customContentModel.getName());
|
||||
restWrapper.processEmptyModel(request);
|
||||
}
|
||||
|
||||
public RestCustomAspectModel createAspect(CustomAspectModel aspectModel)
|
||||
{
|
||||
RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, aspectModel.toJson(),
|
||||
"cmm/{modelName}/aspects?{parameters}", this.customContentModel.getName(), restWrapper.getParameters());
|
||||
return restWrapper.processModel(RestCustomAspectModel.class, request);
|
||||
}
|
||||
|
||||
public RestCustomTypeModel createCustomType(RestCustomTypeModel customType)
|
||||
{
|
||||
RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, customType.toJson(),
|
||||
"cmm/{modelName}/types?{parameters}", this.customContentModel.getName(), restWrapper.getParameters());
|
||||
return restWrapper.processModel(RestCustomTypeModel.class, request);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,164 @@
|
||||
package org.alfresco.rest.requests;
|
||||
|
||||
import org.alfresco.rest.core.JsonBodyGenerator;
|
||||
import org.alfresco.rest.core.RestRequest;
|
||||
import org.alfresco.rest.core.RestWrapper;
|
||||
import org.alfresco.utility.model.CustomAspectPropertiesModel;
|
||||
import org.alfresco.utility.model.CustomContentModel;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import javax.json.JsonArrayBuilder;
|
||||
import javax.json.JsonObjectBuilder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Bogdan Bocancea
|
||||
*/
|
||||
public class CustomModelProperties extends ModelRequest<CustomModelProperties>
|
||||
{
|
||||
public CustomModelProperties(RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
}
|
||||
|
||||
public void addProperty(CustomAspectPropertiesModel propertyModel,
|
||||
CustomContentModel customContentModel,
|
||||
boolean isAspect,
|
||||
String aspectOrTypeName,
|
||||
boolean hasConstraints,
|
||||
JsonArrayBuilder constraintsArray)
|
||||
{
|
||||
JsonArrayBuilder array;
|
||||
if(hasConstraints)
|
||||
{
|
||||
array = getPropertiesArray(propertyModel, true, constraintsArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
array = getPropertiesArray(propertyModel, false, null);
|
||||
}
|
||||
|
||||
String body = JsonBodyGenerator.defineJSON()
|
||||
.add("name", aspectOrTypeName)
|
||||
.add("properties", array).build().toString();
|
||||
String urlPath;
|
||||
if(isAspect)
|
||||
{
|
||||
urlPath = "cmm/{modelName}/aspects/{aspectName}?select=props";
|
||||
}
|
||||
else
|
||||
{
|
||||
urlPath = "cmm/{modelName}/types/{typeName}?select=props";
|
||||
}
|
||||
RestRequest request = RestRequest.requestWithBody(HttpMethod.PUT, body, urlPath,
|
||||
customContentModel.getName(), aspectOrTypeName);
|
||||
restWrapper.processEmptyModel(request);
|
||||
}
|
||||
|
||||
private JsonArrayBuilder getPropertiesArray(CustomAspectPropertiesModel propertyModel, boolean hasConstraints, JsonArrayBuilder constraintsArray)
|
||||
{
|
||||
JsonArrayBuilder array = JsonBodyGenerator.defineJSONArray();;
|
||||
if(hasConstraints)
|
||||
{
|
||||
array.add(JsonBodyGenerator.defineJSON()
|
||||
.add("name", propertyModel.getName())
|
||||
.add("title", propertyModel.getTitle())
|
||||
.add("description", propertyModel.getDescription())
|
||||
.add("dataType", propertyModel.getDataType())
|
||||
.add("multiValued", propertyModel.isMultiValued())
|
||||
.add("mandatory", propertyModel.isMandatory())
|
||||
.add("mandatoryEnforced", propertyModel.isMandatoryEnforced())
|
||||
.add("constraints", constraintsArray));
|
||||
}
|
||||
else
|
||||
{
|
||||
array.add(JsonBodyGenerator.defineJSON()
|
||||
.add("name", propertyModel.getName())
|
||||
.add("title", propertyModel.getTitle())
|
||||
.add("description", propertyModel.getDescription())
|
||||
.add("dataType", propertyModel.getDataType())
|
||||
.add("multiValued", propertyModel.isMultiValued())
|
||||
.add("mandatory", propertyModel.isMandatory())
|
||||
.add("mandatoryEnforced", propertyModel.isMandatoryEnforced()));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public JsonArrayBuilder createMinMaxValueConstraintArray(int minValue, int maxValue)
|
||||
{
|
||||
JsonArrayBuilder constraintsArray = JsonBodyGenerator.defineJSONArray();
|
||||
JsonObjectBuilder param1 = JsonBodyGenerator.defineJSON()
|
||||
.add("name", "minValue")
|
||||
.add("simpleValue", Integer.valueOf(minValue));
|
||||
JsonObjectBuilder param2 = JsonBodyGenerator.defineJSON()
|
||||
.add("name", "maxValue")
|
||||
.add("simpleValue", Integer.valueOf(maxValue));
|
||||
JsonArrayBuilder parameters = JsonBodyGenerator.defineJSONArray();
|
||||
parameters.add(0, param1).add(1, param2);
|
||||
constraintsArray.add(JsonBodyGenerator.defineJSON()
|
||||
.add("name", "MINMAX_" + UUID.randomUUID())
|
||||
.add("type", "MINMAX")
|
||||
.add("parameters", parameters));
|
||||
return constraintsArray;
|
||||
}
|
||||
|
||||
public JsonArrayBuilder createMinMaxLengthConstraint(int minLength, int maxLength)
|
||||
{
|
||||
JsonArrayBuilder constraintsArray = JsonBodyGenerator.defineJSONArray();
|
||||
JsonObjectBuilder param1 = JsonBodyGenerator.defineJSON()
|
||||
.add("name", "minLength")
|
||||
.add("simpleValue", Integer.valueOf(minLength));
|
||||
JsonObjectBuilder param2 = JsonBodyGenerator.defineJSON()
|
||||
.add("name", "maxLength")
|
||||
.add("simpleValue", Integer.valueOf(maxLength));
|
||||
JsonArrayBuilder parameters = JsonBodyGenerator.defineJSONArray();
|
||||
parameters.add(0, param1).add(1, param2);
|
||||
constraintsArray.add(JsonBodyGenerator.defineJSON()
|
||||
.add("name", "LENGTH_" + UUID.randomUUID())
|
||||
.add("type", "LENGTH")
|
||||
.add("parameters", parameters));
|
||||
return constraintsArray;
|
||||
}
|
||||
|
||||
public JsonArrayBuilder createListOfValuesConstraint(boolean sorted, String... listOfValues)
|
||||
{
|
||||
JsonArrayBuilder valuesArray = JsonBodyGenerator.defineJSONArray();
|
||||
Arrays.stream(listOfValues).forEach(valuesArray::add);
|
||||
JsonArrayBuilder constraintsArray = JsonBodyGenerator.defineJSONArray();
|
||||
JsonObjectBuilder param1 = JsonBodyGenerator.defineJSON()
|
||||
.add("name", "allowedValues")
|
||||
.add("listValue", valuesArray);
|
||||
JsonObjectBuilder param2 = JsonBodyGenerator.defineJSON()
|
||||
.add("name", "sorted")
|
||||
.add("simpleValue", Boolean.valueOf(sorted));
|
||||
JsonArrayBuilder parameters = JsonBodyGenerator.defineJSONArray();
|
||||
parameters.add(0, param1).add(1, param2);
|
||||
constraintsArray.add(JsonBodyGenerator.defineJSON()
|
||||
.add("name", "LIST_" + UUID.randomUUID())
|
||||
.add("type", "LIST")
|
||||
.add("parameters", parameters));
|
||||
return constraintsArray;
|
||||
}
|
||||
|
||||
public JsonArrayBuilder createRegexConstraint(String regex)
|
||||
{
|
||||
JsonArrayBuilder constraintsArray = JsonBodyGenerator.defineJSONArray();
|
||||
JsonObjectBuilder param1 = JsonBodyGenerator.defineJSON()
|
||||
.add("name", "expression")
|
||||
.add("simpleValue", regex);
|
||||
JsonObjectBuilder param2 = JsonBodyGenerator.defineJSON()
|
||||
.add("name", "requiresMatch")
|
||||
.add("simpleValue", true);
|
||||
JsonArrayBuilder parameters = JsonBodyGenerator.defineJSONArray();
|
||||
parameters.add(0, param1).add(1, param2);
|
||||
constraintsArray.add(JsonBodyGenerator.defineJSON()
|
||||
.add("name", "REGEX_" + UUID.randomUUID())
|
||||
.add("type", "REGEX")
|
||||
.add("parameters", parameters));
|
||||
return constraintsArray;
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
package org.alfresco.rest.requests;
|
||||
|
||||
import org.alfresco.rest.core.RestRequest;
|
||||
import org.alfresco.rest.core.RestWrapper;
|
||||
import org.alfresco.rest.model.RestCustomTypeModel;
|
||||
import org.alfresco.utility.model.CustomAspectPropertiesModel;
|
||||
import org.alfresco.utility.model.CustomContentModel;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
* @author Bogdan Bocancea
|
||||
*/
|
||||
public class CustomTypeManager extends ModelRequest<CustomTypeManager>
|
||||
{
|
||||
private CustomContentModel customContentModel;
|
||||
private RestCustomTypeModel customTypeModel;
|
||||
private CustomModelProperties customProperties = new CustomModelProperties(restWrapper);
|
||||
|
||||
public CustomTypeManager(CustomContentModel customContentModel, RestCustomTypeModel customTypeModel, RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
this.customContentModel = customContentModel;
|
||||
this.customTypeModel = customTypeModel;
|
||||
}
|
||||
|
||||
public RestCustomTypeModel getCustomType()
|
||||
{
|
||||
RestRequest request = RestRequest.simpleRequest(HttpMethod.GET, "cmm/{modelName}/types/{typeName}?{parameters}",
|
||||
this.customContentModel.getName(), this.customTypeModel.getName(), restWrapper.getParameters());
|
||||
return restWrapper.processModel(RestCustomTypeModel.class, request);
|
||||
}
|
||||
|
||||
public void addProperty(CustomAspectPropertiesModel propertyModel)
|
||||
{
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, false,
|
||||
this.customTypeModel.getName(), false, null);
|
||||
}
|
||||
|
||||
public void addPropertyWithMinMaxValueConstraint(CustomAspectPropertiesModel propertyModel, int minValue, int maxValue)
|
||||
{
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, false, this.customTypeModel.getName(),
|
||||
true, customProperties.createMinMaxValueConstraintArray(minValue, maxValue));
|
||||
}
|
||||
|
||||
public void addPropertyWithMinMaxLengthConstraint(CustomAspectPropertiesModel propertyModel, int minLength, int maxLength)
|
||||
{
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, false, this.customTypeModel.getName(),
|
||||
true, customProperties.createMinMaxLengthConstraint(minLength, maxLength));
|
||||
}
|
||||
|
||||
public void addPropertyWithListOfValues(CustomAspectPropertiesModel propertyModel, boolean sorted, String... listOfValues)
|
||||
{
|
||||
customProperties.addProperty(propertyModel, this.customContentModel, false, this.customTypeModel.getName(),
|
||||
true, customProperties.createListOfValuesConstraint(sorted, listOfValues));
|
||||
}
|
||||
|
||||
public void deleteCustomType()
|
||||
{
|
||||
RestRequest request = RestRequest.simpleRequest(HttpMethod.DELETE,
|
||||
"cmm/{modelName}/types/{typeName}",
|
||||
this.customContentModel.getName(),
|
||||
this.customTypeModel.getName());
|
||||
restWrapper.processEmptyModel(request);
|
||||
}
|
||||
}
|
@@ -192,6 +192,38 @@ public class Site extends ModelRequest<Site>
|
||||
return restWrapper.processModel(RestSiteModel.class, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a site: Site title, description, visibility can be updated
|
||||
* Body:
|
||||
* {
|
||||
* "title": "string",
|
||||
* "description": "string",
|
||||
* "visibility": "PRIVATE"
|
||||
* }
|
||||
*
|
||||
* Response:
|
||||
* {
|
||||
* "entry": {
|
||||
* "id": "string",
|
||||
* "guid": "string",
|
||||
* "title": "string",
|
||||
* "description": "string",
|
||||
* "visibility": "PRIVATE",
|
||||
* "preset": "string",
|
||||
* "role": "SiteConsumer"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return the properties of an updated site
|
||||
* @throws Exception
|
||||
*/
|
||||
public RestSiteModel updateSite(SiteModel site) throws Exception
|
||||
{
|
||||
String siteBody = JsonBodyGenerator.updateSiteRequest(site);
|
||||
RestRequest request = RestRequest.requestWithBody(HttpMethod.PUT, siteBody, "sites/{siteId}", site.getId());
|
||||
return restWrapper.processModel(RestSiteModel.class, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get site membership requests by using GET /site-membership-requests
|
||||
*
|
||||
|
@@ -1,10 +1,12 @@
|
||||
package org.alfresco.rest.requests.privateAPI;
|
||||
|
||||
import org.alfresco.rest.core.RestWrapper;
|
||||
import org.alfresco.rest.model.RestCustomTypeModel;
|
||||
import org.alfresco.rest.model.RestSubscriberModel;
|
||||
import org.alfresco.rest.model.RestSyncNodeSubscriptionModel;
|
||||
import org.alfresco.rest.requests.CustomAspectModelManager;
|
||||
import org.alfresco.rest.requests.CustomModelManager;
|
||||
import org.alfresco.rest.requests.CustomTypeManager;
|
||||
import org.alfresco.rest.requests.ModelRequest;
|
||||
import org.alfresco.rest.requests.syncServiceAPI.Healthcheck;
|
||||
import org.alfresco.rest.requests.syncServiceAPI.Subscribers;
|
||||
@@ -38,6 +40,11 @@ public class RestPrivateAPI extends ModelRequest<RestPrivateAPI>
|
||||
return new CustomModelManager(customContentModel, restWrapper);
|
||||
}
|
||||
|
||||
public CustomModelManager usingCustomModel()
|
||||
{
|
||||
return new CustomModelManager(restWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides DSL on all REST calls under <code>cmm/{modelName}/aspects/{aspectName}...</code> API path
|
||||
*
|
||||
@@ -50,6 +57,18 @@ public class RestPrivateAPI extends ModelRequest<RestPrivateAPI>
|
||||
return new CustomAspectModelManager(customContentModel, aspectModel, restWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides DSL on all REST calls under <code>cmm/{modelName}/types/{typeName}...</code> API path
|
||||
*
|
||||
* @param customContentModel {@link CustomContentModel}
|
||||
* @param customType {@link RestCustomTypeModel}
|
||||
* @return {@link CustomTypeManager}
|
||||
*/
|
||||
public CustomTypeManager usingCustomType(CustomContentModel customContentModel, RestCustomTypeModel customType)
|
||||
{
|
||||
return new CustomTypeManager(customContentModel, customType, restWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides DSL on all REST calls under <code>subscribers/</code> API path
|
||||
*
|
||||
|
@@ -35,6 +35,7 @@ public class SearchAPI extends ModelRequest<SearchAPI>
|
||||
public SearchAPI(RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
restWrapper.configureAlfrescoEndpoint();
|
||||
RestAssured.basePath = "alfresco/api/-default-/public/search/versions/1";
|
||||
restWrapper.configureRequestSpec().setBasePath(RestAssured.basePath);
|
||||
}
|
||||
|
@@ -127,6 +127,7 @@ public class SearchSQLAPI extends ModelRequest<SearchSQLAPI>
|
||||
public SearchSQLAPI(RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
restWrapper.configureAlfrescoEndpoint();
|
||||
RestAssured.basePath = "alfresco/api/-default-/public/search/versions/1";
|
||||
restWrapper.configureRequestSpec().setBasePath(RestAssured.basePath);
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ public class ShardInfoAPI extends ModelRequest<ShardInfoAPI>
|
||||
public ShardInfoAPI(RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
restWrapper.configureAlfrescoEndpoint();
|
||||
RestAssured.basePath = "alfresco/api/-default-/private/search/versions/1";
|
||||
restWrapper.configureRequestSpec().setBasePath(RestAssured.basePath);
|
||||
}
|
||||
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Alfresco Software Limited.
|
||||
* This file is part of Alfresco
|
||||
* 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/>.
|
||||
*/
|
||||
package org.alfresco.rest.requests.search;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.rest.core.RestRequest;
|
||||
import org.alfresco.rest.core.RestResponse;
|
||||
import org.alfresco.rest.core.RestWrapper;
|
||||
import org.alfresco.rest.requests.ModelRequest;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.Header;
|
||||
import io.restassured.http.Headers;
|
||||
|
||||
/**
|
||||
* Wrapper for SOLR Admin REST API
|
||||
*
|
||||
* @author aborroy
|
||||
*
|
||||
*/
|
||||
public class SolrAdminAPI extends ModelRequest<SolrAdminAPI>
|
||||
{
|
||||
public SolrAdminAPI(RestWrapper restWrapper)
|
||||
{
|
||||
super(restWrapper);
|
||||
RestAssured.basePath = "solr/admin";
|
||||
|
||||
restWrapper.configureSolrEndPoint();
|
||||
restWrapper.configureRequestSpec().setBasePath(RestAssured.basePath);
|
||||
}
|
||||
|
||||
public RestResponse getAction(String action) throws Exception
|
||||
{
|
||||
List<Header> headers = new ArrayList<Header>();
|
||||
headers.add(new Header("Content-Type", "application/json"));
|
||||
Headers header = new Headers(headers);
|
||||
restWrapper.setResponseHeaders(header);
|
||||
restWrapper.configureRequestSpec().setUrlEncodingEnabled(false);
|
||||
RestRequest request = RestRequest.simpleRequest(HttpMethod.GET,
|
||||
"cores?action=" + action + "&wt=json&{parameters}", restWrapper.getParameters());
|
||||
return restWrapper.process(request);
|
||||
}
|
||||
}
|
@@ -57,6 +57,9 @@ public class RestInstanceModel
|
||||
|
||||
/** Transactions remaining */
|
||||
private Long transactionsRemaining;
|
||||
|
||||
/** Sharding Parameters */
|
||||
private String shardParams;
|
||||
|
||||
/**
|
||||
* @return the baseUrl
|
||||
@@ -233,4 +236,21 @@ public class RestInstanceModel
|
||||
{
|
||||
this.transactionsRemaining = transactionsRemaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the shardParams
|
||||
*/
|
||||
public String getShardParams()
|
||||
{
|
||||
return this.shardParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param shardParams the shardParams to set
|
||||
*/
|
||||
public void setShardParams(String shardParams)
|
||||
{
|
||||
this.shardParams = shardParams;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user