Skip to content

Commit

Permalink
Add a mean to update collection visibility to organisations and publi…
Browse files Browse the repository at this point in the history
…c visibility
  • Loading branch information
alainbodiguel committed Feb 14, 2024
1 parent 2429aba commit 1454575
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 16 deletions.
4 changes: 2 additions & 2 deletions arlas-commons/src/main/resources/roles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ technicalRoles:
- "Building dashboards in ARLAS"
permissions:
- r:collections:GET
- r:collections/.*:PUT,DELETE
- r:collections/.*:PATCH,PUT,DELETE
- r:collections/_export:GET
- r:collections/_import:POST
- r:persist/resource/.*:PUT,POST,DELETE
Expand Down Expand Up @@ -94,7 +94,7 @@ technicalRoles:
- "M2M account for importing collections"
permissions:
- r:collections:GET
- r:collections/.*:PUT,DELETE
- r:collections/.*:PATCH,PUT,DELETE
- r:collections/_import:POST
- r:organisations/.*:GET
- r:persist/resource/.*:POST,PUT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@

import com.fasterxml.jackson.annotation.JsonProperty;

import java.io.Serial;
import java.io.Serializable;

public class CollectionReference implements Serializable {
@Serial
private static final long serialVersionUID = 2270763501550669101L;

public static final String COLLECTION_NAME = "collection_name";
public static final String INDEX_NAME = "index_name";
public static final String ID_PATH = "id_path";
public static final String GEOMETRY_PATH = "geometry_path";
public static final String CENTROID_PATH = "centroid_path";
public static final String H3_PATH = "h3_path";
public static final String TIMESTAMP_PATH = "timestamp_path";
public static final String TIMESTAMP_FORMAT = "timestamp_format";
public static final String DEFAULT_TIMESTAMP_FORMAT = "strict_date_optional_time||epoch_millis";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ public class CollectionReferenceParameters implements Serializable {
@JsonProperty(value = CollectionReference.CENTROID_PATH, required = true)
public String centroidPath;

@JsonProperty(value = CollectionReference.H3_PATH)
public String h3Path;

@NotEmpty
@JsonProperty(value = CollectionReference.TIMESTAMP_PATH, required = true)
public String timestampPath;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Licensed to Gisaïa under one or more contributor
* license agreements. See the NOTICE.txt file distributed with
* this work for additional information regarding copyright
* ownership. Gisaïa licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package io.arlas.server.core.model;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

import static io.arlas.server.core.model.CollectionReference.ORGANISATIONS_PUBLIC;
import static io.arlas.server.core.model.CollectionReference.ORGANISATIONS_SHARED;

public class CollectionReferenceUpdate {
@JsonProperty(value = ORGANISATIONS_PUBLIC, required = false)
public Boolean isPublic;
@JsonProperty(value = ORGANISATIONS_SHARED, required = false)
public List<String> sharedWith;

public CollectionReferenceUpdate() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,23 @@ public CollectionReference putCollectionReference(CollectionReference collection
return collectionReference;
}

public CollectionReference updateCollectionReference(String collection,
String organisations,
String columnFilter,
boolean isPublic,
List<String> sharedWith)
throws ArlasException {
CollectionReference collectionReference = getCollectionReference(collection, Optional.ofNullable(organisations));
ColumnFilterUtil.assertCollectionsAllowed(Optional.ofNullable(columnFilter), List.of(collectionReference));
checkIfAllowedForOrganisations(collectionReference, Optional.ofNullable(organisations), true);
collectionReference.params.collectionOrganisations.isPublic = isPublic;
collectionReference.params.collectionOrganisations.sharedWith = sharedWith;
putCollectionReferenceWithDao(collectionReference);
cacheManager.removeCollectionReference(collectionReference.collectionName);
cacheManager.removeMapping(collectionReference.params.indexName);
return collectionReference;
}

public List<CollectionReferenceDescription> describeAllCollections(List<CollectionReference> collectionReferenceList,
Optional<String> columnFilter) throws CollectionUnavailableException {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import io.arlas.server.core.model.*;
import io.arlas.server.core.services.CollectionReferenceService;
import io.arlas.server.core.utils.CheckParams;
import io.arlas.server.core.utils.CollectionUtil;
import io.arlas.server.core.utils.ColumnFilterUtil;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
Expand All @@ -45,6 +44,8 @@
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
Expand Down Expand Up @@ -158,12 +159,11 @@ public Response importCollections(
removeMetacollection(collections);
Set<String> allowedCollections = ColumnFilterUtil.getAllowedCollections(Optional.ofNullable(columnFilter));
for (CollectionReference collection : collections) {
collectionReferenceService.checkIfAllowedForOrganisations(collection, Optional.ofNullable(organisations), true);
for (String c : allowedCollections) {
if ((c.endsWith("*") && collection.collectionName.startsWith(c.substring(0, c.indexOf("*"))))
|| collection.collectionName.equals(c)) {
try {
savedCollections.add(save(collection.collectionName, collection.params, true));
savedCollections.add(save(collection.collectionName, collection.params, true, organisations));
} catch (Exception e) {
throw new ArlasException(e.getMessage());
}
Expand Down Expand Up @@ -245,10 +245,14 @@ public Response get(
@ApiResponse(code = 404, message = "Not Found Error.", response = Error.class),
@ApiResponse(code = 500, message = "Arlas Server Error.", response = Error.class)})
public Response put(
@ApiParam(hidden = true)
@HeaderParam(value = ARLAS_ORGANISATION) String organisations,

@ApiParam(name = "collection",
value = "collection",
required = true)
@PathParam(value = "collection") String collection,

@ApiParam(name = "collectionParams",
value = "collectionParams",
required = true)
Expand All @@ -269,17 +273,68 @@ public Response put(
if (collection != null && collection.equals(META_COLLECTION_NAME)) {
throw new NotAllowedException("'" + META_COLLECTION_NAME + "' is not allowed as a name for collections");
}
return ResponseFormatter.getResultResponse(save(collection, collectionReferenceParameters, checkFields == null ? Boolean.TRUE : checkFields));
return ResponseFormatter.getResultResponse(save(collection, collectionReferenceParameters,
checkFields == null ? Boolean.TRUE : checkFields, organisations));
}

@Timed
@Path("{collection}/organisations")
@PATCH
@Produces(UTF8JSON)
@Consumes(UTF8JSON)
@ApiOperation(
value = "Update a collection reference's organisations attribute.",
produces = UTF8JSON,
notes = "Update a collection reference's organisations attribute.",
consumes = UTF8JSON,
response = CollectionReference.class
)
@ApiResponses(value = {@ApiResponse(code = 200, message = "Successful operation", response = CollectionReference.class),
@ApiResponse(code = 400, message = "JSON parameter malformed.", response = Error.class),
@ApiResponse(code = 404, message = "Not Found Error.", response = Error.class),
@ApiResponse(code = 500, message = "Arlas Server Error.", response = Error.class)})
public Response patch(
@Context HttpHeaders headers,
@ApiParam(name = "collection",
value = "collection",
required = true)
@PathParam(value = "collection") String collection,

@ApiParam(name = "collectionParamsUpdate",
value = "collectionParamsUpdate",
required = true)
@NotNull CollectionReferenceUpdate cru,

@ApiParam(hidden = true)
@HeaderParam(value = COLUMN_FILTER) String columnFilter,

@ApiParam(hidden = true)
@HeaderParam(value = ARLAS_ORGANISATION) String organisations,
// --------------------------------------------------------
// ----------------------- FORM -----------------------
// --------------------------------------------------------
@ApiParam(name = "pretty",
value = Documentation.FORM_PRETTY,
defaultValue = "false")
@QueryParam(value = "pretty") Boolean pretty

) throws ArlasException {
if (collection != null && collection.equals(META_COLLECTION_NAME)) {
throw new NotAllowedException("'" + META_COLLECTION_NAME + "' cannot be updated");
}
return ResponseFormatter.getResultResponse(collectionReferenceService.updateCollectionReference(collection, organisations, columnFilter, cru.isPublic, cru.sharedWith));
}

public CollectionReference save(String collection, CollectionReferenceParameters collectionReferenceParameters, Boolean checkFields) throws ArlasException {
public CollectionReference save(String collection, CollectionReferenceParameters collectionReferenceParameters,
Boolean checkFields, String organisations) throws ArlasException {
CollectionReference collectionReference = new CollectionReference(collection, collectionReferenceParameters);
setDefaultInspireParameters(collectionReference);
if (inspireConfigurationEnabled) {
CheckParams.checkMissingInspireParameters(collectionReference);
CheckParams.checkInvalidDublinCoreElementsForInspire(collectionReference);
}
CheckParams.checkInvalidInspireParameters(collectionReference);
collectionReferenceService.checkIfAllowedForOrganisations(collectionReference, Optional.ofNullable(organisations), true);
return collectionReferenceService.putCollectionReference(collectionReference, checkFields);
}

Expand Down Expand Up @@ -329,26 +384,26 @@ private void setDefaultInspireParameters(CollectionReference collectionReference
if (collectionReference.params.inspire == null) {
collectionReference.params.inspire = new Inspire();
}
if (collectionReference.params.inspire.keywords == null ||collectionReference.params.inspire.keywords.size() == 0) {
if (collectionReference.params.inspire.keywords == null || collectionReference.params.inspire.keywords.isEmpty()) {
collectionReference.params.inspire.keywords = new ArrayList<>();
Keyword k = new Keyword();
k.value = collectionReference.collectionName;
collectionReference.params.inspire.keywords.add(k);
}
if (collectionReference.params.inspire.inspireUseConditions == null || collectionReference.params.inspire.inspireUseConditions.equals("")) {
if (collectionReference.params.inspire.inspireUseConditions == null || collectionReference.params.inspire.inspireUseConditions.isEmpty()) {
collectionReference.params.inspire.inspireUseConditions = "no conditions apply";
}
if (collectionReference.params.inspire.inspireURI == null) {
collectionReference.params.inspire.inspireURI = new InspireURI();
}
if (collectionReference.params.inspire.inspireURI.code == null || collectionReference.params.inspire.inspireURI.code.equals("")) {
if (collectionReference.params.inspire.inspireURI.code == null || collectionReference.params.inspire.inspireURI.code.isEmpty()) {
collectionReference.params.inspire.inspireURI.code = collectionReference.params.dublinCoreElementName.identifier;
}
if (collectionReference.params.inspire.inspireURI.namespace == null || collectionReference.params.inspire.inspireURI.namespace.equals("")) {
if (collectionReference.params.inspire.inspireURI.namespace == null || collectionReference.params.inspire.inspireURI.namespace.isEmpty()) {
collectionReference.params.inspire.inspireURI.namespace = "ARLAS." + collectionReference.collectionName.toUpperCase();
}
//a default language must be specified
if (collectionReference.params.inspire.languages == null || collectionReference.params.inspire.languages.size() == 0) {
if (collectionReference.params.inspire.languages == null || collectionReference.params.inspire.languages.isEmpty()) {
collectionReference.params.inspire.languages = new ArrayList<>();
collectionReference.params.inspire.languages.add("eng");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,55 @@ public void test08WithCollectionFilter() throws Exception {

}

@Test
public void test09Organisations() throws Exception {
Map<String, Object> jsonAsMap = getJsonAsMap("bar.com", null, false);
jsonAsMap.put(CollectionReference.INSPIRE_PATH, getInspireJsonAsMap());
jsonAsMap.put(CollectionReference.DUBLIN_CORE_PATH, getDublinJsonAsMap());

// PUT new collection
given().contentType("application/json")
.body(jsonAsMap)
.when().put(arlasPath + "collections/bar")
.then().statusCode(200);

// GET collection
when().get(arlasPath + "collections/bar")
.then().statusCode(200)
.body("collection_name", equalTo("bar"))
.body("params.index_name", equalTo(DataSetTool.DATASET_INDEX_NAME))
.body("params.id_path", equalTo(DataSetTool.DATASET_ID_PATH))
.body("params.geometry_path", equalTo(DataSetTool.DATASET_GEOMETRY_PATH))
.body("params.centroid_path", equalTo(DataSetTool.DATASET_CENTROID_PATH))
.body("params.timestamp_path", equalTo(DataSetTool.DATASET_TIMESTAMP_PATH))
.body("params.exclude_fields", equalTo(DataSetTool.DATASET_EXCLUDE_FIELDS))
.body("params.exclude_wfs_fields", equalTo(DataSetTool.DATASET_EXCLUDE_WFS_FIELDS))
.body("params.organisations.owner", equalTo("bar.com"))
.body("params.organisations.shared", hasSize(0))
.body("params.organisations.public", equalTo(Boolean.FALSE));

// PATCH collection
given().contentType("application/json")
.body(getOrgAsMap(null, List.of("foo.com"), Boolean.TRUE))
.when().patch(arlasPath + "collections/bar/organisations")
.then().statusCode(200)
.body("collection_name", equalTo("bar"))
.body("params.index_name", equalTo(DataSetTool.DATASET_INDEX_NAME))
.body("params.id_path", equalTo(DataSetTool.DATASET_ID_PATH))
.body("params.geometry_path", equalTo(DataSetTool.DATASET_GEOMETRY_PATH))
.body("params.centroid_path", equalTo(DataSetTool.DATASET_CENTROID_PATH))
.body("params.timestamp_path", equalTo(DataSetTool.DATASET_TIMESTAMP_PATH))
.body("params.exclude_fields", equalTo(DataSetTool.DATASET_EXCLUDE_FIELDS))
.body("params.exclude_wfs_fields", equalTo(DataSetTool.DATASET_EXCLUDE_WFS_FIELDS))
.body("params.organisations.owner", equalTo("bar.com"))
.body("params.organisations.shared", hasItems("foo.com"))
.body("params.organisations.public", equalTo(Boolean.TRUE));

// DELETE collection
when().delete(arlasPath + "collections/bar")
.then().statusCode(200);

}

private void handleInvalidCollectionParameters(ValidatableResponse then) throws Exception {
then.statusCode(400);
Expand All @@ -380,6 +429,10 @@ private ValidatableResponse put(Map<String, Object> jsonAsMap) {
}

private Map<String, Object> getJsonAsMap() {
return getJsonAsMap(null, null, null);
}

private Map<String, Object> getJsonAsMap(String orgOwner, List<String> orgShared, Boolean isPublic) {
Map<String, Object> jsonAsMap = new HashMap<>();
jsonAsMap.put(CollectionReference.INDEX_NAME, DataSetTool.DATASET_INDEX_NAME);
jsonAsMap.put(CollectionReference.ID_PATH, DataSetTool.DATASET_ID_PATH);
Expand All @@ -388,9 +441,22 @@ private Map<String, Object> getJsonAsMap() {
jsonAsMap.put(CollectionReference.TIMESTAMP_PATH, DataSetTool.DATASET_TIMESTAMP_PATH);
jsonAsMap.put(CollectionReference.EXCLUDE_FIELDS, DataSetTool.DATASET_EXCLUDE_FIELDS);
jsonAsMap.put(CollectionReference.EXCLUDE_WFS_FIELDS, DataSetTool.DATASET_EXCLUDE_WFS_FIELDS);
if (orgOwner != null) {
jsonAsMap.put(CollectionReference.ORGANISATIONS, getOrgAsMap(orgOwner, orgShared, isPublic));
}
return jsonAsMap;
}

private Map<String, Object> getOrgAsMap(String orgOwner, List<String> orgShared, Boolean isPublic) {
Map<String, Object> orgAsMap = new HashMap<>();
if (orgOwner != null) {
orgAsMap.put(CollectionReference.ORGANISATIONS_OWNER, orgOwner);
}
orgAsMap.put(CollectionReference.ORGANISATIONS_SHARED, Objects.requireNonNullElse(orgShared, Collections.emptyList()));
orgAsMap.put(CollectionReference.ORGANISATIONS_PUBLIC, Objects.requireNonNullElse(isPublic, Boolean.FALSE));
return orgAsMap;
}

private Object getCollectionDescriptionJsonAsMap() {
Map<String, Object> jsonAsMap = new HashMap<>();
jsonAsMap.put(CollectionReference.COLLECTION_DISPLAY_NAME, DataSetTool.DATASET_COLLECTION_DISPLAY_NAME);
Expand Down

0 comments on commit 1454575

Please sign in to comment.