We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Incorrect usage of slashes
## Current Behavior

MedTagger services incorrectly use slashes at the end of namespaces making it incorrect according to REST practises. E.g endpoint for returning all scans looks like this:

`GET /api/v1/scans/`

## Expected Behavior

MedTagger services should not use slashes at the end of namespaces. E.g endpoint for returning all scans should look like this:

`GET /api/v1/scans`

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `backend/medtagger/api/scans/service_rest.py`
Content:
```
1 """Module responsible for definition of Scans service available via HTTP REST API."""
2 import json
3 from typing import Any
4 
5 from flask import request
6 from flask_restplus import Resource
7 from jsonschema import validate, ValidationError, Draft4Validator
8 from jsonschema.exceptions import best_match
9 
10 from medtagger.types import ScanID
11 from medtagger.api import api
12 from medtagger.api.exceptions import InvalidArgumentsException
13 from medtagger.api.scans import business, serializers
14 from medtagger.api.security import login_required, role_required, require_one_of_roles
15 from medtagger.api.scans.serializers import elements_schema
16 
17 scans_ns = api.namespace('scans', 'Methods related with scans')
18 
19 
20 @scans_ns.route('/')
21 class Scans(Resource):
22     """Endpoint that can create new scan."""
23 
24     @staticmethod
25     @login_required
26     @role_required('doctor', 'admin')
27     @scans_ns.expect(serializers.in__new_scan)
28     @scans_ns.marshal_with(serializers.out__new_scan)
29     @scans_ns.doc(security='token')
30     @scans_ns.doc(description='Creates empty scan.')
31     @scans_ns.doc(responses={201: 'Success'})
32     def post() -> Any:
33         """Create empty scan."""
34         payload = request.json
35         dataset_key = payload['dataset']
36         number_of_slices = payload['number_of_slices']
37         if not business.dataset_is_valid(dataset_key):
38             raise InvalidArgumentsException('Dataset "{}" is not available.'.format(dataset_key))
39 
40         scan = business.create_empty_scan(dataset_key, number_of_slices)
41         return scan, 201
42 
43 
44 @scans_ns.route('/random')
45 class Random(Resource):
46     """Endpoint that returns random scan for labeling from specified task."""
47 
48     @staticmethod
49     @login_required
50     @scans_ns.expect(serializers.args__random_scan)
51     @scans_ns.marshal_with(serializers.out__random_scan)
52     @scans_ns.doc(security='token')
53     @scans_ns.doc(description='Returns random scan from task.')
54     @scans_ns.doc(responses={200: 'Success', 400: 'Invalid arguments', 404: 'No Scans available'})
55     def get() -> Any:
56         """Return random Scan."""
57         args = serializers.args__random_scan.parse_args(request)
58         task_key = args.task
59         return business.get_random_scan(task_key)
60 
61 
62 @scans_ns.route('/<string:scan_id>/<string:task_key>/label')
63 @scans_ns.param('scan_id', 'Scan identifier')
64 @scans_ns.param('task_key', 'Key of Task')
65 class Label(Resource):
66     """Endpoint that stores label for given scan."""
67 
68     @staticmethod
69     @login_required
70     @scans_ns.expect(serializers.in__label)
71     @scans_ns.marshal_with(serializers.out__label)
72     @scans_ns.doc(security='token')
73     @scans_ns.doc(description='Stores label and assigns it to given scan.')
74     @scans_ns.doc(responses={201: 'Successfully saved', 400: 'Invalid arguments', 404: 'Could not find scan or tag'})
75     def post(scan_id: ScanID, task_key: str) -> Any:
76         """Add new Label for given scan.
77 
78         This endpoint needs a multipart/form-data content where there is one mandatory section called "label".
79         Such section will contain a JSON payload with representation of a Label. If such Label needs additional
80         information like images (binary mask), please attach them as a separate part.
81 
82         Here is an example CURL command that sends Label with Brush Element:
83 
84             $> curl -v
85                     -H "Content-Type:multipart/form-data"
86                     -H "Authorization: Bearer MEDTAGGER_API_TOKEN"
87                     -F "SLICE_1=@"/Users/jakubpowierza/Desktop/test.png""
88                     -F "label={"elements": [{"width": 1, "height": 1, "image_key": "SLICE_1",
89                                "slice_index": 1, "tag": "LEFT_KIDNEY", "tool": "BRUSH"}],
90                                "labeling_time": 0.1};type=application/json"
91                      http://localhost:51000/api/v1/scans/c5102707-cb36-4869-8041-f00421c03fa1/MARK_KIDNEYS/label
92         """
93         is_predefined = (request.args.get('is_predefined', 'false') == 'true')
94         if is_predefined:
95             require_one_of_roles({'doctor', 'admin'})
96 
97         files = {name: file_data.read() for name, file_data in request.files.items()}
98         label = json.loads(request.form['label'])
99         elements = label['elements']
100         try:
101             validate(elements, elements_schema)
102         except ValidationError:
103             validator = Draft4Validator(elements_schema)
104             errors = validator.iter_errors(elements)
105             best_error = best_match(errors)
106             raise InvalidArgumentsException(best_error.message)
107 
108         business.validate_label_payload(label, task_key, files)
109 
110         labeling_time = label['labeling_time']
111         comment = label.get('comment')
112         label = business.add_label(scan_id, task_key, elements, files, labeling_time, comment, is_predefined)
113         return label, 201
114 
115 
116 @scans_ns.route('/<string:scan_id>')
117 @scans_ns.param('scan_id', 'Scan identifier')
118 class Scan(Resource):
119     """Endpoint that returns scan for the given scan id."""
120 
121     @staticmethod
122     @login_required
123     @scans_ns.marshal_with(serializers.out__scan)
124     @scans_ns.doc(security='token')
125     @scans_ns.doc(description='Returns scan with given scan_id.')
126     @scans_ns.doc(responses={200: 'Success', 404: 'Could not find scan'})
127     def get(scan_id: ScanID) -> Any:
128         """Return scan for the given scan_id."""
129         return business.get_scan(scan_id)
130 
131 
132 @scans_ns.route('/<string:scan_id>/skip')
133 @scans_ns.param('scan_id', 'Scan identifier')
134 class SkipScan(Resource):
135     """Endpoint that allows for skipping given Scan."""
136 
137     @staticmethod
138     @login_required
139     @scans_ns.doc(security='token')
140     @scans_ns.doc(description='Increases skip count of a scan with given scan_id.')
141     @scans_ns.doc(responses={200: 'Success', 404: 'Could not find scan'})
142     def post(scan_id: ScanID) -> Any:
143         """Increases skip count of a scan with given scan_id."""
144         if not business.skip_scan(scan_id):
145             return '', 404
146         return '', 200
147 
148 
149 @scans_ns.route('/<string:scan_id>/slices')
150 @scans_ns.param('scan_id', 'Scan identifier')
151 class ScanSlices(Resource):
152     """Endpoint that allows for uploading Slices to given Scan."""
153 
154     @staticmethod
155     @login_required
156     @scans_ns.marshal_with(serializers.out__new_slice)
157     @scans_ns.doc(security='token')
158     @scans_ns.doc(description='Returns newly created Slice.')
159     @scans_ns.doc(responses={201: 'Success', 400: 'Invalid arguments'})
160     def post(scan_id: ScanID) -> Any:
161         """Upload Slice for given Scan."""
162         image = request.files['image']
163         image_data = image.read()
164         new_slice = business.add_new_slice(scan_id, image_data)
165         return new_slice, 201
166
```

Path: `backend/medtagger/api/users/service.py`
Content:
```
1 """Module responsible for defining endpoints for users administration."""
2 from typing import Any
3 
4 from flask import request
5 from flask_restplus import Resource
6 
7 from medtagger.api import api
8 from medtagger.api.exceptions import AccessForbiddenException
9 from medtagger.api.users import serializers
10 from medtagger.api.users.business import get_all_users, set_user_role, set_user_info, set_user_settings
11 from medtagger.api.utils import get_current_user
12 from medtagger.api.security import login_required, role_required
13 
14 users_ns = api.namespace('users', 'Users management')
15 
16 
17 @users_ns.route('/')
18 class GetUsers(Resource):
19     """Get all users endpoint."""
20 
21     @staticmethod
22     @login_required
23     @role_required('admin')
24     @users_ns.marshal_with(serializers.users_list)
25     @users_ns.doc(security='token')
26     def get() -> Any:
27         """Get all users endpoint."""
28         users = get_all_users()
29         return {'users': users}, 200
30 
31 
32 @users_ns.route('/<int:user_id>/role')
33 class SetRole(Resource):
34     """Set user's role."""
35 
36     @staticmethod
37     @login_required
38     @role_required('admin')
39     @users_ns.doc(security='token')
40     def put(user_id: int) -> Any:
41         """Set user's role."""
42         set_user_role(user_id, request.json['role'])
43         return {'success': True}, 200
44 
45 
46 @users_ns.route('/info')
47 class GetUserInfo(Resource):
48     """Get current user information."""
49 
50     @staticmethod
51     @login_required
52     @users_ns.marshal_with(serializers.user)
53     @users_ns.doc(security='token')
54     @users_ns.doc(responses={200: 'Successfully retrieved data.'})
55     def get() -> Any:
56         """Get user info."""
57         user = get_current_user()
58         return user, 200
59 
60 
61 @users_ns.route('/<int:user_id>/settings')
62 class SetUserSettings(Resource):
63     """Set user's settings."""
64 
65     @staticmethod
66     @login_required
67     @users_ns.doc(security='token')
68     def post(user_id: int) -> Any:
69         """Set current user's settings. If settings' param is not specified in request, it is not updated."""
70         user = get_current_user()
71         if user.id != user_id:
72             raise AccessForbiddenException("Cannot update settings for someone else.")
73         if request.json.get('skipTutorial', None) is not None:
74             set_user_settings('skip_tutorial', request.json['skipTutorial'])
75         return {'success': True}, 200
76 
77 
78 @users_ns.route('/<int:user_id>')
79 class SetUserInfo(Resource):
80     """Set user's information (first name and last name)."""
81 
82     @staticmethod
83     @login_required
84     @users_ns.doc(security='token')
85     def put(user_id: int) -> Any:
86         """Set user info."""
87         if get_current_user().id != user_id:
88             raise AccessForbiddenException("Cannot update user's information for someone else.")
89         set_user_info(user_id, request.json['firstName'], request.json['lastName'])
90         return {'success': True}, 200
91
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/backend/medtagger/api/scans/service_rest.py b/backend/medtagger/api/scans/service_rest.py
--- a/backend/medtagger/api/scans/service_rest.py
+++ b/backend/medtagger/api/scans/service_rest.py
@@ -17,7 +17,7 @@
 scans_ns = api.namespace('scans', 'Methods related with scans')
 
 
-@scans_ns.route('/')
+@scans_ns.route('')
 class Scans(Resource):
     """Endpoint that can create new scan."""
 
diff --git a/backend/medtagger/api/users/service.py b/backend/medtagger/api/users/service.py
--- a/backend/medtagger/api/users/service.py
+++ b/backend/medtagger/api/users/service.py
@@ -14,7 +14,7 @@
 users_ns = api.namespace('users', 'Users management')
 
 
-@users_ns.route('/')
+@users_ns.route('')
 class GetUsers(Resource):
     """Get all users endpoint."""

{"golden_diff": "diff --git a/backend/medtagger/api/scans/service_rest.py b/backend/medtagger/api/scans/service_rest.py\n--- a/backend/medtagger/api/scans/service_rest.py\n+++ b/backend/medtagger/api/scans/service_rest.py\n@@ -17,7 +17,7 @@\n scans_ns = api.namespace('scans', 'Methods related with scans')\n \n \n-@scans_ns.route('/')\n+@scans_ns.route('')\n class Scans(Resource):\n     \"\"\"Endpoint that can create new scan.\"\"\"\n \ndiff --git a/backend/medtagger/api/users/service.py b/backend/medtagger/api/users/service.py\n--- a/backend/medtagger/api/users/service.py\n+++ b/backend/medtagger/api/users/service.py\n@@ -14,7 +14,7 @@\n users_ns = api.namespace('users', 'Users management')\n \n \n-@users_ns.route('/')\n+@users_ns.route('')\n class GetUsers(Resource):\n     \"\"\"Get all users endpoint.\"\"\"\n", "issue": "Incorrect usage of slashes\n## Current Behavior\r\n\r\nMedTagger services incorrectly use slashes at the end of namespaces making it incorrect according to REST practises. E.g endpoint for returning all scans looks like this:\r\n\r\n`GET /api/v1/scans/`\r\n\r\n## Expected Behavior\r\n\r\nMedTagger services should not use slashes at the end of namespaces. E.g endpoint for returning all scans should look like this:\r\n\r\n`GET /api/v1/scans`\n", "before_files": [{"content": "\"\"\"Module responsible for definition of Scans service available via HTTP REST API.\"\"\"\nimport json\nfrom typing import Any\n\nfrom flask import request\nfrom flask_restplus import Resource\nfrom jsonschema import validate, ValidationError, Draft4Validator\nfrom jsonschema.exceptions import best_match\n\nfrom medtagger.types import ScanID\nfrom medtagger.api import api\nfrom medtagger.api.exceptions import InvalidArgumentsException\nfrom medtagger.api.scans import business, serializers\nfrom medtagger.api.security import login_required, role_required, require_one_of_roles\nfrom medtagger.api.scans.serializers import elements_schema\n\nscans_ns = api.namespace('scans', 'Methods related with scans')\n\n\n@scans_ns.route('/')\nclass Scans(Resource):\n    \"\"\"Endpoint that can create new scan.\"\"\"\n\n    @staticmethod\n    @login_required\n    @role_required('doctor', 'admin')\n    @scans_ns.expect(serializers.in__new_scan)\n    @scans_ns.marshal_with(serializers.out__new_scan)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Creates empty scan.')\n    @scans_ns.doc(responses={201: 'Success'})\n    def post() -> Any:\n        \"\"\"Create empty scan.\"\"\"\n        payload = request.json\n        dataset_key = payload['dataset']\n        number_of_slices = payload['number_of_slices']\n        if not business.dataset_is_valid(dataset_key):\n            raise InvalidArgumentsException('Dataset \"{}\" is not available.'.format(dataset_key))\n\n        scan = business.create_empty_scan(dataset_key, number_of_slices)\n        return scan, 201\n\n\n@scans_ns.route('/random')\nclass Random(Resource):\n    \"\"\"Endpoint that returns random scan for labeling from specified task.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.expect(serializers.args__random_scan)\n    @scans_ns.marshal_with(serializers.out__random_scan)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Returns random scan from task.')\n    @scans_ns.doc(responses={200: 'Success', 400: 'Invalid arguments', 404: 'No Scans available'})\n    def get() -> Any:\n        \"\"\"Return random Scan.\"\"\"\n        args = serializers.args__random_scan.parse_args(request)\n        task_key = args.task\n        return business.get_random_scan(task_key)\n\n\n@scans_ns.route('/<string:scan_id>/<string:task_key>/label')\n@scans_ns.param('scan_id', 'Scan identifier')\n@scans_ns.param('task_key', 'Key of Task')\nclass Label(Resource):\n    \"\"\"Endpoint that stores label for given scan.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.expect(serializers.in__label)\n    @scans_ns.marshal_with(serializers.out__label)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Stores label and assigns it to given scan.')\n    @scans_ns.doc(responses={201: 'Successfully saved', 400: 'Invalid arguments', 404: 'Could not find scan or tag'})\n    def post(scan_id: ScanID, task_key: str) -> Any:\n        \"\"\"Add new Label for given scan.\n\n        This endpoint needs a multipart/form-data content where there is one mandatory section called \"label\".\n        Such section will contain a JSON payload with representation of a Label. If such Label needs additional\n        information like images (binary mask), please attach them as a separate part.\n\n        Here is an example CURL command that sends Label with Brush Element:\n\n            $> curl -v\n                    -H \"Content-Type:multipart/form-data\"\n                    -H \"Authorization: Bearer MEDTAGGER_API_TOKEN\"\n                    -F \"SLICE_1=@\"/Users/jakubpowierza/Desktop/test.png\"\"\n                    -F \"label={\"elements\": [{\"width\": 1, \"height\": 1, \"image_key\": \"SLICE_1\",\n                               \"slice_index\": 1, \"tag\": \"LEFT_KIDNEY\", \"tool\": \"BRUSH\"}],\n                               \"labeling_time\": 0.1};type=application/json\"\n                     http://localhost:51000/api/v1/scans/c5102707-cb36-4869-8041-f00421c03fa1/MARK_KIDNEYS/label\n        \"\"\"\n        is_predefined = (request.args.get('is_predefined', 'false') == 'true')\n        if is_predefined:\n            require_one_of_roles({'doctor', 'admin'})\n\n        files = {name: file_data.read() for name, file_data in request.files.items()}\n        label = json.loads(request.form['label'])\n        elements = label['elements']\n        try:\n            validate(elements, elements_schema)\n        except ValidationError:\n            validator = Draft4Validator(elements_schema)\n            errors = validator.iter_errors(elements)\n            best_error = best_match(errors)\n            raise InvalidArgumentsException(best_error.message)\n\n        business.validate_label_payload(label, task_key, files)\n\n        labeling_time = label['labeling_time']\n        comment = label.get('comment')\n        label = business.add_label(scan_id, task_key, elements, files, labeling_time, comment, is_predefined)\n        return label, 201\n\n\n@scans_ns.route('/<string:scan_id>')\n@scans_ns.param('scan_id', 'Scan identifier')\nclass Scan(Resource):\n    \"\"\"Endpoint that returns scan for the given scan id.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.marshal_with(serializers.out__scan)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Returns scan with given scan_id.')\n    @scans_ns.doc(responses={200: 'Success', 404: 'Could not find scan'})\n    def get(scan_id: ScanID) -> Any:\n        \"\"\"Return scan for the given scan_id.\"\"\"\n        return business.get_scan(scan_id)\n\n\n@scans_ns.route('/<string:scan_id>/skip')\n@scans_ns.param('scan_id', 'Scan identifier')\nclass SkipScan(Resource):\n    \"\"\"Endpoint that allows for skipping given Scan.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Increases skip count of a scan with given scan_id.')\n    @scans_ns.doc(responses={200: 'Success', 404: 'Could not find scan'})\n    def post(scan_id: ScanID) -> Any:\n        \"\"\"Increases skip count of a scan with given scan_id.\"\"\"\n        if not business.skip_scan(scan_id):\n            return '', 404\n        return '', 200\n\n\n@scans_ns.route('/<string:scan_id>/slices')\n@scans_ns.param('scan_id', 'Scan identifier')\nclass ScanSlices(Resource):\n    \"\"\"Endpoint that allows for uploading Slices to given Scan.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.marshal_with(serializers.out__new_slice)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Returns newly created Slice.')\n    @scans_ns.doc(responses={201: 'Success', 400: 'Invalid arguments'})\n    def post(scan_id: ScanID) -> Any:\n        \"\"\"Upload Slice for given Scan.\"\"\"\n        image = request.files['image']\n        image_data = image.read()\n        new_slice = business.add_new_slice(scan_id, image_data)\n        return new_slice, 201\n", "path": "backend/medtagger/api/scans/service_rest.py"}, {"content": "\"\"\"Module responsible for defining endpoints for users administration.\"\"\"\nfrom typing import Any\n\nfrom flask import request\nfrom flask_restplus import Resource\n\nfrom medtagger.api import api\nfrom medtagger.api.exceptions import AccessForbiddenException\nfrom medtagger.api.users import serializers\nfrom medtagger.api.users.business import get_all_users, set_user_role, set_user_info, set_user_settings\nfrom medtagger.api.utils import get_current_user\nfrom medtagger.api.security import login_required, role_required\n\nusers_ns = api.namespace('users', 'Users management')\n\n\n@users_ns.route('/')\nclass GetUsers(Resource):\n    \"\"\"Get all users endpoint.\"\"\"\n\n    @staticmethod\n    @login_required\n    @role_required('admin')\n    @users_ns.marshal_with(serializers.users_list)\n    @users_ns.doc(security='token')\n    def get() -> Any:\n        \"\"\"Get all users endpoint.\"\"\"\n        users = get_all_users()\n        return {'users': users}, 200\n\n\n@users_ns.route('/<int:user_id>/role')\nclass SetRole(Resource):\n    \"\"\"Set user's role.\"\"\"\n\n    @staticmethod\n    @login_required\n    @role_required('admin')\n    @users_ns.doc(security='token')\n    def put(user_id: int) -> Any:\n        \"\"\"Set user's role.\"\"\"\n        set_user_role(user_id, request.json['role'])\n        return {'success': True}, 200\n\n\n@users_ns.route('/info')\nclass GetUserInfo(Resource):\n    \"\"\"Get current user information.\"\"\"\n\n    @staticmethod\n    @login_required\n    @users_ns.marshal_with(serializers.user)\n    @users_ns.doc(security='token')\n    @users_ns.doc(responses={200: 'Successfully retrieved data.'})\n    def get() -> Any:\n        \"\"\"Get user info.\"\"\"\n        user = get_current_user()\n        return user, 200\n\n\n@users_ns.route('/<int:user_id>/settings')\nclass SetUserSettings(Resource):\n    \"\"\"Set user's settings.\"\"\"\n\n    @staticmethod\n    @login_required\n    @users_ns.doc(security='token')\n    def post(user_id: int) -> Any:\n        \"\"\"Set current user's settings. If settings' param is not specified in request, it is not updated.\"\"\"\n        user = get_current_user()\n        if user.id != user_id:\n            raise AccessForbiddenException(\"Cannot update settings for someone else.\")\n        if request.json.get('skipTutorial', None) is not None:\n            set_user_settings('skip_tutorial', request.json['skipTutorial'])\n        return {'success': True}, 200\n\n\n@users_ns.route('/<int:user_id>')\nclass SetUserInfo(Resource):\n    \"\"\"Set user's information (first name and last name).\"\"\"\n\n    @staticmethod\n    @login_required\n    @users_ns.doc(security='token')\n    def put(user_id: int) -> Any:\n        \"\"\"Set user info.\"\"\"\n        if get_current_user().id != user_id:\n            raise AccessForbiddenException(\"Cannot update user's information for someone else.\")\n        set_user_info(user_id, request.json['firstName'], request.json['lastName'])\n        return {'success': True}, 200\n", "path": "backend/medtagger/api/users/service.py"}], "after_files": [{"content": "\"\"\"Module responsible for definition of Scans service available via HTTP REST API.\"\"\"\nimport json\nfrom typing import Any\n\nfrom flask import request\nfrom flask_restplus import Resource\nfrom jsonschema import validate, ValidationError, Draft4Validator\nfrom jsonschema.exceptions import best_match\n\nfrom medtagger.types import ScanID\nfrom medtagger.api import api\nfrom medtagger.api.exceptions import InvalidArgumentsException\nfrom medtagger.api.scans import business, serializers\nfrom medtagger.api.security import login_required, role_required, require_one_of_roles\nfrom medtagger.api.scans.serializers import elements_schema\n\nscans_ns = api.namespace('scans', 'Methods related with scans')\n\n\n@scans_ns.route('')\nclass Scans(Resource):\n    \"\"\"Endpoint that can create new scan.\"\"\"\n\n    @staticmethod\n    @login_required\n    @role_required('doctor', 'admin')\n    @scans_ns.expect(serializers.in__new_scan)\n    @scans_ns.marshal_with(serializers.out__new_scan)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Creates empty scan.')\n    @scans_ns.doc(responses={201: 'Success'})\n    def post() -> Any:\n        \"\"\"Create empty scan.\"\"\"\n        payload = request.json\n        dataset_key = payload['dataset']\n        number_of_slices = payload['number_of_slices']\n        if not business.dataset_is_valid(dataset_key):\n            raise InvalidArgumentsException('Dataset \"{}\" is not available.'.format(dataset_key))\n\n        scan = business.create_empty_scan(dataset_key, number_of_slices)\n        return scan, 201\n\n\n@scans_ns.route('/random')\nclass Random(Resource):\n    \"\"\"Endpoint that returns random scan for labeling from specified task.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.expect(serializers.args__random_scan)\n    @scans_ns.marshal_with(serializers.out__random_scan)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Returns random scan from task.')\n    @scans_ns.doc(responses={200: 'Success', 400: 'Invalid arguments', 404: 'No Scans available'})\n    def get() -> Any:\n        \"\"\"Return random Scan.\"\"\"\n        args = serializers.args__random_scan.parse_args(request)\n        task_key = args.task\n        return business.get_random_scan(task_key)\n\n\n@scans_ns.route('/<string:scan_id>/<string:task_key>/label')\n@scans_ns.param('scan_id', 'Scan identifier')\n@scans_ns.param('task_key', 'Key of Task')\nclass Label(Resource):\n    \"\"\"Endpoint that stores label for given scan.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.expect(serializers.in__label)\n    @scans_ns.marshal_with(serializers.out__label)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Stores label and assigns it to given scan.')\n    @scans_ns.doc(responses={201: 'Successfully saved', 400: 'Invalid arguments', 404: 'Could not find scan or tag'})\n    def post(scan_id: ScanID, task_key: str) -> Any:\n        \"\"\"Add new Label for given scan.\n\n        This endpoint needs a multipart/form-data content where there is one mandatory section called \"label\".\n        Such section will contain a JSON payload with representation of a Label. If such Label needs additional\n        information like images (binary mask), please attach them as a separate part.\n\n        Here is an example CURL command that sends Label with Brush Element:\n\n            $> curl -v\n                    -H \"Content-Type:multipart/form-data\"\n                    -H \"Authorization: Bearer MEDTAGGER_API_TOKEN\"\n                    -F \"SLICE_1=@\"/Users/jakubpowierza/Desktop/test.png\"\"\n                    -F \"label={\"elements\": [{\"width\": 1, \"height\": 1, \"image_key\": \"SLICE_1\",\n                               \"slice_index\": 1, \"tag\": \"LEFT_KIDNEY\", \"tool\": \"BRUSH\"}],\n                               \"labeling_time\": 0.1};type=application/json\"\n                     http://localhost:51000/api/v1/scans/c5102707-cb36-4869-8041-f00421c03fa1/MARK_KIDNEYS/label\n        \"\"\"\n        is_predefined = (request.args.get('is_predefined', 'false') == 'true')\n        if is_predefined:\n            require_one_of_roles({'doctor', 'admin'})\n\n        files = {name: file_data.read() for name, file_data in request.files.items()}\n        label = json.loads(request.form['label'])\n        elements = label['elements']\n        try:\n            validate(elements, elements_schema)\n        except ValidationError:\n            validator = Draft4Validator(elements_schema)\n            errors = validator.iter_errors(elements)\n            best_error = best_match(errors)\n            raise InvalidArgumentsException(best_error.message)\n\n        business.validate_label_payload(label, task_key, files)\n\n        labeling_time = label['labeling_time']\n        comment = label.get('comment')\n        label = business.add_label(scan_id, task_key, elements, files, labeling_time, comment, is_predefined)\n        return label, 201\n\n\n@scans_ns.route('/<string:scan_id>')\n@scans_ns.param('scan_id', 'Scan identifier')\nclass Scan(Resource):\n    \"\"\"Endpoint that returns scan for the given scan id.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.marshal_with(serializers.out__scan)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Returns scan with given scan_id.')\n    @scans_ns.doc(responses={200: 'Success', 404: 'Could not find scan'})\n    def get(scan_id: ScanID) -> Any:\n        \"\"\"Return scan for the given scan_id.\"\"\"\n        return business.get_scan(scan_id)\n\n\n@scans_ns.route('/<string:scan_id>/skip')\n@scans_ns.param('scan_id', 'Scan identifier')\nclass SkipScan(Resource):\n    \"\"\"Endpoint that allows for skipping given Scan.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Increases skip count of a scan with given scan_id.')\n    @scans_ns.doc(responses={200: 'Success', 404: 'Could not find scan'})\n    def post(scan_id: ScanID) -> Any:\n        \"\"\"Increases skip count of a scan with given scan_id.\"\"\"\n        if not business.skip_scan(scan_id):\n            return '', 404\n        return '', 200\n\n\n@scans_ns.route('/<string:scan_id>/slices')\n@scans_ns.param('scan_id', 'Scan identifier')\nclass ScanSlices(Resource):\n    \"\"\"Endpoint that allows for uploading Slices to given Scan.\"\"\"\n\n    @staticmethod\n    @login_required\n    @scans_ns.marshal_with(serializers.out__new_slice)\n    @scans_ns.doc(security='token')\n    @scans_ns.doc(description='Returns newly created Slice.')\n    @scans_ns.doc(responses={201: 'Success', 400: 'Invalid arguments'})\n    def post(scan_id: ScanID) -> Any:\n        \"\"\"Upload Slice for given Scan.\"\"\"\n        image = request.files['image']\n        image_data = image.read()\n        new_slice = business.add_new_slice(scan_id, image_data)\n        return new_slice, 201\n", "path": "backend/medtagger/api/scans/service_rest.py"}, {"content": "\"\"\"Module responsible for defining endpoints for users administration.\"\"\"\nfrom typing import Any\n\nfrom flask import request\nfrom flask_restplus import Resource\n\nfrom medtagger.api import api\nfrom medtagger.api.exceptions import AccessForbiddenException\nfrom medtagger.api.users import serializers\nfrom medtagger.api.users.business import get_all_users, set_user_role, set_user_info, set_user_settings\nfrom medtagger.api.utils import get_current_user\nfrom medtagger.api.security import login_required, role_required\n\nusers_ns = api.namespace('users', 'Users management')\n\n\n@users_ns.route('')\nclass GetUsers(Resource):\n    \"\"\"Get all users endpoint.\"\"\"\n\n    @staticmethod\n    @login_required\n    @role_required('admin')\n    @users_ns.marshal_with(serializers.users_list)\n    @users_ns.doc(security='token')\n    def get() -> Any:\n        \"\"\"Get all users endpoint.\"\"\"\n        users = get_all_users()\n        return {'users': users}, 200\n\n\n@users_ns.route('/<int:user_id>/role')\nclass SetRole(Resource):\n    \"\"\"Set user's role.\"\"\"\n\n    @staticmethod\n    @login_required\n    @role_required('admin')\n    @users_ns.doc(security='token')\n    def put(user_id: int) -> Any:\n        \"\"\"Set user's role.\"\"\"\n        set_user_role(user_id, request.json['role'])\n        return {'success': True}, 200\n\n\n@users_ns.route('/info')\nclass GetUserInfo(Resource):\n    \"\"\"Get current user information.\"\"\"\n\n    @staticmethod\n    @login_required\n    @users_ns.marshal_with(serializers.user)\n    @users_ns.doc(security='token')\n    @users_ns.doc(responses={200: 'Successfully retrieved data.'})\n    def get() -> Any:\n        \"\"\"Get user info.\"\"\"\n        user = get_current_user()\n        return user, 200\n\n\n@users_ns.route('/<int:user_id>/settings')\nclass SetUserSettings(Resource):\n    \"\"\"Set user's settings.\"\"\"\n\n    @staticmethod\n    @login_required\n    @users_ns.doc(security='token')\n    def post(user_id: int) -> Any:\n        \"\"\"Set current user's settings. If settings' param is not specified in request, it is not updated.\"\"\"\n        user = get_current_user()\n        if user.id != user_id:\n            raise AccessForbiddenException(\"Cannot update settings for someone else.\")\n        if request.json.get('skipTutorial', None) is not None:\n            set_user_settings('skip_tutorial', request.json['skipTutorial'])\n        return {'success': True}, 200\n\n\n@users_ns.route('/<int:user_id>')\nclass SetUserInfo(Resource):\n    \"\"\"Set user's information (first name and last name).\"\"\"\n\n    @staticmethod\n    @login_required\n    @users_ns.doc(security='token')\n    def put(user_id: int) -> Any:\n        \"\"\"Set user info.\"\"\"\n        if get_current_user().id != user_id:\n            raise AccessForbiddenException(\"Cannot update user's information for someone else.\")\n        set_user_info(user_id, request.json['firstName'], request.json['lastName'])\n        return {'success': True}, 200\n", "path": "backend/medtagger/api/users/service.py"}]}