Commit 968e612c authored by neelesh thakur's avatar neelesh thakur
Browse files

rebase

parents ac4e98ba 35f068a4
Pipeline #30147 failed with stages
in 48 minutes and 42 seconds
......@@ -55,13 +55,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
200:
description: "All kinds retrieved successfully."
......@@ -113,13 +106,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
200:
description: "Record Ids retrieved successfully."
......@@ -157,13 +143,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
200:
description: "Fetch multiple records successfully."
......@@ -204,13 +183,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
204:
description: "Record deleted successfully."
......@@ -258,13 +230,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
200:
description: "Record retrieved successfully."
......@@ -303,13 +268,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
204:
description: "Record purged successfully."
......@@ -363,13 +321,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
200:
description: "Record retrieved successfully."
......@@ -409,13 +360,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
200:
description: "Record versions retrieved successfully."
......@@ -466,13 +410,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
201:
description: "Records created and/or updated successfully."
......@@ -491,6 +428,51 @@ paths:
schema:
$ref: "#/definitions/AppError"
security:
- datalake_auth:
- "email"
- Bearer: []
patch:
tags:
- "records"
summary: "Modify record metadata attributes using patch operations"
description: "The API represents the patch update mechanism for records. It allows\
\ updating multiple records in one request. It supports legal tags, ACLs or tags\
\ updates at the moment. For the legal tags and ACLs only replace operation supported.\
\ For tags update replace, add and remove operation allowed."
operationId: "Patch update records"
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- in: "body"
name: "body"
required: false
schema:
type: "array"
items:
$ref: "#/definitions/RecordBulkUpdateParam"
- name: "OSDU-Account-Id"
in: "header"
description: "Account ID is the active OSDU account (OSDU account or customer's\
\ account) which the users choose to use with the Search API."
required: true
type: "string"
default: "tenant1"
responses:
200:
description: "Records updated successfully."
schema:
$ref: "#/definitions/BulkUpdateRecordsResponse"
206:
description: "Records updated successful partially."
schema:
$ref: "#/definitions/BulkUpdateRecordsResponse"
403:
description: "User not authorized to perform the action."
schema:
$ref: "#/definitions/AppError"
security:
- datalake_auth:
- "email"
- Bearer: []
......@@ -521,13 +503,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
200:
description: "Schema obtained successfully."
......@@ -570,13 +545,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
204:
description: "Schema deleted successfully."
......@@ -617,13 +585,6 @@ paths:
required: true
type: "string"
default: "tenant1"
- name: "OSDU-On-Behalf-Of"
in: "header"
description: "On behalf email or token is the token/email of the original\
\ user making the call. For now, only email is supported but eventually,\
\ primary usage will be token."
required: false
type: "string"
responses:
201:
description: "Schema created successfully."
......@@ -912,4 +873,99 @@ definitions:
- "boolean"
- "link"
- "datetime."
description: "Schema item which describes schema properties and their data types."
\ No newline at end of file
description: "Schema item which describes schema properties and their data types."
RecordBulkUpdateParam:
type: "object"
required:
- "query"
- "ops"
properties:
query:
description: "Patch update query information"
allowEmptyValue: false
$ref: "#/definitions/RecordQuery"
ops:
type: "array"
description: "List of operations for records pathc update"
allowEmptyValue: false
items:
$ref: "#/definitions/PatchOperation"
description: "Patch update input information"
example:
query:
- ids:
- "recordId1"
- "recordId2"
ops:
- op: "replace"
path: "/path1"
value:
- "value1"
- "value2"
- "value3"
- op: "replace"
path: "/path2"
value:
- "value4"
- "value5"
- "value6"
RecordQuery:
type: "object"
required:
- "ids"
properties:
ids:
type: "array"
description: "Records ids for whom patch operations going to be applied"
description: "Patch api query specific information"
PatchOperation:
type: "object"
required:
- "op"
- "path"
- "value"
properties:
op:
type: "string"
description: "Type of patch operation"
enum:
- "add"
- "replace"
- "remove"
path:
type: "string"
description: "Path for batch operation"
value:
type: "array"
description: "Path for batch operation"
items:
type: "string"
description: "Patch api operation specific information"
BulkUpdateRecordsResponse:
type: "object"
properties:
recordCount:
type: "integer"
format: "int32"
description: "Number of records which updated successfully."
recordIds:
type: "array"
description: "List of successfully updated record ids."
items:
type: "string"
notFoundRecordIds:
type: "array"
description: "List of record ids for whom RecordMetadata was not found"
items:
type: "string"
unAuthorizedRecordIds:
type: "array"
description: "List of record ids for whom user does not has owner permissions"
items:
type: "string"
lockedRecordIds:
type: "array"
description: "List of locked record ids"
items:
type: "string"
description: "Result of the record batch update request."
\ No newline at end of file
......@@ -33,6 +33,8 @@
- [Get record <a name="Retrieve-latest-record-version"></a>](#get-record)
- [Parameters <a name="parameters"></a>](#parameters-2)
- [Delete record <a name="Delete-record"></a>](#delete-record)
- [Patch api <a name="patch"></a>](#patch)
- [Update batch of records with patch api <a name="patch-api-update"></a>](#patch-update)
- [Using service accounts to access Storage APIs <a name="Service-accounts"></a>](#using-service-accounts-to-access-storage-apis)
- [Using skipdupes <a name="skipdupes"></a>](#using-skipdupes)
......@@ -450,6 +452,82 @@ curl --request POST \
```
</details>
## Tags <a name="patch"></a>
### Append or Update record tags <a name="patch-api-update"></a>
The API patch records updates. It allows updating following attributes of the record metadata:
1. ACLs (only replace operation supported)
1. Legal tags (only replace operation supported)
1. Tags (add, replace, remove operation supported)
If we need add or replace tags ops.value should be colon separated string value, e.g.:
```
"ops": [
{
"op":"replace",
"path":"/tags",
"value":[
"key1:value1",
"key2:value2",
"key3:value3"
]
}
```
If we need remove tags ops.value should be array of the tags keys which we are going to remove, e.g.:
```
"ops": [
{
"op":"remove",
"path":"/tags",
"value":[
"key1",
"key2",
"key3"
]
}
```
```
PATCH /api/storage/records
```
<details><summary>curl</summary>
```
curl --request PACTH \
--url '/api/storage/v2/records' \
--header 'accept: application/json' \
--header 'authorization: Bearer <JWT>' \
--header 'content-type: application/json' \
--header 'Data-Partition-Id: common'
--data '{
"query": {
"ids": [
"common:well:123456789",
"common:wellTop:abc789456",
"common:wellLog:4531wega22"
],
}
"ops": [
{
"op":"replace",
"path":"/path1",
"value":[
"value1",
"value2",
"value3"
]
},
{
"op":"add",
"path":"/path2",
"value":[
"value4",
"value5",
"value6"
]
}
]
}
```
</details>
## Using service accounts to access Storage APIs <a name="Service-accounts"></a>
The Storage service relies on the Google native data access authorization mechanisms to provide access control on the records.
......
......@@ -46,6 +46,7 @@
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-core-common</artifactId>
<version>0.6.9</version>
</dependency>
<dependency>
......
......@@ -16,6 +16,7 @@ package org.opengroup.osdu.storage.api;
import javax.validation.Valid;
import org.opengroup.osdu.storage.service.BulkUpdateRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
......@@ -28,7 +29,6 @@ import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.storage.RecordBulkUpdateParam;
import org.opengroup.osdu.core.common.model.storage.StorageRole;
import org.opengroup.osdu.storage.response.BulkUpdateRecordsResponse;
import org.opengroup.osdu.storage.service.RecordService;
@RestController
@RequestMapping("records")
......@@ -40,12 +40,12 @@ public class PatchApi {
private DpsHeaders headers;
@Autowired
private RecordService recordService;
private BulkUpdateRecordService bulkUpdateRecordService;
@PatchMapping()
@PreAuthorize("@authorizationFilter.hasRole('" + StorageRole.CREATOR + "', '" + StorageRole.ADMIN + "')")
public ResponseEntity<BulkUpdateRecordsResponse> updateRecordsMetadata(@RequestBody @Valid RecordBulkUpdateParam recordBulkUpdateParam) {
BulkUpdateRecordsResponse response = this.recordService.bulkUpdateRecords(recordBulkUpdateParam, this.headers.getUserEmail());
BulkUpdateRecordsResponse response = this.bulkUpdateRecordService.bulkUpdateRecords(recordBulkUpdateParam, this.headers.getUserEmail());
if (!response.getLockedRecordIds().isEmpty() || !response.getNotFoundRecordIds().isEmpty() || !response.getUnAuthorizedRecordIds().isEmpty()) {
return new ResponseEntity<>(response, HttpStatus.PARTIAL_CONTENT);
} else {
......
// Copyright 2017-2021, Schlumberger
//
// Licensed 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 org.opengroup.osdu.storage.di;
import static java.time.Clock.systemDefaultZone;
import java.time.Clock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.gson.Gson;
@Configuration
public class BeanConfig {
@Bean
public Clock clock() {
return systemDefaultZone();
}
@Bean
public Gson gson() {
return new Gson();
}
}
// Copyright 2017-2021, Schlumberger
//
// Licensed 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 org.opengroup.osdu.storage.service;
import org.opengroup.osdu.core.common.model.storage.RecordBulkUpdateParam;
import org.opengroup.osdu.storage.response.BulkUpdateRecordsResponse;
public interface BulkUpdateRecordService {
BulkUpdateRecordsResponse bulkUpdateRecords(RecordBulkUpdateParam recordBulkUpdateParam, String user);
}
\ No newline at end of file
// Copyright 2017-2021, Schlumberger
//
// Licensed 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 org.opengroup.osdu.storage.service;
import org.opengroup.osdu.core.common.entitlements.IEntitlementsAndCacheService;
import org.opengroup.osdu.core.common.model.http.DpsHeaders;
import org.opengroup.osdu.core.common.model.indexer.OperationType;
import org.opengroup.osdu.core.common.model.storage.PatchOperation;
import org.opengroup.osdu.core.common.model.storage.RecordBulkUpdateParam;
import org.opengroup.osdu.core.common.model.storage.RecordMetadata;
import org.opengroup.osdu.core.common.model.storage.RecordQuery;
import org.opengroup.osdu.core.common.storage.IPersistenceService;
import org.opengroup.osdu.storage.logging.StorageAuditLogger;
import org.opengroup.osdu.storage.policy.service.IPolicyService;
import org.opengroup.osdu.storage.provider.interfaces.IRecordsMetadataRepository;
import org.opengroup.osdu.storage.response.BulkUpdateRecordsResponse;
import org.opengroup.osdu.storage.util.api.RecordUtil;
import org.opengroup.osdu.storage.validation.api.PatchOperationValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.Clock;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
@Service
public class BulkUpdateRecordServiceImpl implements BulkUpdateRecordService {
@Autowired
private IRecordsMetadataRepository recordRepository;
@Autowired
private PatchOperationValidator patchOperationValidator;
@Autowired
private IEntitlementsAndCacheService entitlementsAndCacheService;
@Autowired
private StorageAuditLogger auditLogger;
@Autowired
private IPersistenceService persistenceService;
@Autowired
private DpsHeaders headers;
@Autowired
private RecordUtil recordUtil;
@Autowired
private Clock clock;
@Autowired
private DataAuthorizationService dataAuthorizationService;
@Autowired(required = false)