diff --git a/postman.json b/postman.json index d0d1aa0f..796643d0 100644 --- a/postman.json +++ b/postman.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "f1e394b5-5489-4662-9683-359fa4b8ad3e", + "_postman_id": "51273dbf-d56a-49f4-b8a6-de33f9fb30e7", "name": "tc-project-service", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -1978,14 +1978,13 @@ { "listen": "test", "script": { - "id": "b2961136-d13b-4780-841b-5b3d9e49ee10", + "type": "text/javascript", "exec": [ "pm.test(\"Status code is 201\", function () {", " pm.response.to.have.status(201);", " pm.environment.set(\"WorkStreamId\", pm.response.json().result.content.id);", "});" - ], - "type": "text/javascript" + ] } } ], @@ -2258,14 +2257,13 @@ { "listen": "test", "script": { - "id": "55d7752f-f0de-41f8-8100-6bf2c8464ad0", + "type": "text/javascript", "exec": [ "pm.test(\"Status code is 201\", function () {", " pm.response.to.have.status(201);", " pm.environment.set(\"WorkId\", pm.response.json().result.content.id);", "});" - ], - "type": "text/javascript" + ] } } ], @@ -2692,14 +2690,13 @@ { "listen": "test", "script": { - "id": "f3729ae5-d926-490d-a11b-4843ec956db9", + "type": "text/javascript", "exec": [ "pm.test(\"Status code is 201\", function () {", " pm.response.to.have.status(201);", " pm.environment.set(\"ItemId\", pm.response.json().result.content.id);", "});" - ], - "type": "text/javascript" + ] } } ], @@ -2861,38 +2858,618 @@ "v4", "projects", "1", - "workstreams", - "{{WorkStreamId}}", - "works", - "{{WorkId}}", - "workitems", - "{{ItemId}}" + "workstreams", + "{{WorkStreamId}}", + "works", + "{{WorkId}}", + "workitems", + "{{ItemId}}" + ] + }, + "description": "Delete a project by id" + }, + "response": [] + }, + { + "name": "Update work item", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t\t\"name\": \"work item - updated\"\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/1/workstreams/{{WorkStreamId}}/works/{{WorkId}}/workitems/{{ItemId}}", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "1", + "workstreams", + "{{WorkStreamId}}", + "works", + "{{WorkId}}", + "workitems", + "{{ItemId}}" + ] + }, + "description": "Update the project name. Name should be updated successfully." + }, + "response": [] + } + ], + "description": "Requests for all things projects." + }, + { + "name": "Work Management Permission", + "item": [ + { + "name": "Create work management permission without payload", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ] + }, + "description": "Request body is mandatory while creating project. If invalid request body is supplied this should return 422 status code." + }, + "response": [] + }, + { + "name": "Create work management permission without valid name", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ] + }, + "description": "Certain fields are mandatory while creating project. If invalid request body is supplied this should return 422 status code." + }, + "response": [] + }, + { + "name": "Create work management permission with valid values", + "event": [ + { + "listen": "test", + "script": { + "id": "305f3d68-6e9f-4c4d-b031-7487986a93e2", + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + " pm.environment.set(\"workManagementPermissionId\", pm.response.json().result.content.id);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n \"policy\": \"work.new.create\",\n \"permission\": {\n \"allowRule\": {\n \"projectRoles\": [\"customer\", \"copilot\"],\n \"topcoderRoles\": [\"Connect Manager\", \"Connect Admin\", \"administrator\"]\n },\n \"denyRule\": { \"projectRoles\": [\"copilot\"] }\n },\n \"projectTemplateId\": 1\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ] + }, + "description": "Valid request body. Project should be created successfully." + }, + "response": [] + }, + { + "name": "Create work management permission with valid values", + "event": [ + { + "listen": "test", + "script": { + "id": "305f3d68-6e9f-4c4d-b031-7487986a93e2", + "exec": [ + "pm.test(\"Status code is 201\", function () {", + " pm.response.to.have.status(201);", + " pm.environment.set(\"workManagementPermissionId\", pm.response.json().result.content.id);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n \"policy\": \"work.new.create\",\n \"permission\": {\n \"allowRule\": {\n \"projectRoles\": [\"customer\", \"copilot\"],\n \"topcoderRoles\": [\"Connect Manager\", \"Connect Admin\", \"administrator\"]\n },\n \"denyRule\": { \"projectRoles\": [\"copilot\"] }\n },\n \"projectTemplateId\": 2\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ] + }, + "description": "Valid request body. Project should be created successfully." + }, + "response": [] + }, + { + "name": "Create work management permission by inactive user", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer userId_{{inactive-userId}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n \"policy\": \"work.create\",\n \"permission\": {\n \"allowRule\": {\n \"projectRoles\": [\"customer\", \"copilot\"],\n \"topcoderRoles\": [\"Connect Manager\", \"Connect Admin\", \"administrator\"]\n },\n \"denyRule\": { \"projectRoles\": [\"copilot\"] }\n },\n \"projectTemplateId\": 1\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ] + }, + "description": "Valid request body. Project should be created successfully." + }, + "response": [] + }, + { + "name": "Get work management permission by id", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission/{{workManagementPermissionId}}", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission", + "{{workManagementPermissionId}}" + ] + }, + "description": "Get a project by id. project members and attachments should also be returned." + }, + "response": [] + }, + { + "name": "List work management permissions - filter required", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ] + }, + "description": "List all the project with no filter. Default sort and limits are applied." + }, + "response": [] + }, + { + "name": "List work management permissions - missing filter", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission?filter=template", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ], + "query": [ + { + "key": "filter", + "value": "template" + } + ] + }, + "description": "List all the project with no filter. Default sort and limits are applied." + }, + "response": [] + }, + { + "name": "List work management permissions - invalid filter", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission?filter=invalid%3D2%26projectTemplateId%3D1", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ], + "query": [ + { + "key": "filter", + "value": "invalid%3D2%26projectTemplateId%3D1" + } + ] + }, + "description": "List all the project with no filter. Default sort and limits are applied." + }, + "response": [] + }, + { + "name": "List work management permissions", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission?filter=projectTemplateId%3D1", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission" + ], + "query": [ + { + "key": "filter", + "value": "projectTemplateId%3D1" + } + ] + }, + "description": "List all the project with no filter. Default sort and limits are applied." + }, + "response": [] + }, + { + "name": "Update work management permission", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n \"policy\": \"work.new.delete\",\n \"permission\": {\n \"allowRule\": {\n \"projectRoles\": [\"customer\", \"copilot\"],\n \"topcoderRoles\": [\"Connect Manager\", \"Connect Admin\", \"administrator\"]\n },\n \"denyRule\": { \"projectRoles\": [\"copilot\"] }\n },\n \"projectTemplateId\": 1\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission/{{workManagementPermissionId}}", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission", + "{{workManagementPermissionId}}" + ] + }, + "description": "Update the project name. Name should be updated successfully." + }, + "response": [] + }, + { + "name": "Delete work management permission by id", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{api-url}}/v4/projects/metadata/workManagementPermission/{{workManagementPermissionId}}", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "metadata", + "workManagementPermission", + "{{workManagementPermissionId}}" + ] + }, + "description": "Delete a project by id" + }, + "response": [] + } + ], + "description": "Requests for all things projects." + }, + { + "name": "Permissions", + "item": [ + { + "name": "Get permissions - 404", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "url": { + "raw": "{{api-url}}/v4/projects/9999/permissions", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "9999", + "permissions" + ] + }, + "description": "List all the project with no filter. Default sort and limits are applied." + }, + "response": [] + }, + { + "name": "Create project invite for customer with valid values", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t\t\"userIds\": [40051331],\n\t\t\"role\": \"customer\"\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/1/members/invite", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "1", + "members", + "invite" + ] + }, + "description": "If the request payload is valid, than project customer should be added. This should sync with the direct project is project is associated with direct project." + }, + "response": [] + }, + { + "name": "Update project invite to accept invite", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token-member-40051331}}" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"param\": {\n\t\t\"userId\": 40051331,\n\t\t\"status\": \"accepted\"\n\t}\n}" + }, + "url": { + "raw": "{{api-url}}/v4/projects/1/members/invite", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "1", + "members", + "invite" + ] + }, + "description": "If the request payload is valid, than project customer should be added. This should sync with the direct project is project is associated with direct project." + }, + "response": [] + }, + { + "name": "Get permissions", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{jwt-token}}" + } + ], + "url": { + "raw": "{{api-url}}/v4/projects/1/permissions", + "host": [ + "{{api-url}}" + ], + "path": [ + "v4", + "projects", + "1", + "permissions" ] }, - "description": "Delete a project by id" + "description": "List all the project with no filter. Default sort and limits are applied." }, "response": [] }, { - "name": "Update work item", + "name": "Get permissions - manager", "request": { - "method": "PATCH", + "method": "GET", "header": [ { "key": "Authorization", - "value": "Bearer {{jwt-token}}" - }, - { - "key": "Content-Type", - "value": "application/json" + "value": "Bearer {{jwt-token-manager-40051334}}" } ], - "body": { - "mode": "raw", - "raw": "{\n\t\"param\": {\n\t\t\"name\": \"work item - updated\"\n\t}\n}" - }, "url": { - "raw": "{{api-url}}/v4/projects/1/workstreams/{{WorkStreamId}}/works/{{WorkId}}/workitems/{{ItemId}}", + "raw": "{{api-url}}/v4/projects/1/permissions", "host": [ "{{api-url}}" ], @@ -2900,20 +3477,36 @@ "v4", "projects", "1", - "workstreams", - "{{WorkStreamId}}", - "works", - "{{WorkId}}", - "workitems", - "{{ItemId}}" + "permissions" ] }, - "description": "Update the project name. Name should be updated successfully." + "description": "List all the project with no filter. Default sort and limits are applied." }, "response": [] } ], - "description": "Requests for all things projects." + "event": [ + { + "listen": "prerequest", + "script": { + "id": "5197d1ec-429c-4a6f-9e9c-3ec3cd6f292a", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "cc0cbbf1-54d1-481f-b8fa-a6dc4c80e993", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] }, { "name": "WorkManagementForTemplate", @@ -2924,14 +3517,13 @@ { "listen": "test", "script": { - "id": "b2961136-d13b-4780-841b-5b3d9e49ee10", + "type": "text/javascript", "exec": [ "pm.test(\"Status code is 201\", function () {", " pm.response.to.have.status(201);", " pm.environment.set(\"WorkStreamId1\", pm.response.json().result.content.id);", "});" - ], - "type": "text/javascript" + ] } } ], @@ -3148,14 +3740,13 @@ { "listen": "test", "script": { - "id": "b2961136-d13b-4780-841b-5b3d9e49ee10", + "type": "text/javascript", "exec": [ "pm.test(\"Status code is 201\", function () {", " pm.response.to.have.status(201);", " pm.environment.set(\"WorkStreamId2\", pm.response.json().result.content.id);", "});" - ], - "type": "text/javascript" + ] } } ], @@ -3495,28 +4086,6 @@ }, "response": [] } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "id": "ef96ac6a-0fc0-4a64-a4fe-5390e17afe67", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "12f9d794-0872-4058-aafa-77b89e72025b", - "type": "text/javascript", - "exec": [ - "" - ] - } - } ] }, { @@ -5391,38 +5960,6 @@ }, "response": [] } - ], - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJhZG1pbmlzdHJhdG9yIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJwc2hhaDEiLCJleHAiOjI0NjI0OTQ2MTgsInVzZXJJZCI6IjQwMTM1OTc4IiwiaWF0IjoxNDYyNDk0MDE4LCJlbWFpbCI6InBzaGFoMUB0ZXN0LmNvbSIsImp0aSI6ImY0ZTFhNTE0LTg5ODAtNDY0MC04ZWM1LWUzNmUzMWE3ZTg0OSJ9.XuNN7tpMOXvBG1QwWRQROj7NfuUbqhkjwn39Vy4tR5I", - "type": "string" - } - ] - }, - "event": [ - { - "listen": "prerequest", - "script": { - "id": "f0092ef5-e624-4c25-87b2-b6a9e4c81ec8", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "9183c429-a5e0-4bf9-96a2-89f4d66e9b0d", - "type": "text/javascript", - "exec": [ - "" - ] - } - } ] }, { @@ -6938,16 +7475,6 @@ { "name": "Get all metadata", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [ { @@ -6973,16 +7500,6 @@ { "name": "Get all metadata with includeAllVersion", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7013,16 +7530,6 @@ { "name": "List forms", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7045,16 +7552,6 @@ { "name": "Get a particular version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7078,16 +7575,6 @@ { "name": "Get latest version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7109,16 +7596,6 @@ { "name": "Create form", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -7152,16 +7629,6 @@ { "name": "Update form", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "PATCH", "header": [ { @@ -7196,16 +7663,6 @@ { "name": "Delete form", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "DELETE", "header": [ { @@ -7245,16 +7702,6 @@ { "name": "List all revision for version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7279,16 +7726,6 @@ { "name": "Get a particular revision", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7314,16 +7751,6 @@ { "name": "Create form", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -7359,16 +7786,6 @@ { "name": "Create for no exist key", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -7404,16 +7821,6 @@ { "name": "Delete revision", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "DELETE", "header": [ { @@ -7455,16 +7862,6 @@ { "name": "List price configs", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7487,16 +7884,6 @@ { "name": "Get a particular version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7520,16 +7907,6 @@ { "name": "Get latest version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7551,16 +7928,6 @@ { "name": "Create priceConfig", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -7594,16 +7961,6 @@ { "name": "Update priceConfig", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "PATCH", "header": [ { @@ -7638,16 +7995,6 @@ { "name": "Delete priceConfig", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "DELETE", "header": [ { @@ -7679,28 +8026,6 @@ }, "response": [] } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "id": "59182724-4332-4d76-90ea-f7520a7b1be9", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "abc13dca-e8a4-4995-970f-00e5889a5f2d", - "type": "text/javascript", - "exec": [ - "" - ] - } - } ] }, { @@ -7709,16 +8034,6 @@ { "name": "List all revision for version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7743,16 +8058,6 @@ { "name": "Get a particular revision", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7778,16 +8083,6 @@ { "name": "Create price config", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -7823,16 +8118,6 @@ { "name": "Create for no exist key", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -7868,16 +8153,6 @@ { "name": "Delete revision", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "DELETE", "header": [ { @@ -7919,16 +8194,6 @@ { "name": "List plan configs", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7951,16 +8216,6 @@ { "name": "Get a particular version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -7984,16 +8239,6 @@ { "name": "Get latest version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -8015,16 +8260,6 @@ { "name": "Create plan config", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -8058,16 +8293,6 @@ { "name": "Update plan config", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "PATCH", "header": [ { @@ -8102,16 +8327,6 @@ { "name": "Delete plan config", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "DELETE", "header": [ { @@ -8151,16 +8366,6 @@ { "name": "List all revision for version", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -8185,16 +8390,6 @@ { "name": "Get a particular revision", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "GET", "header": [], "url": { @@ -8220,16 +8415,6 @@ { "name": "Create plan config", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -8265,16 +8450,6 @@ { "name": "Create for no exist key", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "POST", "header": [ { @@ -8310,16 +8485,6 @@ { "name": "Delete revision", "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw", - "type": "string" - } - ] - }, "method": "DELETE", "header": [ { @@ -8533,4 +8698,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/permissions/index.js b/src/permissions/index.js index a5a81446..f27346da 100644 --- a/src/permissions/index.js +++ b/src/permissions/index.js @@ -117,4 +117,12 @@ module.exports = () => { Authorizer.setPolicy('workItem.edit', workManagementPermissions('workItem.edit')); Authorizer.setPolicy('workItem.delete', workManagementPermissions('workItem.delete')); Authorizer.setPolicy('workItem.view', projectView); + + // Work management permission + Authorizer.setPolicy('workManagementPermission.create', projectAdmin); + Authorizer.setPolicy('workManagementPermission.edit', projectAdmin); + Authorizer.setPolicy('workManagementPermission.delete', projectAdmin); + Authorizer.setPolicy('workManagementPermission.view', projectAdmin); + + Authorizer.setPolicy('permissions.view', projectView); }; diff --git a/src/routes/index.js b/src/routes/index.js index 2ac3c21f..eb2fce43 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -65,6 +65,10 @@ router.route('/v4/projects/metadata/productCategories') router.route('/v4/projects/metadata/productCategories/:key') .get(require('./productCategories/get')); +router.route('/v4/projects/metadata/workManagementPermission') + .get(require('./workManagementPermissions/list')); +router.route('/v4/projects/metadata/workManagementPermission/:id') + .get(require('./workManagementPermissions/get')); router.use('/v4/projects/metadata', compression()); router.route('/v4/projects/metadata') @@ -109,6 +113,10 @@ router.route('/v4/projects/:projectId(\\d+)/members/:id(\\d+)') .delete(require('./projectMembers/delete')) .patch(require('./projectMembers/update')); +// Permissions +router.route('/v4/projects/:projectId(\\d+)/permissions') + .get(require('./permissions/get')); + router.route('/v4/projects/:projectId(\\d+)/attachments') .post(require('./attachments/create')); @@ -165,6 +173,13 @@ router.route('/v4/projects/metadata/productCategories/:key') .patch(require('./productCategories/update')) .delete(require('./productCategories/delete')); +router.route('/v4/projects/metadata/workManagementPermission') + .post(require('./workManagementPermissions/create')); + +router.route('/v4/projects/metadata/workManagementPermission/:id') + .patch(require('./workManagementPermissions/update')) + .delete(require('./workManagementPermissions/delete')); + router.route('/v4/projects/metadata/projectTypes') .post(require('./projectTypes/create')); diff --git a/src/routes/permissions/get.js b/src/routes/permissions/get.js new file mode 100644 index 00000000..01ea6fc4 --- /dev/null +++ b/src/routes/permissions/get.js @@ -0,0 +1,65 @@ +/** + * API to get project permissions + */ +import validate from 'express-validation'; +import Joi from 'joi'; +import { middleware as tcMiddleware } from 'tc-core-library-js'; +import util from '../../util'; +import models from '../../models'; + +const permissions = tcMiddleware.permissions; + +const schema = { + params: { + projectId: Joi.number().integer().positive().required(), + }, +}; + +module.exports = [ + validate(schema), + permissions('permissions.view'), + (req, res, next) => { + const projectId = req.params.projectId; + return models.Project.findOne({ + where: { + id: projectId, + }, + }) + .then((project) => { + if (!project) { + const apiErr = new Error(`Project not found for id ${projectId}`); + apiErr.status = 404; + return Promise.reject(apiErr); + } + + if (!project.templateId) { + return Promise.resolve([]); + } + + return models.WorkManagementPermission.findAll({ + where: { + projectTemplateId: project.templateId, + }, + }); + }) + .then((workManagementPermissions) => { + const allowPermissions = {}; + + // find all allowed permissions + workManagementPermissions.forEach((workManagementPermission) => { + const isAllowed = util.hasPermission( + workManagementPermission.permission, + req.authUser, + req.context.currentProjectMembers, + ); + + if (isAllowed) { + allowPermissions[workManagementPermission.policy] = true; + } + }); + + res.json(util.wrapResponse(req.id, allowPermissions)); + }) + .catch(next); + }, +]; diff --git a/src/routes/permissions/get.spec.js b/src/routes/permissions/get.spec.js new file mode 100644 index 00000000..06e23482 --- /dev/null +++ b/src/routes/permissions/get.spec.js @@ -0,0 +1,231 @@ +/* eslint-disable no-unused-expressions */ +/** + * Tests for get.js + */ +import _ from 'lodash'; +import chai from 'chai'; +import request from 'supertest'; + +import models from '../../models'; +import server from '../../app'; +import testUtil from '../../tests/util'; + +chai.should(); + +describe('GET permissions', () => { + let projectId; + let templateId; + + const memberUser = { + handle: testUtil.getDecodedToken(testUtil.jwts.member).handle, + userId: testUtil.getDecodedToken(testUtil.jwts.member).userId, + firstName: 'fname', + lastName: 'lName', + email: 'some@abc.com', + }; + const copilotUser = { + handle: testUtil.getDecodedToken(testUtil.jwts.copilot).handle, + userId: testUtil.getDecodedToken(testUtil.jwts.copilot).userId, + firstName: 'fname', + lastName: 'lName', + email: 'some@abc.com', + }; + + const permissions = [ + { + policy: 'work.create', + permission: { + allowRule: { + projectRoles: ['customer', 'copilot'], + topcoderRoles: ['Connect Manager', 'administrator'], + }, + denyRule: { projectRoles: ['copilot'] }, + }, + createdBy: 1, + updatedBy: 1, + }, + { + policy: 'work.edit', + permission: { + allowRule: { + projectRoles: ['copilot'], + topcoderRoles: ['Connect Manager'], + }, + denyRule: { topcoderRoles: ['Connect Admin'] }, + }, + createdBy: 1, + updatedBy: 1, + }, + ]; + + beforeEach((done) => { + testUtil.clearDb() + .then(() => { + models.ProjectTemplate.create({ + name: 'template 2', + key: 'key 2', + category: 'category 2', + icon: 'http://example.com/icon1.ico', + question: 'question 2', + info: 'info 2', + aliases: ['key-2', 'key_2'], + scope: {}, + phases: {}, + createdBy: 1, + updatedBy: 2, + }) + .then((t) => { + templateId = t.id; + // Create projects + models.Project.create({ + type: 'generic', + billingAccountId: 1, + name: 'test1', + description: 'test project1', + status: 'draft', + templateId, + details: {}, + createdBy: 1, + updatedBy: 1, + lastActivityAt: 1, + lastActivityUserId: '1', + }) + .then((project) => { + projectId = project.id; + models.ProjectMember.bulkCreate([{ + id: 1, + userId: copilotUser.userId, + projectId, + role: 'copilot', + isPrimary: false, + createdBy: 1, + updatedBy: 1, + }, { + id: 2, + userId: memberUser.userId, + projectId, + role: 'customer', + isPrimary: true, + createdBy: 1, + updatedBy: 1, + }]).then(() => { + const newPermissions = _.map(permissions, p => _.assign({}, p, { projectTemplateId: templateId })); + models.WorkManagementPermission.bulkCreate(newPermissions, { returning: true }) + .then(() => done()); + }); + }); + }); + }); + }); + + after(testUtil.clearDb); + + describe('GET /projects/{projectId}/permissions', () => { + it('should return 403 if user is not authenticated', (done) => { + request(server) + .get(`/v4/projects/${projectId}/permissions`) + .expect(403, done); + }); + + it('should return 403 for non-member', (done) => { + request(server) + .get(`/v4/projects/${projectId}/permissions`) + .set({ + Authorization: `Bearer ${testUtil.jwts.member2}`, + }) + .expect(403, done); + }); + + it('should return 404 for non-existed project', (done) => { + request(server) + .get('/v4/projects/9999/permissions') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(404, done); + }); + + it('should return 200 for project with no template', (done) => { + models.Project.create({ + type: 'generic', + name: 'test1', + status: 'draft', + createdBy: 1, + updatedBy: 1, + lastActivityAt: 1, + lastActivityUserId: '1', + }) + .then((p) => { + request(server) + .get(`/v4/projects/${p.id}/permissions`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.should.be.empty; + done(); + }); + }); + }); + + it('should return 200 for connect admin - no permission', (done) => { + request(server) + .get(`/v4/projects/${projectId}/permissions`) + .set({ + Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, + }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.should.not.have.all.keys(permissions[0].policy, permissions[1].policy); + done(); + }); + }); + + it('should return 200 for copilot - has both no-permission and permission', (done) => { + request(server) + .get(`/v4/projects/${projectId}/permissions`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.should.have.all.keys(permissions[1].policy); + resJson.should.not.have.all.keys(permissions[0].policy); + done(); + }); + }); + + it('should return 200 for admin - has both permission and no-permission', (done) => { + request(server) + .get(`/v4/projects/${projectId}/permissions`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.should.have.all.keys(permissions[0].policy); + resJson.should.not.have.all.keys(permissions[1].policy); + done(); + }); + }); + + it('should return 200 for manager - has permissions', (done) => { + request(server) + .get(`/v4/projects/${projectId}/permissions`) + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.should.have.all.keys(permissions[0].policy, permissions[1].policy); + done(); + }); + }); + }); +}); diff --git a/src/routes/workManagementPermissions/create.js b/src/routes/workManagementPermissions/create.js new file mode 100644 index 00000000..cecaf9e7 --- /dev/null +++ b/src/routes/workManagementPermissions/create.js @@ -0,0 +1,63 @@ +/* eslint-disable max-len */ +/** + * API to add a work management permission + */ +import validate from 'express-validation'; +import _ from 'lodash'; +import Joi from 'joi'; +import { middleware as tcMiddleware } from 'tc-core-library-js'; +import util from '../../util'; +import models from '../../models'; + +const permissions = tcMiddleware.permissions; + +const schema = { + body: { + param: Joi.object().keys({ + policy: Joi.string().max(255).required(), + permission: Joi.object().required(), + projectTemplateId: Joi.number().integer().positive().required(), + createdAt: Joi.any().strip(), + updatedAt: Joi.any().strip(), + deletedAt: Joi.any().strip(), + createdBy: Joi.any().strip(), + updatedBy: Joi.any().strip(), + deletedBy: Joi.any().strip(), + }).required(), + }, +}; + +module.exports = [ + validate(schema), + permissions('workManagementPermission.create'), + (req, res, next) => { + const entity = _.assign(req.body.param, { + createdBy: req.authUser.userId, + updatedBy: req.authUser.userId, + }); + + // Check if already exists + return models.WorkManagementPermission.findOne({ + where: { + policy: entity.policy, + projectTemplateId: entity.projectTemplateId, + }, + paranoid: false, + }) + .then((existing) => { + if (existing) { + const apiErr = new Error(`Work Management Permission already exists (may be deleted) for policy "${entity.policy}" and project template id ${entity.projectTemplateId}`); + apiErr.status = 422; + return Promise.reject(apiErr); + } + + // Create + return models.WorkManagementPermission.create(entity); + }).then((createdEntity) => { + // Omit deletedAt, deletedBy + res.status(201).json(util.wrapResponse( + req.id, _.omit(createdEntity.toJSON(), 'deletedAt', 'deletedBy'), 1, 201)); + }) + .catch(next); + }, +]; diff --git a/src/routes/workManagementPermissions/create.spec.js b/src/routes/workManagementPermissions/create.spec.js new file mode 100644 index 00000000..cc542d38 --- /dev/null +++ b/src/routes/workManagementPermissions/create.spec.js @@ -0,0 +1,203 @@ +/** + * Tests for create.js + */ +import _ from 'lodash'; +import chai from 'chai'; +import request from 'supertest'; + +import server from '../../app'; +import testUtil from '../../tests/util'; +import models from '../../models'; + +const should = chai.should(); + +describe('CREATE work management permission', () => { + let templateId; + + const body = { + param: { + policy: 'work.create', + permission: { + allowRule: { + projectRoles: ['customer', 'copilot'], + topcoderRoles: ['Connect Manager', 'Connect Admin', 'administrator'], + }, + denyRule: { projectRoles: ['copilot'] }, + }, + createdBy: 1, + updatedBy: 1, + }, + }; + + beforeEach((done) => { + testUtil.clearDb() + .then(() => { + models.ProjectTemplate.create({ + name: 'template 2', + key: 'key 2', + category: 'category 2', + icon: 'http://example.com/icon1.ico', + question: 'question 2', + info: 'info 2', + aliases: ['key-2', 'key_2'], + scope: {}, + phases: {}, + createdBy: 1, + updatedBy: 2, + }) + .then((t) => { + templateId = t.id; + body.param = _.assign({}, body.param, { projectTemplateId: templateId }); + }).then(() => done()); + }); + }); + + after(testUtil.clearDb); + + describe('POST /projects/metadata/workManagementPermission', () => { + it('should return 403 if user is not authenticated', (done) => { + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .send(body) + .expect(403, done); + }); + + it('should return 403 for member', (done) => { + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.member}`, + }) + .send(body) + .expect(403, done); + }); + + it('should return 403 for copilot', (done) => { + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .send(body) + .expect(403, done); + }); + + it('should return 403 for manager', (done) => { + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .send(body) + .expect(403, done); + }); + + it('should return 403 for non-member', (done) => { + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.member2}`, + }) + .send(body) + .expect(403, done); + }); + + it('should return 422 for missing policy', (done) => { + const invalidBody = _.cloneDeep(body); + delete invalidBody.param.policy; + + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(invalidBody) + .expect('Content-Type', /json/) + .expect(422, done); + }); + + it('should return 422 for missing permission', (done) => { + const invalidBody = _.cloneDeep(body); + delete invalidBody.param.permission; + + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(invalidBody) + .expect('Content-Type', /json/) + .expect(422, done); + }); + + it('should return 422 for missing projectTemplateId', (done) => { + const invalidBody = _.cloneDeep(body); + delete invalidBody.param.projectTemplateId; + + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(invalidBody) + .expect('Content-Type', /json/) + .expect(422, done); + }); + + it('should return 422 for duplicated policy and projectTemplateId', (done) => { + models.WorkManagementPermission.create(body.param) + .then(() => { + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(body) + .expect('Content-Type', /json/) + .expect(422, done); + }); + }); + + it('should return 422 for deleted but duplicated policy and projectTemplateId', (done) => { + models.WorkManagementPermission.create(body.param) + .then((permission) => { + models.WorkManagementPermission.destroy({ where: { id: permission.id } }); + }) + .then(() => { + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(body) + .expect('Content-Type', /json/) + .expect(422, done); + }); + }); + + it('should return 201 for admin', (done) => { + request(server) + .post('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(body) + .expect('Content-Type', /json/) + .expect(201) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.policy.should.be.eql(body.param.policy); + resJson.permission.should.be.eql(body.param.permission); + resJson.projectTemplateId.should.be.eql(body.param.projectTemplateId); + resJson.createdBy.should.be.eql(40051333); // admin + should.exist(resJson.createdAt); + resJson.updatedBy.should.be.eql(40051333); // admin + should.exist(resJson.updatedAt); + should.not.exist(resJson.deletedBy); + should.not.exist(resJson.deletedAt); + + done(); + }); + }); + }); +}); diff --git a/src/routes/workManagementPermissions/delete.js b/src/routes/workManagementPermissions/delete.js new file mode 100644 index 00000000..cae7d69c --- /dev/null +++ b/src/routes/workManagementPermissions/delete.js @@ -0,0 +1,37 @@ +/** + * API to delete a work management permission + */ +import validate from 'express-validation'; +import Joi from 'joi'; +import { middleware as tcMiddleware } from 'tc-core-library-js'; +import models from '../../models'; + +const permissions = tcMiddleware.permissions; + +const schema = { + params: { + id: Joi.number().integer().positive().required(), + }, +}; + +module.exports = [ + validate(schema), + permissions('workManagementPermission.delete'), + (req, res, next) => + models.sequelize.transaction(() => + models.WorkManagementPermission.findById(req.params.id) + .then((entity) => { + if (!entity) { + const apiErr = new Error(`Work Management Permission not found for id ${req.params.id}`); + apiErr.status = 404; + return Promise.reject(apiErr); + } + // Update the deletedBy, then delete + return entity.update({ deletedBy: req.authUser.userId }); + }) + .then(entity => entity.destroy())) + .then(() => { + res.status(204).end(); + }) + .catch(next), +]; diff --git a/src/routes/workManagementPermissions/delete.spec.js b/src/routes/workManagementPermissions/delete.spec.js new file mode 100644 index 00000000..ef263872 --- /dev/null +++ b/src/routes/workManagementPermissions/delete.spec.js @@ -0,0 +1,208 @@ +/** + * Tests for delete.js + */ +import _ from 'lodash'; +import request from 'supertest'; +import chai from 'chai'; +import models from '../../models'; +import server from '../../app'; +import testUtil from '../../tests/util'; + +const expectAfterDelete = (permissionId, err, next) => { + if (err) throw err; + setTimeout(() => + models.WorkManagementPermission.findOne({ + where: { + id: permissionId, + }, + paranoid: false, + }) + .then((res) => { + if (!res) { + throw new Error('Should found the entity'); + } else { + chai.assert.isNotNull(res.deletedAt); + chai.assert.isNotNull(res.deletedBy); + + request(server) + .get(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(404, next); + } + }), 500); +}; + +describe('DELETE work management permission', () => { + let permissionId; + + const memberUser = { + handle: testUtil.getDecodedToken(testUtil.jwts.member).handle, + userId: testUtil.getDecodedToken(testUtil.jwts.member).userId, + firstName: 'fname', + lastName: 'lName', + email: 'some@abc.com', + }; + const copilotUser = { + handle: testUtil.getDecodedToken(testUtil.jwts.copilot).handle, + userId: testUtil.getDecodedToken(testUtil.jwts.copilot).userId, + firstName: 'fname', + lastName: 'lName', + email: 'some@abc.com', + }; + + let permission = { + policy: 'work.create', + permission: { + allowRule: { + projectRoles: ['customer', 'copilot'], + topcoderRoles: ['Connect Manager', 'Connect Admin', 'administrator'], + }, + denyRule: { projectRoles: ['copilot'] }, + }, + createdBy: 1, + updatedBy: 1, + }; + + beforeEach((done) => { + testUtil.clearDb() + .then(() => { + models.ProjectTemplate.create({ + name: 'template 2', + key: 'permissionId 2', + category: 'category 2', + icon: 'http://example.com/icon1.ico', + question: 'question 2', + info: 'info 2', + aliases: ['permissionId-2', 'key_2'], + scope: {}, + phases: {}, + createdBy: 1, + updatedBy: 2, + }) + .then((t) => { + permission = _.assign({}, permission, { projectTemplateId: t.id }); + // Create projects + models.Project.create({ + type: 'generic', + billingAccountId: 1, + name: 'test1', + description: 'test project1', + status: 'draft', + templateId: t.id, + details: {}, + createdBy: 1, + updatedBy: 1, + lastActivityAt: 1, + lastActivityUserId: '1', + }) + .then((project) => { + // create members + models.ProjectMember.bulkCreate([{ + id: 1, + userId: copilotUser.userId, + projectId: project.id, + role: 'copilot', + isPrimary: false, + createdBy: 1, + updatedBy: 1, + }, { + id: 2, + userId: memberUser.userId, + projectId: project.id, + role: 'customer', + isPrimary: true, + createdBy: 1, + updatedBy: 1, + }]).then(() => { + models.WorkManagementPermission.create(permission) + .then((p) => { + permissionId = p.id; + }) + .then(() => done()); + }); + }); + }); + }); + }); + + after(testUtil.clearDb); + + + describe('DELETE /projects/metadata/workManagementPermission/{permissionId}', () => { + it('should return 403 if user is not authenticated', (done) => { + request(server) + .delete(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .expect(403, done); + }); + + it('should return 403 for member', (done) => { + request(server) + .delete(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.member}`, + }) + .expect(403, done); + }); + + it('should return 403 for copilot', (done) => { + request(server) + .delete(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .expect(403, done); + }); + + it('should return 403 for manager', (done) => { + request(server) + .delete(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .expect(403, done); + }); + + it('should return 404 for non-existed permission', (done) => { + request(server) + .delete('/v4/projects/metadata/workManagementPermission/123') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(404, done); + }); + + it('should return 404 for deleted permission', (done) => { + models.WorkManagementPermission.destroy({ where: { id: permissionId } }) + .then(() => { + request(server) + .delete(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(404, done); + }); + }); + + it('should return 204, for admin, if permission was successfully removed', (done) => { + request(server) + .delete(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(204) + .end(err => expectAfterDelete(permissionId, err, done)); + }); + + it('should return 204, for connect admin, if permission was successfully removed', (done) => { + request(server) + .delete(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.connectAdmin}`, + }) + .expect(204) + .end(err => expectAfterDelete(permissionId, err, done)); + }); + }); +}); diff --git a/src/routes/workManagementPermissions/get.js b/src/routes/workManagementPermissions/get.js new file mode 100644 index 00000000..cb6bb927 --- /dev/null +++ b/src/routes/workManagementPermissions/get.js @@ -0,0 +1,39 @@ +/** + * API to get a work management permission + */ +import validate from 'express-validation'; +import Joi from 'joi'; +import { middleware as tcMiddleware } from 'tc-core-library-js'; +import util from '../../util'; +import models from '../../models'; + +const permissions = tcMiddleware.permissions; + +const schema = { + params: { + id: Joi.number().integer().positive().required(), + }, +}; + +module.exports = [ + validate(schema), + permissions('workManagementPermission.view'), + (req, res, next) => models.WorkManagementPermission.findOne({ + where: { + id: req.params.id, + }, + attributes: { exclude: ['deletedAt', 'deletedBy'] }, + }) + .then((existing) => { + // Not found + if (!existing) { + const apiErr = new Error(`Work Management Permission not found for id ${req.params.id}`); + apiErr.status = 404; + return Promise.reject(apiErr); + } + + res.json(util.wrapResponse(req.id, existing)); + return Promise.resolve(); + }) + .catch(next), +]; diff --git a/src/routes/workManagementPermissions/get.spec.js b/src/routes/workManagementPermissions/get.spec.js new file mode 100644 index 00000000..8138a260 --- /dev/null +++ b/src/routes/workManagementPermissions/get.spec.js @@ -0,0 +1,147 @@ +/** + * Tests for get.js + */ +import _ from 'lodash'; +import chai from 'chai'; +import request from 'supertest'; + +import models from '../../models'; +import server from '../../app'; +import testUtil from '../../tests/util'; + +const should = chai.should(); + +describe('GET work management permission', () => { + let permissionId; + + let permission = { + policy: 'work.create', + permission: { + allowRule: { + projectRoles: ['customer', 'copilot'], + topcoderRoles: ['Connect Manager', 'Connect Admin', 'administrator'], + }, + denyRule: { projectRoles: ['copilot'] }, + }, + createdBy: 1, + updatedBy: 1, + }; + + beforeEach((done) => { + testUtil.clearDb() + .then(() => { + models.ProjectTemplate.create({ + name: 'template 2', + key: 'key 2', + category: 'category 2', + icon: 'http://example.com/icon1.ico', + question: 'question 2', + info: 'info 2', + aliases: ['key-2', 'key_2'], + scope: {}, + phases: {}, + createdBy: 1, + updatedBy: 2, + }) + .then((t) => { + permission = _.assign({}, permission, { projectTemplateId: t.id }); + models.WorkManagementPermission.create(permission) + .then((p) => { + permissionId = p.id; + }) + .then(() => done()); + }); + }); + }); + + after(testUtil.clearDb); + + describe('GET /projects/metadata/workManagementPermission/{permissionId}', () => { + it('should return 403 if user is not authenticated', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .expect(403, done); + }); + + it('should return 403 for member', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.member}`, + }) + .expect(403, done); + }); + + it('should return 403 for copilot', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .expect(403, done); + }); + + it('should return 403 for manager', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .expect(403, done); + }); + + it('should return 403 for non-member', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.member2}`, + }) + .expect(403, done); + }); + + it('should return 404 for non-existed permission', (done) => { + request(server) + .get('/v4/projects/metadata/workManagementPermission/1234') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(404, done); + }); + + it('should return 404 for deleted permission', (done) => { + models.WorkManagementPermission.destroy({ where: { id: permissionId } }) + .then(() => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(404, done); + }); + }); + + it('should return 200 for admin', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.id.should.be.eql(permissionId); + resJson.policy.should.be.eql(permission.policy); + resJson.permission.should.be.eql(permission.permission); + resJson.projectTemplateId.should.be.eql(permission.projectTemplateId); + resJson.createdBy.should.be.eql(permission.createdBy); + should.exist(resJson.createdAt); + resJson.updatedBy.should.be.eql(permission.updatedBy); + should.exist(resJson.updatedAt); + should.not.exist(resJson.deletedBy); + should.not.exist(resJson.deletedAt); + + done(); + }); + }); + }); +}); diff --git a/src/routes/workManagementPermissions/list.js b/src/routes/workManagementPermissions/list.js new file mode 100644 index 00000000..1f6992e9 --- /dev/null +++ b/src/routes/workManagementPermissions/list.js @@ -0,0 +1,43 @@ +/** + * API to list all work management permissions + */ +import validate from 'express-validation'; +import { middleware as tcMiddleware } from 'tc-core-library-js'; +import Joi from 'joi'; +import util from '../../util'; +import models from '../../models'; + +const permissions = tcMiddleware.permissions; + +const schema = { + query: { + filter: Joi.string().required(), + }, +}; + +module.exports = [ + validate(schema), + permissions('workManagementPermission.view'), + (req, res, next) => { + // handle filters + const filters = util.parseQueryFilter(req.query.filter); + // Throw error if projectTemplateId is not present in filter + if (!filters.projectTemplateId) { + return next(util.buildApiError('Missing filter projectTemplateId', 422)); + } + if (!util.isValidFilter(filters, ['projectTemplateId'])) { + return util.handleError('Invalid filters', null, req, next); + } + req.log.debug(filters); + + return models.WorkManagementPermission.findAll({ + where: filters, + attributes: { exclude: ['deletedAt', 'deletedBy'] }, + raw: true, + }) + .then((result) => { + res.json(util.wrapResponse(req.id, result)); + }) + .catch(next); + }, +]; diff --git a/src/routes/workManagementPermissions/list.spec.js b/src/routes/workManagementPermissions/list.spec.js new file mode 100644 index 00000000..bc0c0d55 --- /dev/null +++ b/src/routes/workManagementPermissions/list.spec.js @@ -0,0 +1,239 @@ +/* eslint-disable max-len */ +/** + * Tests for list.js + */ +import _ from 'lodash'; +import chai from 'chai'; +import request from 'supertest'; + +import models from '../../models'; +import server from '../../app'; +import testUtil from '../../tests/util'; + +const should = chai.should(); + +describe('LIST work management permissions', () => { + let templateIds; + + const templates = [ + { + name: 'template 1', + key: 'key 1', + category: 'category 1', + icon: 'http://example.com/icon1.ico', + question: 'question 1', + info: 'info 1', + aliases: ['key-1', 'key_1'], + disabled: true, + hidden: true, + scope: { + scope1: { + subScope1A: 1, + subScope1B: 2, + }, + scope2: [1, 2, 3], + }, + phases: { + phase1: { + name: 'phase 1', + details: { + anyDetails: 'any details 1', + }, + others: ['others 11', 'others 12'], + }, + phase2: { + name: 'phase 2', + details: { + anyDetails: 'any details 2', + }, + others: ['others 21', 'others 22'], + }, + }, + createdBy: 1, + updatedBy: 1, + }, + { + name: 'template 2', + key: 'key 2', + category: 'category 2', + icon: 'http://example.com/icon1.ico', + question: 'question 2', + info: 'info 2', + aliases: ['key-2', 'key_2'], + scope: {}, + phases: {}, + createdBy: 1, + updatedBy: 2, + }, + ]; + const permissions = [ + { + policy: 'work.create', + permission: { + allowRule: { + projectRoles: ['customer', 'copilot'], + topcoderRoles: ['Connect Manager', 'Connect Admin', 'administrator'], + }, + denyRule: { projectRoles: ['copilot'] }, + }, + createdBy: 1, + updatedBy: 1, + }, + { + policy: 'work.edit', + permission: { + allowRule: { + projectRoles: ['customer', 'copilot'], + topcoderRoles: ['Connect Manager', 'Connect Admin', 'administrator'], + }, + denyRule: { projectRoles: ['copilot'] }, + }, + createdBy: 1, + updatedBy: 1, + }, + ]; + beforeEach((done) => { + testUtil.clearDb() + .then(() => { + models.ProjectTemplate.bulkCreate(templates, { returning: true }) + .then((t) => { + templateIds = _.map(t, template => template.id); + const newPermissions = _.map(permissions, p => _.assign({}, p, { projectTemplateId: templateIds[0] })); + newPermissions.push(_.assign({}, permissions[0], { projectTemplateId: templateIds[1] })); + models.WorkManagementPermission.bulkCreate(newPermissions, { returning: true }) + .then(() => done()); + }); + }); + }); + + after(testUtil.clearDb); + + describe('GET /projects/metadata/workManagementPermission', () => { + it('should return 403 if user is not authenticated', (done) => { + request(server) + .get('/v4/projects/metadata/workManagementPermission?filter=projectTemplateId%3D1') + .expect(403, done); + }); + + it('should return 403 for member', (done) => { + request(server) + .get('/v4/projects/metadata/workManagementPermission?filter=projectTemplateId%3D1') + .set({ + Authorization: `Bearer ${testUtil.jwts.member}`, + }) + .expect(403, done); + }); + + it('should return 403 for copilot', (done) => { + request(server) + .get('/v4/projects/metadata/workManagementPermission?filter=projectTemplateId%3D1') + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .expect(403, done); + }); + + it('should return 403 for manager', (done) => { + request(server) + .get('/v4/projects/metadata/workManagementPermission?filter=projectTemplateId%3D1') + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .expect(403, done); + }); + + it('should return 403 for non-member', (done) => { + request(server) + .get('/v4/projects/metadata/workManagementPermission?filter=projectTemplateId%3D1') + .set({ + Authorization: `Bearer ${testUtil.jwts.member2}`, + }) + .expect(403, done); + }); + + it('should return 422 for missing filter', (done) => { + request(server) + .get('/v4/projects/metadata/workManagementPermission') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(422, done); + }); + + it('should return 422 for missing projectTemplateId', (done) => { + request(server) + .get('/v4/projects/metadata/workManagementPermission?filter=template') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(422, done); + }); + + it('should return 422 for invalid filter', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission?filter=invalid%3D2%26projectTemplateId%3D${templateIds[0]}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(500, done); + }); + + + it('should return 200 for admin for projectTemplateId=1', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission?filter=projectTemplateId%3D${templateIds[0]}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.should.have.length(2); + resJson[0].policy.should.be.eql(permissions[0].policy); + resJson[0].permission.should.be.eql(permissions[0].permission); + resJson[0].projectTemplateId.should.be.eql(templateIds[0]); + should.exist(resJson[0].createdAt); + resJson[0].updatedBy.should.be.eql(permissions[0].updatedBy); + should.exist(resJson[0].updatedAt); + should.not.exist(resJson[0].deletedBy); + should.not.exist(resJson[0].deletedAt); + resJson[1].policy.should.be.eql(permissions[1].policy); + resJson[1].permission.should.be.eql(permissions[1].permission); + resJson[1].projectTemplateId.should.be.eql(templateIds[0]); + should.exist(resJson[1].createdAt); + resJson[1].updatedBy.should.be.eql(permissions[1].updatedBy); + should.exist(resJson[1].updatedAt); + should.not.exist(resJson[1].deletedBy); + should.not.exist(resJson[1].deletedAt); + + done(); + }); + }); + + it('should return 200 for admin for projectTemplateId=2', (done) => { + request(server) + .get(`/v4/projects/metadata/workManagementPermission?filter=projectTemplateId%3D${templateIds[1]}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.should.have.length(1); + resJson[0].policy.should.be.eql(permissions[0].policy); + resJson[0].permission.should.be.eql(permissions[0].permission); + resJson[0].projectTemplateId.should.be.eql(templateIds[1]); + should.exist(resJson[0].createdAt); + resJson[0].updatedBy.should.be.eql(permissions[0].updatedBy); + should.exist(resJson[0].updatedAt); + should.not.exist(resJson[0].deletedBy); + should.not.exist(resJson[0].deletedAt); + + done(); + }); + }); + }); +}); diff --git a/src/routes/workManagementPermissions/update.js b/src/routes/workManagementPermissions/update.js new file mode 100644 index 00000000..cb51d732 --- /dev/null +++ b/src/routes/workManagementPermissions/update.js @@ -0,0 +1,84 @@ +/* eslint-disable max-len */ +/** + * API to update a work management permission + */ +import validate from 'express-validation'; +import _ from 'lodash'; +import Joi from 'joi'; +import { middleware as tcMiddleware } from 'tc-core-library-js'; +import util from '../../util'; +import models from '../../models'; + +const permissions = tcMiddleware.permissions; + +const schema = { + params: { + id: Joi.number().integer().positive().required(), + }, + body: { + param: Joi.object().keys({ + policy: Joi.string().max(255).optional(), + permission: Joi.object().optional(), + projectTemplateId: Joi.number().integer().positive().optional(), + createdAt: Joi.any().strip(), + updatedAt: Joi.any().strip(), + deletedAt: Joi.any().strip(), + createdBy: Joi.any().strip(), + updatedBy: Joi.any().strip(), + deletedBy: Joi.any().strip(), + }).required(), + }, +}; + +module.exports = [ + validate(schema), + permissions('workManagementPermission.edit'), + (req, res, next) => { + const entityToUpdate = _.assign(req.body.param, { + updatedBy: req.authUser.userId, + }); + + let permissionToUpdate; + + return models.sequelize.transaction(() => // Get work management permission + models.WorkManagementPermission.findOne({ + where: { + id: req.params.id, + }, + attributes: { exclude: ['deletedAt', 'deletedBy'] }, + }) + .then((permission) => { + // Not found + if (!permission) { + const apiErr = new Error(`Work Management Permission not found for id ${req.params.id}`); + apiErr.status = 404; + return Promise.reject(apiErr); + } + + permissionToUpdate = permission; + return models.WorkManagementPermission.findOne({ + where: { + policy: entityToUpdate.policy, + projectTemplateId: entityToUpdate.projectTemplateId, + id: { $ne: req.params.id }, + }, + paranoid: false, + }); + }) + .then((existing) => { + if (existing) { + const apiErr = new Error(`Work Management Permission already exists (may be deleted) for policy "${entityToUpdate.policy}" and project template id ${entityToUpdate.projectTemplateId}`); + apiErr.status = 422; + return Promise.reject(apiErr); + } + + return permissionToUpdate.update(entityToUpdate); + }), + ) + .then((updated) => { + res.json(util.wrapResponse(req.id, updated)); + return Promise.resolve(); + }) + .catch(next); + }, +]; diff --git a/src/routes/workManagementPermissions/update.spec.js b/src/routes/workManagementPermissions/update.spec.js new file mode 100644 index 00000000..8d3fc64a --- /dev/null +++ b/src/routes/workManagementPermissions/update.spec.js @@ -0,0 +1,300 @@ +/** + * Tests for update.js + */ +import _ from 'lodash'; +import chai from 'chai'; +import request from 'supertest'; + +import models from '../../models'; +import server from '../../app'; +import testUtil from '../../tests/util'; + +const should = chai.should(); + +describe('UPDATE work management permission', () => { + let permissionId; + let templateId; + + let permission = { + policy: 'work.create', + permission: { + allowRule: { + projectRoles: ['customer', 'copilot'], + topcoderRoles: ['Connect Manager', 'Connect Admin', 'administrator'], + }, + denyRule: { projectRoles: ['copilot'] }, + }, + createdBy: 1, + updatedBy: 1, + }; + + beforeEach((done) => { + testUtil.clearDb() + .then(() => { + models.ProjectTemplate.create({ + name: 'template 2', + key: 'key 2', + category: 'category 2', + icon: 'http://example.com/icon1.ico', + question: 'question 2', + info: 'info 2', + aliases: ['key-2', 'key_2'], + scope: {}, + phases: {}, + createdBy: 1, + updatedBy: 2, + }) + .then((t) => { + templateId = t.id; + permission = _.assign({}, permission, { projectTemplateId: templateId }); + models.WorkManagementPermission.create(permission) + .then((p) => { + permissionId = p.id; + }) + .then(() => done()); + }); + }); + }); + + after(testUtil.clearDb); + + describe('PATCH /projects/metadata/workManagementPermission/{permissionId}', () => { + const body = { + param: { + policy: 'work.edit', + permission: { + allowRule: { + projectRoles: ['customer', 'copilot'], + topcoderRoles: ['Connect Manager', 'Connect Admin', 'administrator'], + }, + denyRule: { projectRoles: ['copilot'] }, + }, + createdBy: 1, + updatedBy: 1, + }, + }; + + it('should return 403 if user is not authenticated', (done) => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .send(body) + .expect(403, done); + }); + + it('should return 403 for member', (done) => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.member}`, + }) + .send(body) + .expect(403, done); + }); + + it('should return 403 for copilot', (done) => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .send(body) + .set({ + Authorization: `Bearer ${testUtil.jwts.copilot}`, + }) + .expect(403, done); + }); + + it('should return 403 for manager', (done) => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .send(body) + .set({ + Authorization: `Bearer ${testUtil.jwts.manager}`, + }) + .expect(403, done); + }); + + it('should return 403 for non-member', (done) => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.member2}`, + }) + .send(body) + .expect(403, done); + }); + + it('should return 404 for non-existed type', (done) => { + request(server) + .patch('/v4/projects/metadata/workManagementPermission/1234') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(body) + .expect(404, done); + }); + + it('should return 404 for deleted type', (done) => { + models.WorkManagementPermission.destroy({ where: { id: permissionId } }) + .then(() => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(body) + .expect(404, done); + }); + }); + + it('should return 422 when updated with invalid param', (done) => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send({ param: { invalid: null } }) + .expect('Content-Type', /json/) + .expect(422, done); + }); + + it('should return 422 for policy and projectTemplateId updated with existing(non-deleted) values', (done) => { + const newParam = _.assign({}, body.param, { projectTemplateId: templateId }); + models.WorkManagementPermission.create(newParam) + .then(() => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send({ param: newParam }) + .expect('Content-Type', /json/) + .expect(422, done); + }); + }); + + it('should return 422 for policy and projectTemplateId updated with existing(deleted) values', (done) => { + const newParam = _.assign({}, body.param, { projectTemplateId: templateId }); + models.WorkManagementPermission.create(newParam) + .then((p) => { + models.WorkManagementPermission.destroy({ where: { id: p.id } }); + }) + .then(() => { + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send({ param: newParam }) + .expect('Content-Type', /json/) + .expect(422, done); + }); + }); + + it('should return 200 for policy updated', (done) => { + const partialBody = _.cloneDeep(body); + delete partialBody.param.permission; + delete partialBody.param.projectTemplateId; + + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(partialBody) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.id.should.be.eql(permissionId); + resJson.policy.should.be.eql(partialBody.param.policy); + resJson.permission.should.be.eql(permission.permission); + resJson.projectTemplateId.should.be.eql(permission.projectTemplateId); + resJson.createdBy.should.be.eql(permission.createdBy); // should not update createdAt + resJson.updatedBy.should.be.eql(40051333); // admin + should.exist(resJson.updatedAt); + should.not.exist(resJson.deletedBy); + should.not.exist(resJson.deletedAt); + + done(); + }); + }); + + it('should return 200 for admin permission updated', (done) => { + const partialBody = _.cloneDeep(body); + delete partialBody.param.policy; + delete partialBody.param.projectTemplateId; + + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(partialBody) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.id.should.be.eql(permissionId); + resJson.policy.should.be.eql(permission.policy); + resJson.permission.should.be.eql(partialBody.param.permission); + resJson.projectTemplateId.should.be.eql(permission.projectTemplateId); + resJson.createdBy.should.be.eql(permission.createdBy); // should not update createdAt + resJson.updatedBy.should.be.eql(40051333); // admin + should.exist(resJson.updatedAt); + should.not.exist(resJson.deletedBy); + should.not.exist(resJson.deletedAt); + + done(); + }); + }); + + it('should return 200 for admin projectTemplateId updated', (done) => { + const partialBody = _.cloneDeep(body); + partialBody.param = _.assign({}, partialBody.param, { projectTemplateId: templateId }); + delete partialBody.param.policy; + delete partialBody.param.permission; + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send(partialBody) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.id.should.be.eql(permissionId); + resJson.policy.should.be.eql(permission.policy); + resJson.permission.should.be.eql(permission.permission); + resJson.projectTemplateId.should.be.eql(partialBody.param.projectTemplateId); + resJson.createdBy.should.be.eql(permission.createdBy); // should not update createdAt + resJson.updatedBy.should.be.eql(40051333); // admin + should.exist(resJson.updatedAt); + should.not.exist(resJson.deletedBy); + should.not.exist(resJson.deletedAt); + + done(); + }); + }); + + it('should return 200 for admin all fields updated', (done) => { + const newParam = _.assign({}, body.param, { projectTemplateId: templateId }); + request(server) + .patch(`/v4/projects/metadata/workManagementPermission/${permissionId}`) + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .send({ param: newParam }) + .expect(200) + .end((err, res) => { + const resJson = res.body.result.content; + resJson.id.should.be.eql(permissionId); + resJson.policy.should.be.eql(body.param.policy); + resJson.permission.should.be.eql(body.param.permission); + resJson.projectTemplateId.should.be.eql(newParam.projectTemplateId); + resJson.createdBy.should.be.eql(permission.createdBy); // should not update createdAt + resJson.updatedBy.should.be.eql(40051333); // admin + should.exist(resJson.updatedAt); + should.not.exist(resJson.deletedBy); + should.not.exist(resJson.deletedAt); + + done(); + }); + }); + }); +}); diff --git a/swagger.yaml b/swagger.yaml index 930fe2bf..4879a085 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -1971,6 +1971,191 @@ paths: description: If organization config is not found schema: $ref: '#/definitions/ErrorModel' + + /projects/metadata/workManagementPermission: + get: + tags: + - workManagementPermission + operationId: findWorkManagementPermissions + security: + - Bearer: [] + description: >- + Retrieve all work management permissions. Only admin or connect admin can access + this endpoint. + parameters: + - name: filter + required: true + type: string + in: query + description: | + Url encoded list of Supported filters + - projectTemplateId (required) + responses: + '200': + description: A list of work management permissions + schema: + $ref: '#/definitions/WorkManagementPermissionListResponse' + '403': + description: No permission or wrong token + schema: + $ref: '#/definitions/ErrorModel' + post: + tags: + - workManagementPermission + operationId: addWorkManagementPermission + security: + - Bearer: [] + description: >- + Create a work management permission. Only admin or connect admin can access + this endpoint. + parameters: + - in: body + name: body + required: true + schema: + $ref: '#/definitions/WorkManagementPermissionCreateBodyParam' + responses: + '201': + description: Returns the newly created work management permission + schema: + $ref: '#/definitions/WorkManagementPermissionResponse' + '403': + description: No permission or wrong token + schema: + $ref: '#/definitions/ErrorModel' + '422': + description: Invalid input + schema: + $ref: '#/definitions/ErrorModel' + '/projects/metadata/workManagementPermission/{id}': + get: + tags: + - workManagementPermission + description: Retrieve work management permission by id. Only admin or connect admin can access + this endpoint. + security: + - Bearer: [] + responses: + '200': + description: a project type + schema: + $ref: '#/definitions/WorkManagementPermissionResponse' + '403': + description: No permission or wrong token + schema: + $ref: '#/definitions/ErrorModel' + '404': + description: Not found + schema: + $ref: '#/definitions/ErrorModel' + parameters: + - $ref: '#/parameters/permissionIdParam' + operationId: getWorkManagementPermission + patch: + tags: + - workManagementPermission + operationId: updateWorkManagementPermission + security: + - Bearer: [] + description: >- + Update a work management permission. Only admin or connect admin can access + this endpoint. + responses: + '200': + description: Successfully updated work management permission. + schema: + $ref: '#/definitions/WorkManagementPermissionResponse' + '403': + description: No permission or wrong token + schema: + $ref: '#/definitions/ErrorModel' + '404': + description: Not found + schema: + $ref: '#/definitions/ErrorModel' + '422': + description: Invalid input + schema: + $ref: '#/definitions/ErrorModel' + default: + description: error payload + schema: + $ref: '#/definitions/ErrorModel' + parameters: + - $ref: '#/parameters/permissionIdParam' + - name: body + in: body + required: true + schema: + $ref: '#/definitions/WorkManagementPermissionCreateBodyParam' + delete: + tags: + - workManagementPermission + description: >- + Remove an existing work management permission. Only admin or connect admin can + access this endpoint. + security: + - Bearer: [] + parameters: + - $ref: '#/parameters/permissionIdParam' + responses: + '204': + description: Work management permission successfully removed + '403': + description: No permission or wrong token + schema: + $ref: '#/definitions/ErrorModel' + '404': + description: If work management permission is not found + schema: + $ref: '#/definitions/ErrorModel' + + '/projects/{projectId}/permissions': + get: + tags: + - permissions + description: Retrieve permissions. + security: + - Bearer: [] + responses: + '200': + description: permissions + schema: + title: Single work management permission response object + type: object + properties: + id: + type: string + description: unique id identifying the request + version: + type: string + result: + type: object + properties: + success: + type: boolean + status: + type: integer + format: int32 + description: http status code + metadata: + $ref: '#/definitions/ResponseMetadata' + content: + type: object + example: + 'work.create': true + '403': + description: No permission or wrong token + schema: + $ref: '#/definitions/ErrorModel' + '404': + description: Not found + schema: + $ref: '#/definitions/ErrorModel' + parameters: + - $ref: '#/parameters/projectIdParam' + operationId: getPermissions + /timelines: get: tags: @@ -3463,6 +3648,13 @@ parameters: required: true type: integer format: int64 + permissionIdParam: + name: id + in: path + description: work management permission id + required: true + type: integer + format: int64 offsetParam: name: offset description: number of items to skip. Defaults to 0 @@ -5132,6 +5324,130 @@ definitions: type: array items: $ref: '#/definitions/OrgConfig' + + + + WorkManagementPermissionCreateRequest: + title: Work Management Permission request object + type: object + required: + - policy + - permission + - projectTemplateId + properties: + policy: + type: string + description: the policy + permission: + type: object + description: the permission + projectTemplateId: + type: number + format: int64 + description: the template id + WorkManagementPermissionCreateBodyParam: + title: Work Management Permission creation body param + type: object + required: + - param + properties: + param: + $ref: '#/definitions/WorkManagementPermissionCreateRequest' + WorkManagementPermission: + title: Work Management Permission object + allOf: + - type: object + required: + - id + - policy + - permission + - projectTemplateId + - createdAt + - createdBy + - updatedAt + - updatedBy + properties: + id: + type: number + format: int64 + description: the id + policy: + type: string + description: the policy + permission: + type: object + description: the permission + projectTemplateId: + type: number + format: int64 + description: the template id + createdAt: + type: string + description: Datetime (GMT) when object was created + readOnly: true + createdBy: + type: integer + format: int64 + description: READ-ONLY. User who created this object + readOnly: true + updatedAt: + type: string + description: READ-ONLY. Datetime (GMT) when object was updated + readOnly: true + updatedBy: + type: integer + format: int64 + description: READ-ONLY. User that last updated this object + readOnly: true + - $ref: '#/definitions/WorkManagementPermissionCreateRequest' + WorkManagementPermissionResponse: + title: Single work management permission response object + type: object + properties: + id: + type: string + description: unique id identifying the request + version: + type: string + result: + type: object + properties: + success: + type: boolean + status: + type: integer + format: int32 + description: http status code + metadata: + $ref: '#/definitions/ResponseMetadata' + content: + $ref: '#/definitions/WorkManagementPermission' + + WorkManagementPermissionListResponse: + title: Work management permissions response object + type: object + properties: + id: + type: string + readOnly: true + description: unique id identifying the request + version: + type: string + result: + type: object + properties: + success: + type: boolean + status: + type: integer + format: int32 + description: http status code + metadata: + $ref: '#/definitions/ResponseMetadata' + content: + type: array + items: + $ref: '#/definitions/WorkManagementPermission' ProjectTypeResponse: title: Single project type response object type: object