diff --git a/harena-manager.postman_collection.json b/harena-manager.postman_collection.json index 800d415..8b65380 100644 --- a/harena-manager.postman_collection.json +++ b/harena-manager.postman_collection.json @@ -17,7 +17,6 @@ { "listen": "test", "script": { - "id": "7e4ca188-f483-438b-92e4-faabcb68e232", "exec": [ "var response = pm.response.json();", "pm.environment.set(\"user-token\", response.token);", @@ -39,12 +38,12 @@ "formdata": [ { "key": "email", - "value": "jacinto@email.com", + "value": "", "type": "text" }, { "key": "password", - "value": "jacinto", + "value": "", "type": "text" }, { @@ -53,10 +52,7 @@ "type": "text", "disabled": true } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/auth/login/", @@ -78,7 +74,6 @@ { "listen": "test", "script": { - "id": "4d239fcd-b358-47f3-874b-0f0fe8eb2be6", "exec": [ "" ], @@ -101,10 +96,7 @@ "header": [], "body": { "mode": "formdata", - "formdata": [], - "options": { - "formdata": {} - } + "formdata": [] }, "url": { "raw": "{{api-base-url}}/auth/logout/", @@ -125,7 +117,6 @@ { "listen": "prerequest", "script": { - "id": "7cc84993-51ae-49e5-9d6a-fbcf06c938e3", "type": "text/javascript", "exec": [ "" @@ -135,16 +126,13 @@ { "listen": "test", "script": { - "id": "e8d036f7-f38d-4f12-9350-332845532e2f", "type": "text/javascript", "exec": [ "" ] } } - ], - "protocolProfileBehavior": {}, - "_postman_isSubFolder": true + ] }, { "name": "/auth/login session", @@ -152,7 +140,6 @@ { "listen": "test", "script": { - "id": "62c53a04-7306-4590-ac1f-e0a0415ee3c5", "exec": [ "var response = pm.response.json();", "console.log(response)", @@ -180,10 +167,7 @@ "value": "", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/auth/login", @@ -204,7 +188,6 @@ { "listen": "test", "script": { - "id": "005e1c53-285c-4eb4-a33d-7039ac2a6002", "exec": [ "pm.environment.set(\"user-token\", 'revoked');" ], @@ -250,8 +233,7 @@ "response": [] } ], - "description": "Authentication endpoints", - "protocolProfileBehavior": {} + "description": "Authentication endpoints" }, { "name": "user", @@ -262,7 +244,6 @@ { "listen": "test", "script": { - "id": "8d76235e-2ca8-4773-802b-41b22c5d37c0", "exec": [ "var response = pm.response.json();", "", @@ -291,10 +272,7 @@ "value": "aa9da08a-1bd4-4a57-b4bf-076a889d6046", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/user/cases_by_quest", @@ -315,7 +293,6 @@ { "listen": "test", "script": { - "id": "db6e3ed4-8ce6-44a3-b4da-60fbd5ec5e80", "exec": [ "pm.test(\"Status code is 200\", function () {", " pm.response.to.have.status(200);", @@ -347,7 +324,6 @@ { "listen": "test", "script": { - "id": "ad5da6f0-b5b5-4792-baa7-502b215827c4", "exec": [ "var response = pm.response.json();", "", @@ -375,18 +351,46 @@ { "key": "clearance", "value": "4", - "type": "text" + "type": "text", + "disabled": true }, { "key": "published", - "value": "\n", + "value": "", + "type": "text", + "disabled": true + }, + { + "key": "fInstitution", + "value": "c5562bfd-9a94-40f0-b08a-3627e3e417e0", + "type": "text", + "disabled": true + }, + { + "key": "fUserType", + "value": "aluno", + "type": "text", + "disabled": true + }, + { + "key": "fSpecialty", + "value": "0", + "type": "text", + "disabled": true + }, + { + "key": "fProperty", + "value": "feedback", + "type": "text", + "disabled": true + }, + { + "key": "fPropertyValue", + "value": "1", "type": "text", "disabled": true } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/user/cases", @@ -407,7 +411,6 @@ { "listen": "test", "script": { - "id": "d53aca1e-8cff-4141-bfc2-53fca7af2fa8", "exec": [ "" ], @@ -437,7 +440,6 @@ { "listen": "test", "script": { - "id": "0f147b45-e953-4eda-ac7a-811ca797cd98", "exec": [ "var response = pm.response.json();", "", @@ -461,10 +463,7 @@ "header": [], "body": { "mode": "formdata", - "formdata": [], - "options": { - "formdata": {} - } + "formdata": [] }, "url": { "raw": "{{api-base-url}}/user/cases_by_institution", @@ -485,7 +484,6 @@ { "listen": "test", "script": { - "id": "145c56e0-caff-4d47-8fdf-d2f6905abbdd", "exec": [ "var response = pm.response.json();", "", @@ -538,10 +536,7 @@ "value": "aluno", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/user", @@ -578,7 +573,8 @@ { "key": "login", "value": "jacinta", - "type": "text" + "type": "text", + "disabled": true }, { "key": "grade", @@ -646,7 +642,6 @@ { "listen": "test", "script": { - "id": "dcbba21c-af88-435a-9948-8d03adfac96f", "exec": [ "pm.test(\"Status code is 200 or 204\", function () {", " ", @@ -675,25 +670,36 @@ "response": [] } ], - "description": "User services", - "protocolProfileBehavior": {} + "description": "User services" }, { "name": "case", "item": [ { "name": "/case/:id", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, "request": { "method": "GET", "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "caseId", + "value": "", + "type": "text" + } + ] + }, "url": { - "raw": "{{api-base-url}}/case/{{case-id}}", + "raw": "{{api-base-url}}/case", "host": [ "{{api-base-url}}" ], "path": [ - "case", - "{{case-id}}" + "case" ] } }, @@ -705,7 +711,6 @@ { "listen": "test", "script": { - "id": "d358db71-a30f-45df-b924-31f9856e2795", "exec": [ "var response = pm.response.json();", "console.log(response.id)", @@ -799,10 +804,7 @@ "value": "read", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/case", @@ -822,7 +824,6 @@ { "listen": "test", "script": { - "id": "b49b1ec2-2db6-4c3e-b47c-68588064b4cb", "exec": [ "var response = pm.response.json();", "", @@ -866,10 +867,7 @@ "value": "read", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/case/link/user", @@ -938,10 +936,7 @@ "value": "", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/case/{{case-id}}", @@ -961,21 +956,157 @@ "request": { "method": "DELETE", "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "caseId", + "value": "", + "type": "text" + } + ] + }, "url": { - "raw": "{{api-base-url}}/case/{{case-id}}", + "raw": "{{api-base-url}}/case/", "host": [ "{{api-base-url}}" ], "path": [ "case", - "{{case-id}}" + "" + ] + } + }, + "response": [] + }, + { + "name": "/share", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "entity", + "value": "institution", + "type": "text" + }, + { + "key": "subject", + "value": "c5562bfd-9a94-40f0-b08a-3627e3e417e0", + "type": "text" + }, + { + "key": "subject_grade", + "value": "", + "description": "Choose a specific user grade (professor/aluno)", + "type": "text", + "disabled": true + }, + { + "key": "clearance", + "value": "4", + "type": "text" + }, + { + "key": "table_id", + "value": "0008f7a0-6635-439d-af22-d0edd6e22138", + "description": "Case ids. Separated by comma if you want multiple ids", + "type": "text" + } + ] + }, + "url": { + "raw": "{{api-base-url}}/case/share", + "host": [ + "{{api-base-url}}" + ], + "path": [ + "case", + "share" + ] + } + }, + "response": [] + }, + { + "name": "/property", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "case_id", + "value": "88ffeb32-df75-43b4-a7bb-937051cff61e", + "type": "text" + }, + { + "key": "property_title", + "value": "casepropertynovo", + "type": "text" + }, + { + "key": "property_value", + "value": "novissimo", + "type": "text" + } + ] + }, + "url": { + "raw": "{{api-base-url}}/case/property", + "host": [ + "{{api-base-url}}" + ], + "path": [ + "case", + "property" + ] + } + }, + "response": [] + }, + { + "name": "/property", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "case_id", + "value": "af19035f-df50-4178-8f9c-bc0eab59e9bd", + "type": "text" + }, + { + "key": "property_title", + "value": "feedback", + "type": "text" + }, + { + "key": "property_value", + "value": "0", + "type": "text" + } + ] + }, + "url": { + "raw": "{{api-base-url}}/case/property", + "host": [ + "{{api-base-url}}" + ], + "path": [ + "case", + "property" ] } }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "player", @@ -986,7 +1117,6 @@ { "listen": "test", "script": { - "id": "6a4896f8-c94a-4be5-b72e-6a37db0822c9", "exec": [ "" ], @@ -1016,7 +1146,6 @@ { "listen": "test", "script": { - "id": "e4d4a6d3-357b-4d04-aa09-2d744abe950e", "exec": [ "" ], @@ -1038,10 +1167,7 @@ "value": "ea8dbc12-e879-46e6-b5d7-e67ad88e841b", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/player/quest/cases", @@ -1057,8 +1183,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "author", @@ -1069,7 +1194,6 @@ { "listen": "test", "script": { - "id": "1fca660b-8774-4143-814c-db7afee7efd3", "exec": [ "" ], @@ -1099,7 +1223,6 @@ { "listen": "test", "script": { - "id": "d71fe530-8ff2-4d64-8793-5d77ceaf5ccb", "exec": [ "" ], @@ -1121,10 +1244,7 @@ "value": "5131b64a-04ff-4aec-af98-0edab334fd02", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/author/quest/cases", @@ -1140,8 +1260,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "artifact", @@ -1183,10 +1302,7 @@ "value": "desafio-pocus-image", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/artifact", @@ -1223,7 +1339,6 @@ { "listen": "prerequest", "script": { - "id": "7bc7d2a4-7bbc-48af-8fee-153860cad3d5", "type": "text/javascript", "exec": [ "" @@ -1233,15 +1348,13 @@ { "listen": "test", "script": { - "id": "d36a0f4e-2db8-434c-b0bc-770d22e17c89", "type": "text/javascript", "exec": [ "" ] } } - ], - "protocolProfileBehavior": {} + ] }, { "name": "quest", @@ -1252,7 +1365,6 @@ { "listen": "test", "script": { - "id": "69612a32-fec9-4c59-b25d-2b672a45cbf1", "exec": [ "" ], @@ -1274,10 +1386,7 @@ "value": "5885fb0d-ce64-421f-9b9e-1ea2cef3143f", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/quest/users", @@ -1298,7 +1407,6 @@ { "listen": "test", "script": { - "id": "eb43d5c2-763e-4c25-ac0a-0b2ddf2179cb", "exec": [ "var response = pm.response.json();", "", @@ -1336,10 +1444,7 @@ "value": "f9679a24-58f3-4741-9752-f40d0b4f4ab0", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/quest/", @@ -1377,10 +1482,7 @@ "value": "player", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/quest/link/user", @@ -1419,10 +1521,7 @@ "value": "0", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/quest/link/case", @@ -1438,8 +1537,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "category", @@ -1450,7 +1548,6 @@ { "listen": "test", "script": { - "id": "626a67ae-8150-4f96-bc9f-2f7c16c9bde9", "exec": [ "" ], @@ -1469,13 +1566,38 @@ "formdata": [ { "key": "categoryId", - "value": "decisoesExtremas", + "value": "decisoes-extremas", + "type": "text" + }, + { + "key": "clearance", + "value": "1", + "type": "text" + }, + { + "key": "published", + "value": "", + "type": "text", + "disabled": true + }, + { + "key": "fInstitution", + "value": "c5562bfd-9a94-40f0-b08a-3627e3e417e0", + "type": "text", + "disabled": true + }, + { + "key": "fUserType", + "value": "aluno", + "type": "text", + "disabled": true + }, + { + "key": "fSpecialty", + "value": "especialidade 1", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/category/cases", @@ -1496,7 +1618,6 @@ { "listen": "test", "script": { - "id": "3b6e6f6b-df17-42e8-959a-513e0dedc099", "exec": [ "var response = pm.response.json();", "", @@ -1539,10 +1660,7 @@ "value": "desafio-pocus-image", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/category/", @@ -1580,10 +1698,7 @@ "value": "0", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/category/link/case", @@ -1630,30 +1745,51 @@ "method": "PUT", "header": [], "url": { - "raw": "{{api-base-url}}/category/desafio-pocus?artifactId=desafio-pocus-image&title=Desafio Pocus", + "raw": "{{api-base-url}}/category/pocus-training?artifactId=093ebf5d-5cec-48b3-8730-12f92e8a1ffd&title=Treinamento POCUS", "host": [ "{{api-base-url}}" ], "path": [ "category", - "desafio-pocus" + "pocus-training" ], "query": [ { "key": "artifactId", - "value": "desafio-pocus-image" + "value": "093ebf5d-5cec-48b3-8730-12f92e8a1ffd" }, { "key": "title", - "value": "Desafio Pocus" + "value": "Treinamento POCUS" } ] } }, "response": [] } - ], - "protocolProfileBehavior": {} + ] + }, + { + "name": "institution", + "item": [ + { + "name": "/institutions", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api-base-url}}/institutions", + "host": [ + "{{api-base-url}}" + ], + "path": [ + "institutions" + ] + } + }, + "response": [] + } + ] }, { "name": "admin", @@ -1664,7 +1800,6 @@ { "listen": "test", "script": { - "id": "0da4e91e-5a5a-43c6-8fef-223dce72f31f", "exec": [ "var response = pm.response.json();", "", @@ -1688,10 +1823,7 @@ "header": [], "body": { "mode": "formdata", - "formdata": [], - "options": { - "formdata": {} - } + "formdata": [] }, "url": { "raw": "{{api-base-url}}/admin/cases", @@ -1712,7 +1844,6 @@ { "listen": "test", "script": { - "id": "edfe7693-8604-45bf-b2bf-600cea846dc0", "exec": [ "var response = pm.response.json();", "", @@ -1745,10 +1876,7 @@ "header": [], "body": { "mode": "formdata", - "formdata": [], - "options": { - "formdata": {} - } + "formdata": [] }, "url": { "raw": "{{api-base-url}}/admin/users", @@ -1769,7 +1897,6 @@ { "listen": "test", "script": { - "id": "540ef4ca-e4a5-499d-b06b-e538b4702286", "exec": [ "" ], @@ -1799,7 +1926,6 @@ { "listen": "test", "script": { - "id": "6055d49e-f43b-4c6e-8a1f-b63e32c17e11", "exec": [ "" ], @@ -1831,7 +1957,6 @@ { "listen": "test", "script": { - "id": "222550fd-5a12-4a17-bcef-a3ae88e1be3f", "exec": [ "" ], @@ -1865,18 +1990,15 @@ "formdata": [ { "key": "userId", - "value": "781c4351-16d7-4b24-b214-bb9fdb3e75bf", + "value": "ec4ab025-879d-4e8b-b4d1-2b5e847c08e0", "type": "text" }, { "key": "roleId", - "value": "41353296-c9ac-4365-83b6-4c9dbc845930", + "value": "74448d95-fd3f-4dc1-a424-cf73c97ced45", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/admin/user/link/role", @@ -1899,7 +2021,6 @@ { "listen": "test", "script": { - "id": "29920f59-a6b7-4f3e-8909-b7171419cb07", "exec": [ "" ], @@ -1935,10 +2056,7 @@ "value": "BR", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/admin/institution", @@ -1959,7 +2077,6 @@ { "listen": "test", "script": { - "id": "519ed505-fbc6-4eb8-995e-c704486a84b7", "exec": [ "" ], @@ -1979,10 +2096,7 @@ ], "body": { "mode": "formdata", - "formdata": [], - "options": { - "formdata": {} - } + "formdata": [] }, "url": { "raw": "{{api-base-url}}/admin/revoke_tokens", @@ -2020,10 +2134,7 @@ "value": "author", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/admin/quest/link/user", @@ -2046,7 +2157,6 @@ { "listen": "test", "script": { - "id": "f1647ef8-7e68-4b0a-8bfe-91b84283904f", "exec": [ "" ], @@ -2082,10 +2192,7 @@ "value": "Research project member", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/admin/role", @@ -2178,8 +2285,7 @@ "response": [] } ], - "description": "Services for administrate `harena`", - "protocolProfileBehavior": {} + "description": "Services for administrate `harena`" }, { "name": "group", @@ -2190,7 +2296,6 @@ { "listen": "test", "script": { - "id": "94c53d16-ddb2-40c4-8c24-9849f2caf53c", "exec": [ "" ], @@ -2212,10 +2317,7 @@ "value": "37b4159f-b2bf-4014-b5dc-655df6506311", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/group/cases", @@ -2236,7 +2338,6 @@ { "listen": "test", "script": { - "id": "7667499e-a7f5-4236-9eb6-3e8ca72e7e27", "exec": [ "var response = pm.response.json();", "", @@ -2264,10 +2365,7 @@ "value": "Turma do Minho", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/group/", @@ -2300,10 +2398,7 @@ "value": "781c4351-16d7-4b24-b214-bb9fdb3e75bf", "type": "text" } - ], - "options": { - "formdata": {} - } + ] }, "url": { "raw": "{{api-base-url}}/group/link/user", @@ -2319,8 +2414,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] } ], "auth": { @@ -2337,7 +2431,6 @@ { "listen": "prerequest", "script": { - "id": "304b8626-14c1-4881-8a2a-881c9fa0d3bc", "type": "text/javascript", "exec": [ "" @@ -2347,13 +2440,11 @@ { "listen": "test", "script": { - "id": "67ec55a1-a62c-4dc7-bcfe-0d21b1d13da8", "type": "text/javascript", "exec": [ "" ] } } - ], - "protocolProfileBehavior": {} + ] } \ No newline at end of file diff --git a/harena-manager_-_production.postman_environment.json b/harena-manager_-_production.postman_environment.json new file mode 100644 index 0000000..8e8b984 --- /dev/null +++ b/harena-manager_-_production.postman_environment.json @@ -0,0 +1,94 @@ +{ + "id": "5d02c2ab-c7ad-460e-bb7f-ab67b89808e2", + "name": "harena-manager - production", + "values": [ + { + "key": "protocol", + "value": "https://", + "enabled": true + }, + { + "key": "host", + "value": "harena.ds4h.org", + "enabled": true + }, + { + "key": "port", + "value": "443", + "enabled": true + }, + { + "key": "api-version", + "value": "v1", + "enabled": true + }, + { + "key": "api-base-url", + "value": "{{protocol}}{{host}}/manager/api/{{api-version}}", + "enabled": true + }, + { + "key": "user-id", + "value": 130, + "enabled": true + }, + { + "key": "user-email", + "value": "jacinto@email.com", + "enabled": true + }, + { + "key": "user-username", + "value": "jacinto", + "enabled": true + }, + { + "key": "user-password", + "value": "jacinto", + "enabled": true + }, + { + "key": "user-token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEsImlhdCI6MTU4Mzk2ODUzMn0.FWwj3i0VFKOJakMM_1Oo6Ads0gkMYYjcmcqkE4UjbrA", + "enabled": true + }, + { + "key": "case-uuid", + "value": "d5d804b0-1876-4430-a5bf-42b442eeb26a", + "enabled": true + }, + { + "key": "case-name", + "value": "case001-development", + "enabled": true + }, + { + "key": "case-source", + "value": "Start\n=====\n\n## Case 001 (start,dialog_left)\n:NURSE Agnes: Doctor, we have a man (51 years old) who entered the emergency department reporting chest pain. His vital signs are ABP: 144x92mmHG; HR: 78bpm; RR: 21rpm; Temp: 37oC; O2Sat: 98%.\n\n* Let us go! -> Cycle 1.Begin\n\nCycle 1\n=======\n\nBegin (information)\n-------------------\n\n:PATIENT Jakob: Doctor, I am feeling chest pain since yesterday. The pain is continuous and is located just in the middle of my chest, worsening when I breathe and when I lay down on my bed. I suffer from arterial hypertension and smoke 20 cigarettes every day. My father had a “heart attack” at my age and I am very worried about it.\n\nPHYSICAL EXAMINATION
The cardiac and pulmonary auscultation are normal; chest pain does not worse with palpation of the thorax; there is no jugular stasis nor lower limb edema.\n\n:Jacinto:What do you want to do?\n\n* -> Generate hypothesis\n* -> More information\n* Call the supervisor -> Call the supervisor.A\n\nGenerate hypothesis (input)\n---------------------------\nWhat is your main diagnostic hypothesis?\n:PATIENT Jakob:.\n{?1 hypothesis:mesh#pericarditis,myopericarditis,pericardial inflammation,pericardial infection,pericardial effusion;infarction,myocardial infarction,coronary syndrome,acute coronary syndrome,ischemia,myocardial ischemia,coronary insufficiency,angina,angina pectoris}\n\n* Submit hypothesis -> Check hypothesis\n\nMore information (information)\n------------------------------\n\nMORE INFORMATION
The patient never felt chest pain before. He exercises regularly and has lost weight in the last three months. He takes amlodipine and losartan regularly. Two weeks ago, he had an auto-limited gastroenteritis episode. He denies recent travels and surgery.\n:PATIENT Jakob:.\n\n:Jacinto:What do you want to do?\n\n* Back to the case -> Cycle 1.Begin\n\nCall the supervisor\n-------------------\n\n### A (detailed)\n:SUPERVISOR Harry:\nHi! I am glad that you called me. Chest pain is an important complaint at the emergency department and we have to exclude the fatal causes: myocardial infarction (MI), acute aortic dissection (AAD), pulmonary embolism PE), hypertensive pneumothorax (HP), and Boerhaave Syndrome (BS).\n\nThe best way to find out what is happening with your patient, my young padawan, is to gather as much information as possible through history taking and physical examination. We need to search for the signs and symptoms that can guide our clinical reasoning process by changing the pre-test probabilities of each disease.\n::\n\n* See likelihood tables -> B \n\n### B (detailed)\n:SUPERVISOR Harry:.\n**Likelihood Tables**\n\nDo you know the concept of Likelihood ratio (LR)? -> Likelihood Ratio\n\n+ -> Clinical History Myocardial Infarction\n\n+ -> Physical Examination Myocardial Infarction\n\n+ -> Clinical History Aortic Dissection\n\n+ -> Physical Examination Aortic Dissection\n\n+ -> Pulmonary Embolism Wells Criteria\n\n* Continue talking -> C \n\n### C (detailed)\n:SUPERVISOR Harry:.\nHypertensive pneumothorax is more common in tall and thin young adults (primary pneumothorax) or in patients with chronic pulmonary diseases or chest trauma (secondary pneumothorax). On physical examination, we expect asymmetry in lung auscultation and the trachea may be dislocated to the contralateral side of the pneumothorax.\n\nBoerhaave Syndrome is more common in patients who presented vomiting before the chest pain started, were submitted to endoscopic procedures or had chest trauma.\n\nHow does this information can help you to solve your case?\n\n* Back to the case -> Cycle 1.Begin\n\n### Likelihood Ratio (note)\n\nLikelihood ratio (LR) - like sensitivity and specificity, LR describe the discriminatory power of features in a clinical context, estimating the probability of disease. When the LR is higher than 1, the feature increases the probability; when lower than 1, reduces it.\n\n* Back -> Supervisor B\n\n### Clinical History Myocardial Infarction (note)\n![Clinical History Myocardial Infarction](images/ebm-clinical-history-myocardial-infarction.png)\n\n* Back -> Supervisor B\n\n### Physical Examination Myocardial Infarction (note)\n![Physical Examination Myocardial Infarction](images/ebm-physical-examination-myocardial-infarction.png)\n\n* Back -> Supervisor B\n\n### Clinical History Aortic Dissection (note)\n![Clinical History Aortic Dissection](images/ebm-clinical-history-aortic-dissection.png)\n\n* Back -> Supervisor B\n\n### Physical Examination Aortic Dissection (note)\n![Physical Examination Aortic Dissection](images/ebm-physical-examination-aortic-dissection.png)\n\n* Back -> Call the supervisor B\n\n### Pulmonary Embolism Wells Criteria (note)\n![Pulmonary Embolism Wells Criteria](images/ebm-pulmonary-embolism-wells-criteria.png)\n\n* Back -> Call the supervisor B\n\nCheck hypothesis (selector)\n---------------------------\n\n:Jacinto:Let us check out your hypothesis. Highlight in green the findings that corroborate your hypothesis; in blue those that are neutral; and in red the ones speaking against your hypothesis.\n\n{{symptoms#contribution to diagnostics: ,+,=,-\nNurse: Doctor, please you have to evaluate a {man(male)} ({51 years-old(aging=51)#=}) who entered the emergency department reporting {chest pain#=}.His vital signs are {ABP: 144x92mmHG#=}; {HR: 78bpm#=}; {RR: 21rpm#=}; {Temp: 37oC#=}; {O2Sat: 98%#=}.\n\nPatient: Doctor, I am feeling chest pain since yesterday. The {pain is continuous#=} and {is located just in the middle of my chest#=}, {worsening when I breathe#+} and {when I lay down on my bed#+}. I have {arterial hypertension#-} and {I smoke 20 cigarettes(smoking=20/day)#-} every day. {My father had a \"heart attack\"#-} at my age and I am very worried about it.\n\nYou perform physical examination: {cardiac and pulmonary auscultation are normal#-}; {chest pain does not worse with palpation of the thorax#=}; {there is no jugular stasis#=} {nor lower limb edema#=}.\n}}\n\n* Submit -> Review hypothesis \n\nReview hypothesis (input)\n-------------------------\nIf you whant to review your hypothesis, type below the new hypothesis.\n:PATIENT Jakob:.\n{?1 hypothesis:mesh#pericarditis,myopericarditis,pericardial inflammation,pericardial infection,pericardial effusion;infarction,myocardial infarction,coronary syndrome,acute coronary syndrome,ischemia,myocardial ischemia,coronary insufficiency,angina,angina pectoris}\n\n* Submit -> Cycle 2.Order EKG\n\nCycle 2\n=======\n\n## Order EKG (decision_exam)\nOur patient denies any recent long trip, immobilization or surgery.\n\nThe blood pressure is symmetric in the four limbs. \n\n:EKG:.\n\n* Magnify -> Magnify EKG\n\n:Game: What do you want to do?\n* -> Generate hypothesis\n* -> More information\n* -> Call the supervisor\n\n\n## Magnify EKG (note,magnify_exam)\n\n:EKG:.\n\n* Return -> Order EKG\n\n## Generate hypothesis (input)\nWhat is your main diagnostic hypothesis?\n:PATIENT Jakob:.\n{?1 hypothesis:mesh#pericarditis,myopericarditis,pericardial inflammation,pericardial infection,pericardial effusion;infarction,myocardial infarction,coronary syndrome,acute coronary syndrome,ischemia,myocardial ischemia,coronary insufficiency,angina,angina pectoris}\n\n* Submit hypothesis -> Check hypothesis\n\n## More information (decision_exam)\n\n![EKG Description](images/ekg-description.png)\n\n* EKG Analysis\n\n:EKG:.\n\n:Game: What do you want to do?\n* Back -> Order EKG\n* Analyze EKG -> EKG Analysis\n\n## EKG Analysis (note,marker_exam)\n\n\n \n \n \n \n \n \n \n\n\n* Return -> Order EKG\n\n## Call the supervisor (decision_exam)\n\nWe did not find features that increase the likelihood of myocardial ischemia. Moreover, our patient has a pleuritic chest pain that gets worse when the patient lays down.\n\nIn the EKG we found ST-segment elevation in almost all leads. Also, we found a depression of the PR segment in the DII lead.\n\n* -> EKG Analysis\n\n:EKG:.\n\n:Game: What do you want to do?\n* Back -> Order EKG\n* Analyze EKG -> EKG Analysis\n\n## Check hypothesis (marker_exam)\n\n\n \n \n \n \n \n \n \n\n\n* Submit -> Review hypothesis\n\n## Review hypothesis (input)\nIf you whant to review your hypothesis, type below the new hypothesis.\n:PATIENT Jakob:.\n{?1 hypothesis:mesh#pericarditis,myopericarditis,pericardial inflammation,pericardial infection,pericardial effusion;infarction,myocardial infarction,coronary syndrome,acute coronary syndrome,ischemia,myocardial ischemia,coronary insufficiency,angina,angina pectoris}\n\n* Submit -> Final.Report\n\nFinal\n=====\n\nReport (detailed)\n-----------------\n\nCongratulations, my young Dr. you could helped your patient providing his diagnosis. Now, Let's review all levels of this case.\n\n:Computer:Select a final report level:\n\n* -> Level 1\n* -> Level 2.2a\n* -> Level 3.3a\n\nLevel 1 (detailed)\n------------------\n\nLevel 1: your answer was .\n\nOur patient complained about chest pain, located in the middle of his chest, worsening when he breaths and when he lay down on his bed. Both features increases the probability of pericardial disease, especially acute pericarditis. Although patient´s father died of a \"heart attack\", there were no chest pain features that increase the probability of myocardial infarction, as the pain did not irradiate to arms, the pain was not described as a pressure, neither complaining about nausea, vomiting or shortness of breath. Another differential diagnosis to consider is myopericarditis, but we not be able to find heart failure signs (pulmonary and cardiac auscultation were normal) and the patient did not complain about dyspnea. So, at the level 1, the answer to our open-ended question was Acute Pericarditis.\n\n* Next -> Level 2.2a\n* Return -> Report\n\nLevel 2\n-------\n\n### 2a (detailed)\n\n
\nLevel 2: At this level, we asked you to highlight in green all features that corroborate your hypothesis, in blue those are neutral and in red the ones speaking against your hypothesis.\n

\nYour answer:\n
\n{{player#Cycle_1.Check_hypothesis.symptoms: ,+,=,-\nNurse: Doctor, please you have to evaluate a {man(male)} ({51 years-old(aging=51)#=}) who entered the emergency department reporting {chest pain#=}.His vital signs are {ABP: 144x92mmHG#=}; {HR: 78bpm#=}; {RR: 21rpm#=}; {Temp: 37oC#=}; {O2Sat: 98%#=}.\n
\nPatient: Doctor, I am feeling chest pain since yesterday. The {pain is continuous#=} and {is located just in the middle of my chest#=}, {worsening when I breathe#+} and {when I lay down on my bed#+}. I have {arterial hypertension#-} and {I smoke 20 cigarettes(smoking=20/day)#-} every day. {My father had a \"heart attack\"#-} at my age and I am very worried about it.\n
\nYou perform physical examination: {cardiac and pulmonary auscultation are normal#-}; {chest pain does not worse with palpation of the thorax#=}; {there is no jugular stasis#=} {nor lower limb edema#=}.\n}}\n

\nOur answer: \n
\n{{answers#answers: ,+,=,-\nNurse: Doctor, please you have to evaluate a {man(male)} ({51 years-old(aging=51)#=}) who entered the emergency department reporting {chest pain#=}.His vital signs are {ABP: 144x92mmHG#=}; {HR: 78bpm#=}; {RR: 21rpm#=}; {Temp: 37oC#=}; {O2Sat: 98%#=}.\n
\nPatient: Doctor, I am feeling chest pain since yesterday. The {pain is continuous#=} and {is located just in the middle of my chest#=}, {worsening when I breathe#+} and {when I lay down on my bed#+}. I have {arterial hypertension#-} and {I smoke 20 cigarettes(smoking=20/day)#-} every day. {My father had a \"heart attack\"#-} at my age and I am very worried about it.\n
\nYou perform physical examination: {cardiac and pulmonary auscultation are normal#-}; {chest pain does not worse with palpation of the thorax#=}; {there is no jugular stasis#=} {nor lower limb edema#=}.\n}}\n
\n\n* Next -> 2b\n* Return -> Final.Report\n\n### 2b (detailed)\n\nAfter checking the hypothesis you reviewed your answer to: .\n\nIn acute pericarditis, patients are usually young, most cases are reported under 50 years old, but it can be diagnosed at any age. There is no vital signs features that increase the probability of this condition. Some patients may present fever and tachycardia, but it´s not common signs. So, when vital signs are normal, we cannot confirm or exclude this diagnosis.\n\nIn clinical history, two features increase the probability of the chest pain being related to a pericardial disease: worsening with breathing; and worsening when the patient lay down. \n\n* Next -> 2c\n* Return -> Final.Report\n\n### 2c (detailed)\n\nAs the patient has arterial hypertension, is smoker and his father died of a \"heart attack\" we could consider myocardial infarction as one of the diagnosis. But considering chest pain features of our patient, there is no one that increases this possibility. So, these features may lead us to cognitive error if we consider myocardial infarction as the main diagnosis (which is wrong). \n\nIn physical examination in patients with acute pericarditis, we may find pericardial rub, one of the diagnostic criteria. So, when we did not find it, the probability of the disease is reduced, but did not exclude the diagnosis. It is crucial to look for the other diagnostic criteria.\n\n* Next -> Level 3.3a\n* Return -> Final.Report\n\nLevel 3\n-------\n\n### 3a (detailed)\n\nMy young Dr, the EKG interpretation was very helpful to solve our case.\n\nWe found a diffuse ST-segment elevation, and a PR-segment depression in DII lead. These findings, associated to the clinical scenario, strongly indicate the main hypothesis of Acute Pericarditis.\n\n* Next -> 3b\n* Return -> Final.Report\n\n### 3b (detailed)\n\nMy young Dr, the EKG interpretation was very helpful to solve our case.\n\nWe found a diffuse ST-segment elevation, and a PR-segment depression in DII lead. These findings, associated to the clinical scenario, strongly indicate the main hypothesis of Acute Pericarditis.\n\n* Next -> 3c\n* Return -> Final.Report\n\n### 3c (detailed)\n
\nIn the following table, we provide the diagnostic criteria for acute pericaditis and myopericarditis:\n\n![Clinical History Myocardial Infarction](images/ebm-pericarditis.png)\n\nCooper LT, Imazio M. Management of myopericarditis. Expert Rev Cardiovasc Ther 2013; 11(2): 193-201.\n\nOur patient fullfill the following criteria: 1 and 3. So, acute pericarditis is the main diagnostic hypothesis.\n
\n\n* Return -> Final.Report \n", + "enabled": true + }, + { + "key": "filterBy-user", + "value": "user", + "enabled": true + }, + { + "key": "case-id", + "value": "", + "enabled": true + }, + { + "key": "user-refreshToken", + "value": "", + "enabled": true + }, + { + "key": "quest-id", + "value": "", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2020-10-25T22:36:50.123Z", + "_postman_exported_using": "Postman/7.34.0" +} \ No newline at end of file diff --git a/src/adonisjs/app/Controllers/Http/v1/AuthController.js b/src/adonisjs/app/Controllers/Http/v1/AuthController.js index 3aa8655..4b7882e 100644 --- a/src/adonisjs/app/Controllers/Http/v1/AuthController.js +++ b/src/adonisjs/app/Controllers/Http/v1/AuthController.js @@ -3,13 +3,16 @@ const Logger = use('Logger') const User = use('App/Models/v1/User') +const Institution = use('App/Models/v1/Institution') class AuthController { async checkToken ({ request, auth, response }) { try { // console.log('====Checking token...') if(await auth.check()){ - response.json({token:'token valid', username: auth.user.username}) + let userInstitution = await Institution.findBy('id', auth.user.institution_id) + response.json({token:'token valid', username: auth.user.username, + grade: auth.user.grade, institution: userInstitution.acronym, institutionId: auth.user.institution_id}) } // console.log('====Token valid') } catch (error) { diff --git a/src/adonisjs/app/Controllers/Http/v1/CaseController.js b/src/adonisjs/app/Controllers/Http/v1/CaseController.js index c888f63..de02c51 100644 --- a/src/adonisjs/app/Controllers/Http/v1/CaseController.js +++ b/src/adonisjs/app/Controllers/Http/v1/CaseController.js @@ -11,6 +11,8 @@ const Case = use('App/Models/v1/Case') const CaseVersion = use('App/Models/v1/CaseVersion') const Institution = use('App/Models/v1/Institution') const Permission = use('App/Models/v1/Permission') +const Property = use('App/Models/v1/Property') +const CaseProperty = use('App/Models/v1/CaseProperty') const uuidv4 = require('uuid/v4') @@ -36,18 +38,33 @@ class CaseController { * @param {Response} ctx.response * @param {View} ctx.view */ - async show ({ params, response }) { + async show ({ request, response }) { try { - const c = await Case.find(params.id) + + const c = await Case.find(request.input('caseId')) if (c != null) { const versions = await CaseVersion.query() - .where('case_id', '=', params.id) + .where('case_id', '=', request.input('caseId')) .orderBy('created_at', 'asc') .fetch() + const properties = await Database + .select(['properties.title', 'case_properties.value']) + .from('case_properties') + .leftJoin('properties', 'case_properties.property_id', 'properties.id') + .where('case_properties.case_id', request.input('caseId')) + + var prop = {} + for(let p in properties){ + let title = properties[p].title + let value = properties[p].value + prop[title] = value + } + c.source = versions.last().source c.versions = versions + c.property = prop const institution = await Institution.find(c.institution_id) c.institution = institution.acronym @@ -112,11 +129,11 @@ class CaseController { } /** * Update case details. PUT or PATCH case/:id */ - async update ({ params, request, response }) { + async update ({ request, response }) { const trx = await Database.beginTransaction() try { - const c = await Case.find(params.id) + const c = await Case.find(request.input('caseId')) if (c != null) { c.title = request.input('title') || null @@ -171,10 +188,10 @@ class CaseController { * @param {Request} ctx.request * @param {Response} ctx.response */ - async destroy ({ params, response }) { + async destroy ({ request, response }) { const trx = await Database.beginTransaction() try { - const c = await Case.findBy('id', params.id) + const c = await Case.findBy('id', request.input('caseId')) if (c != null) { await c.versions().delete() @@ -198,6 +215,136 @@ class CaseController { } } + async share ({params, request, response}){ + const trx = await Database.beginTransaction() + + try { + const entity = request.input('entity') + const subject = request.input('subject') + const subject_grade = request.input('subject_grade') + const clearance = request.input('clearance') + const table_id = request.input('table_id').split(',') + // console.log(entity) + // console.log(subject) + // console.log(clearance) + // console.log(table_id) + + for (let c in table_id){ + // console.log('============ case for') + console.log(table_id[c]) + if(await Case.findBy('id', table_id[c])){ + // console.log('================================================ case added') + // console.log(table_id[c]) + let permission = new Permission() + permission.id = await uuidv4() + permission.entity = entity + permission.subject = subject + permission.subject_grade = subject_grade + permission.clearance = clearance + permission.table = 'cases' + permission.table_id = table_id[c] + await permission.save(trx) + }else return response.json('Could not find the case id, please review and try again') + } + + trx.commit() + return response.json('Cases shared successfully!') + } catch (e) { + trx.rollback() + console.log(e) + return response.status(500).json({ message: e.message }) + } + + } + + async storeProperty ({params, request, auth, response}) { + const trx = await Database.beginTransaction() + try { + const case_id = request.input('case_id') + const property_title = request.input('property_title') + const property_value = request.input('property_value') + + const property = await Property.findOrCreate( + { title: property_title }, + { id: await uuidv4(), title: property_title }, trx + ) + // const caseProperty = new CaseProperty() + // caseProperty.case_id = case_id + // caseProperty.property_id = property.id + // caseProperty.value = property_value + let caseProperty = await CaseProperty.findOrCreate( + { case_id: case_id, property_id: property.id}, + { case_id: case_id, property_id: property.id, value: property_value}, trx + ) + + await property.save(trx) + await caseProperty.save(trx) + + trx.commit() + + return response.json({property: property, case_property: caseProperty}) + + } catch (e) { + trx.rollback() + console.log('============catch error storeProperty') + console.log(e) + return response.status(e.status).json({ message: e.message}) + } + } + + async updateProperty ({request, auth, response}) { + const trx = await Database.beginTransaction() + try { + const case_id = request.input('case_id') + const property_title = request.input('property_title') + const property_value = request.input('property_value') + + const property = await Property.findBy('title', property_title) + + // const caseProperty = await CaseProperty.findOrCreate( + // { case_id: case_id, property_id: property.id }, + // { case_id: case_id, property_id: property.id}, trx + // ) + + let caseProperty = await CaseProperty + .query() + .where('property_id', property.id) + .where('case_id', case_id) + .fetch() + caseProperty = caseProperty.last() + + await trx + .table('case_properties') + .where('property_id', property.id) + .where('case_id', case_id) + .update({ value: property_value,}) + // console.log('============ db case property') + // console.log(caseProperty) + + caseProperty.value = property_value + + // console.log('============ value') + // console.log(caseProperty.value) + trx.commit() + + + return response.json(caseProperty) + } catch (e) { + trx.rollback() + console.log('============catch error updateProperty') + console.log(e) + return response.status(e.status).json({ message: e.message }) + } + } + + async deleteProperty ({params, request, auth, response}) { + try { + + } catch (e) { + return response.status(e.status).json({ message: e.message }) + } + } + } module.exports = CaseController diff --git a/src/adonisjs/app/Controllers/Http/v1/CategoryController.js b/src/adonisjs/app/Controllers/Http/v1/CategoryController.js index 7925499..3686048 100644 --- a/src/adonisjs/app/Controllers/Http/v1/CategoryController.js +++ b/src/adonisjs/app/Controllers/Http/v1/CategoryController.js @@ -76,32 +76,55 @@ class CategoryController { async listCases ({ request, response, auth }) { try { const user = await auth.user + + const clearance = parseInt(request.input('clearance')) const categoryId = request.input('categoryId') const category = await Category.find(categoryId) var publishedFilter = parseInt(request.input('published')) || 0 + const institutionFilter = request.input('fInstitution') || `%` + const userTypeFilter = request.input('fUserType') || `%` + const specialtyFilter = request.input('fSpecialty') || `%` + + const test = await Database .select([ 'cases.id', 'cases.title','cases.description', 'cases.language', 'cases.domain', - 'cases.specialty', 'cases.keywords', 'cases.complexity', 'cases.original_date', - 'cases.author_grade', 'cases.published', 'users.username']) + 'cases.specialty', 'cases.keywords', 'cases.complexity', 'cases.original_date', + 'cases.author_grade', 'cases.published', 'users.username', + 'institutions.title AS institution', 'institutions.acronym AS institution_acronym', + 'institutions.country AS institution_country', 'cases.created_at']) .distinct('cases.id') .from('cases') .leftJoin('permissions', 'cases.id', 'permissions.table_id') .join('users', 'users.id', 'cases.author_id') + .join('institutions', 'users.institution_id', 'institutions.id') .where('cases.category_id', category.id) .where('cases.published', '>=', publishedFilter) + .where('cases.institution_id', 'like', institutionFilter) + .where('cases.author_grade', 'like', userTypeFilter) + .where(function(){ + if (specialtyFilter != '%') + this.where('cases.specialty', 'like', specialtyFilter) + }) + .where(function(){ this - .where('cases.author_id', user.id) - .orWhere(function () { + .where('cases.author_id', user.id) + .orWhere(function () { + this + .where('permissions.entity', 'institution') + .where('permissions.subject', user.institution_id) + .where('permissions.clearance', '>=', clearance) + .where(function(){ this - .where('permissions.entity', 'institution') - .where('permissions.subject', user.institution_id) - .where('permissions.clearance', '>=', clearance) + .whereNull('permissions.subject_grade') + .orWhere('permissions.subject_grade', user.grade) }) + }) }) + .orderBy('cases.created_at', 'desc') return response.json(test) } catch (e) { diff --git a/src/adonisjs/app/Controllers/Http/v1/InstitutionController.js b/src/adonisjs/app/Controllers/Http/v1/InstitutionController.js index 2bf94a9..9d19cba 100644 --- a/src/adonisjs/app/Controllers/Http/v1/InstitutionController.js +++ b/src/adonisjs/app/Controllers/Http/v1/InstitutionController.js @@ -22,6 +22,22 @@ class InstitutionController { return response.status(500).json({ message: e.message }) } } + + async listInstitutions ({ request, response }) { + try { + const institutions = await Institution + .query() + .where('acronym', '!=', 'uni') + .fetch() + + + return response.json(institutions) + } catch (e) { + console.log(e) + return response.status(500).json({ message: e.message }) + } + } + } module.exports = InstitutionController diff --git a/src/adonisjs/app/Controllers/Http/v1/UserController.js b/src/adonisjs/app/Controllers/Http/v1/UserController.js index 6e0f919..abd372b 100644 --- a/src/adonisjs/app/Controllers/Http/v1/UserController.js +++ b/src/adonisjs/app/Controllers/Http/v1/UserController.js @@ -13,21 +13,21 @@ const User = use('App/Models/v1/User') const Institution = use('App/Models/v1/Institution') const Artifact = use('App/Models/v1/Artifact') const Quest = use('App/Models/v1/Quest') -const Property = use('App/Models/Property') +const Property = use('App/Models/v1/Property') const uuidv4 = require('uuid/v4') const Env = use('Env') class UserController { /** - * Show a list of all users. - * GET users - * - * @param {object} ctx - * @param {Request} ctx.request - * @param {Response} ctx.response - * @param {View} ctx.view - */ + * Show a list of all users. + * GET users + * + * @param {object} ctx + * @param {Request} ctx.request + * @param {Response} ctx.response + * @param {View} ctx.view + */ async index ({ request, response, view, auth }) { try { const users = await User.all() @@ -38,14 +38,14 @@ class UserController { } /** - * Display a single user. - * GET users/:id - * - * @param {object} ctx - * @param {Request} ctx.request - * @param {Response} ctx.response - * @param {View} ctx.view - */ + * Display a single user. + * GET users/:id + * + * @param {object} ctx + * @param {Request} ctx.request + * @param {Response} ctx.response + * @param {View} ctx.view + */ async show ({ params, request, response, view }) { try { const user = await User.find(params.id) @@ -58,13 +58,13 @@ class UserController { } /** - * Create/save a new user. - * POST users - * - * @param {object} ctx - * @param {Request} ctx.request - * @param {Response} ctx.response - */ + * Create/save a new user. + * POST users + * + * @param {object} ctx + * @param {Request} ctx.request + * @param {Response} ctx.response + */ async store ({ request, auth, response }) { try { const user = new User() @@ -97,23 +97,23 @@ class UserController { } /** - * Update user details. - * PUT or PATCH users/:id - * - * @param {object} ctx - * @param {Request} ctx.request - * @param {Response} ctx.response - - */ + * Update user details. + * PUT or PATCH users/:id + * + * @param {object} ctx + * @param {Request} ctx.request + * @param {Response} ctx.response + + */ async update ({ params, request, response, auth }) { try { const user = await User.find(auth.user.id) const updatedUser = { - username : request.input('username') || user.username, - email : request.input('email') || user.email, - login : request.input('login') || user.login, - grade : request.input('grade') || user.grade + username : request.input('username') || user.username, + email : request.input('email') || user.email, + login : request.input('login') || user.login, + grade : request.input('grade') || user.grade } if (user != null) { @@ -161,7 +161,7 @@ class UserController { } /** Delete a user with id. - * DELETE user/:id */ + * DELETE user/:id */ async destroy ({ params, response, auth }) { try { const user = await User.find(params.id) @@ -177,7 +177,7 @@ class UserController { } -// @BROKEN + // @BROKEN async list_quests ({ request, response, auth }) { try { const user = await auth.user @@ -193,34 +193,101 @@ class UserController { try { const user = await auth.user - const clearance = parseInt(request.input('clearance')) + const clearance = parseInt(request.input('clearance')) || 10 var publishedFilter = parseInt(request.input('published')) || 0 - request.input('published') != null - // Atualmente retorna somente casos compartilhados com institution, é preciso aumentar a sql pra comportar outros escopos: grupos, only me, system, etc... - // Return cases which the user is author AND cases which she have access permissions - const result = await Database + const institutionFilter = request.input('fInstitution') || `%` + const userTypeFilter = request.input('fUserType') || `%` + const specialtyFilter = request.input('fSpecialty') || `%` + const propertyFilter = request.input('fProperty') || null + const propertyValueFilter = request.input('fPropertyValue') || '%' + let result = null + // console.log(institutionFilter) + // console.log(userTypeFilter) + + if(propertyFilter != null){ + const selectPropertyTitle = ('case_properties.value AS ' + propertyFilter) + result = await Database .select([ 'cases.id', 'cases.title','cases.description', 'cases.language', 'cases.domain', - 'cases.specialty', 'cases.keywords', 'cases.complexity', 'cases.original_date', - 'cases.author_grade', 'cases.published', 'users.username']) + 'cases.specialty', 'cases.keywords', 'cases.complexity', 'cases.original_date', + 'cases.author_grade', 'cases.published', 'users.username', + 'institutions.title AS institution', 'institutions.acronym AS institution_acronym', + 'institutions.country AS institution_country', 'cases.created_at', + Database.raw(`CASE WHEN case_properties.value = 0 AND properties.title = 'feedback' + THEN 'Waiting for feedback' WHEN case_properties.value = 1 AND properties.title = 'feedback' + THEN 'Feedback complete' ELSE case_properties.value END AS ?`,[propertyFilter])]) .distinct('cases.id') .from('cases') .leftJoin('permissions', 'cases.id', 'permissions.table_id') + .join('case_properties', 'case_properties.case_id', 'cases.id') + .join('properties', 'properties.id', 'case_properties.property_id') .join('users', 'users.id', 'cases.author_id') + .join('institutions', 'users.institution_id', 'institutions.id') + .where('properties.title', propertyFilter) + .where('case_properties.value','like', propertyValueFilter) .where('cases.published', '>=', publishedFilter) + .where('cases.institution_id', 'like', institutionFilter) + .where('cases.author_grade', 'like', userTypeFilter) + .where(function(){ + if (specialtyFilter != '%') + this.where('cases.specialty', 'like', specialtyFilter) + }) + .where(function(){ this - .where('cases.author_id', user.id) - .orWhere(function () { + .where('cases.author_id', user.id) + .orWhere(function () { + this + .where('permissions.entity', 'institution') + .where('permissions.subject', user.institution_id) + .where('permissions.clearance', '>=', clearance) + .where(function(){ this - .where('permissions.entity', 'institution') - .where('permissions.subject', user.institution_id) - .where('permissions.clearance', '>=', clearance) + .whereNull('permissions.subject_grade') + .orWhere('permissions.subject_grade', user.grade) }) + }) }) + .orderBy('cases.created_at', 'desc') + }else{ + result = await Database + .select([ 'cases.id', 'cases.title','cases.description', 'cases.language', 'cases.domain', + 'cases.specialty', 'cases.keywords', 'cases.complexity', 'cases.original_date', + 'cases.author_grade', 'cases.published', 'users.username', + 'institutions.title AS institution', 'institutions.acronym AS institution_acronym', + 'institutions.country AS institution_country', 'cases.created_at']) + .distinct('cases.id') + .from('cases') + .leftJoin('permissions', 'cases.id', 'permissions.table_id') + .join('users', 'users.id', 'cases.author_id') + .join('institutions', 'users.institution_id', 'institutions.id') + .where('cases.published', '>=', publishedFilter) + .where('cases.institution_id', 'like', institutionFilter) + .where('cases.author_grade', 'like', userTypeFilter) + .where(function(){ + if (specialtyFilter != '%') + this.where('cases.specialty', 'like', specialtyFilter) + }) + .where(function(){ + this + .where('cases.author_id', user.id) + .orWhere(function () { + this + .where('permissions.entity', 'institution') + .where('permissions.subject', user.institution_id) + .where('permissions.clearance', '>=', clearance) + .where(function(){ + this + .whereNull('permissions.subject_grade') + .orWhere('permissions.subject_grade', user.grade) + }) + }) + }) + .orderBy('cases.created_at', 'desc') + } console.log(result) @@ -232,16 +299,16 @@ class UserController { } -// @broken + // @broken async list_cases_by_quests ({ params, response, auth }) { try { const user = await auth.user Database - .select('*') - .from('quests_users') - .where('user_id', user.id) - .leftJoin('cases', 'quests.case_id', 'cases.id') + .select('*') + .from('quests_users') + .where('user_id', user.id) + .leftJoin('cases', 'quests.case_id', 'cases.id') const quests = await user.quests().fetch() @@ -257,11 +324,11 @@ class UserController { const user = await auth.user const resultQuest = await Database - .select('*') - .from('quests_users') - .where('user_id', user.id) - .whereIn('permission', ['write', 'share', 'delete']) - .leftJoin('quests', 'quests_users.quest_id', 'quests.id') + .select('*') + .from('quests_users') + .where('user_id', user.id) + .whereIn('permission', ['write', 'share', 'delete']) + .leftJoin('quests', 'quests_users.quest_id', 'quests.id') const base_url = Env.getOrFail('APP_URL') const quests = [] @@ -291,11 +358,11 @@ class UserController { const user = await auth.user const resultQuest = await Database - .select('*') - .from('quests_users') - .where('user_id', user.id) - .where('permission', 'read') - .leftJoin('quests', 'quests_users.quest_id', 'quests.id') + .select('*') + .from('quests_users') + .where('user_id', user.id) + .where('permission', 'read') + .leftJoin('quests', 'quests_users.quest_id', 'quests.id') const base_url = Env.getOrFail('APP_URL') const quests = [] diff --git a/src/adonisjs/app/Middleware/CheckCasePermission.js b/src/adonisjs/app/Middleware/CheckCasePermission.js index 5dd980b..5b670a8 100644 --- a/src/adonisjs/app/Middleware/CheckCasePermission.js +++ b/src/adonisjs/app/Middleware/CheckCasePermission.js @@ -36,6 +36,11 @@ class CheckPermissionForGivenCase { .where('permissions.entity', 'institution') .where('permissions.subject', auth.user.institution_id) .where('permissions.clearance', '>=', 1) + .where(function(){ + this + .whereNull('permissions.subject_grade') + .orWhere('permissions.subject_grade', auth.user.grade) + }) }) .count() } @@ -51,6 +56,11 @@ class CheckPermissionForGivenCase { .where('permissions.entity', 'institution') .where('permissions.subject', auth.user.institution_id) .where('permissions.clearance', '>=', 2) + .where(function(){ + this + .whereNull('permissions.subject_grade') + .orWhere('permissions.subject_grade', auth.user.grade) + }) }) .count() } @@ -66,6 +76,11 @@ class CheckPermissionForGivenCase { .where('permissions.entity', 'institution') .where('permissions.subject', auth.user.institution_id) .where('permissions.clearance', '>=', 4) + .where(function(){ + this + .whereNull('permissions.subject_grade') + .orWhere('permissions.subject_grade', auth.user.grade) + }) }) .count() } diff --git a/src/adonisjs/app/Models/v1/CaseProperty.js b/src/adonisjs/app/Models/v1/CaseProperty.js new file mode 100644 index 0000000..a95252f --- /dev/null +++ b/src/adonisjs/app/Models/v1/CaseProperty.js @@ -0,0 +1,15 @@ +'use strict' + +/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ +const Model = use('Model') + +class CaseProperty extends Model { + static get incrementing () { + return false + } + static get table () { + return 'case_properties' + } +} + +module.exports = CaseProperty diff --git a/src/adonisjs/app/Models/Property.js b/src/adonisjs/app/Models/v1/Property.js similarity index 100% rename from src/adonisjs/app/Models/Property.js rename to src/adonisjs/app/Models/v1/Property.js diff --git a/src/adonisjs/database/migrations/1612398386445_update_case_drop_course_id_schema.js b/src/adonisjs/database/migrations/1612398386445_update_case_drop_course_id_schema.js new file mode 100644 index 0000000..05dc820 --- /dev/null +++ b/src/adonisjs/database/migrations/1612398386445_update_case_drop_course_id_schema.js @@ -0,0 +1,21 @@ +'use strict' + +/** @type {import('@adonisjs/lucid/src/Schema')} */ +const Schema = use('Schema') + +class UpdateCaseDropCourseIdSchema extends Schema { + up () { + this.table('users', (table) => { + table.dropForeign('course_id') + table.dropColumn('course_id') + }) + } + + down () { + this.table('users', (table) => { + table.uuid('course_id').references('id').inTable('courses').index('course_id') + }) + } +} + +module.exports = UpdateCaseDropCourseIdSchema diff --git a/src/adonisjs/database/migrations/1612398605359_update_permissions_add_subject_grade_schema.js b/src/adonisjs/database/migrations/1612398605359_update_permissions_add_subject_grade_schema.js new file mode 100644 index 0000000..14326b6 --- /dev/null +++ b/src/adonisjs/database/migrations/1612398605359_update_permissions_add_subject_grade_schema.js @@ -0,0 +1,20 @@ +'use strict' + +/** @type {import('@adonisjs/lucid/src/Schema')} */ +const Schema = use('Schema') + +class UpdatePermissionsAddSubjectGradeSchema extends Schema { + up () { + this.table('permissions', (table) => { + table.string('subject_grade', 20) + }) + } + + down () { + this.table('permissions', (table) => { + table.dropColumn('subject_grade') + }) + } +} + +module.exports = UpdatePermissionsAddSubjectGradeSchema diff --git a/src/adonisjs/database/seeds/InitialSeeder.js b/src/adonisjs/database/seeds/InitialSeeder.js index ed7f677..97e3c91 100644 --- a/src/adonisjs/database/seeds/InitialSeeder.js +++ b/src/adonisjs/database/seeds/InitialSeeder.js @@ -14,7 +14,7 @@ const Factory = use('Factory') const Institution = use('App/Models/v1/Institution') -const Property = use('App/Models/Property') +const Property = use('App/Models/v1/Property') const CaseArtifacts = use('App/Models/CaseArtifact') const CaseVersion = use('App/Models/v1/CaseVersion') const Case = use('App/Models/v1/Case') diff --git a/src/adonisjs/start/routes.js b/src/adonisjs/start/routes.js index b58b5d8..e41166a 100644 --- a/src/adonisjs/start/routes.js +++ b/src/adonisjs/start/routes.js @@ -66,10 +66,14 @@ Route.group(() => { */ Route.group(() => { Route.post( '', 'v1/CaseController.store') - Route.put( ':id', 'v1/CaseController.update').middleware(['case_permission:write']) - Route.delete(':id', 'v1/CaseController.destroy').middleware(['case_permission:delete']) + Route.put( '', 'v1/CaseController.update').middleware(['case_permission:write']) + Route.delete('', 'v1/CaseController.destroy').middleware(['case_permission:delete']) + Route.post('share', 'v1/CaseController.share').middleware(['case_permission:share']) + + Route.post('property', 'v1/CaseController.storeProperty').middleware(['auth', 'case_permission:write']) + Route.put('property', 'v1/CaseController.updateProperty').middleware(['auth', 'case_permission:write']) }).prefix('/api/v1/case').middleware(['auth', 'is:author']) -Route.get( '/api/v1/case/:id', 'v1/CaseController.show').middleware(['auth', 'case_permission:read']) +Route.get( '/api/v1/case', 'v1/CaseController.show').middleware(['auth', 'case_permission:read']) /* @@ -134,12 +138,27 @@ Route.group(() => { Route.group(() => { Route.post( '', 'v1/CategoryController.store') Route.post( 'link/case', 'v1/CategoryController.linkCase') - Route.get( 'list', 'v1/CategoryController.listCategories') - Route.get( 'cases', 'v1/CategoryController.listCases') Route.put( ':id', 'v1/CategoryController.update') }).prefix('/api/v1/category').middleware('auth', 'is:author') +Route.group(() => { + Route.get( 'list', 'v1/CategoryController.listCategories') + Route.get( 'cases', 'v1/CategoryController.listCases') + +}).prefix('/api/v1/category').middleware('auth') + +/* +|---------------------------------------------------------------------------------------------- +| api: v1 +| resource: /institution +|---------------------------------------------------------------------------------------------- +*/ +Route.group(() => { + + Route.get( '', 'v1/InstitutionController.listInstitutions').middleware(['auth']) +}).prefix('/api/v1/institutions') + /* |----------------------------------------------------------------------------------------------