class Employee(OptionsResource): @api.doc('get_employee', security='apikey', params=required_query_params({'id': 'employee ID'})) @api.marshal_with(full_employee, code=200) @api.response(404, description="Employee not found") @jwt_required def get(self): """Get employee`s account info""" return employee_service.get_employee(get_uuid(request)), 200 @api.doc('edit_employee', security='apikey', params=required_query_params({'id': 'employee ID'})) @api.marshal_with(full_employee, code=201) @api.response(404, description="Employee or subunit not found") @api.response(403, description="Not allowed to edit this employee's info") @api.response(409, description="Employee with given email already exists") @api.response(422, description="All fields are null") @api.expect(employee_edit, validate=True) @jwt_required def put(self): """Edit employee`s account info (only for admins)""" return employee_service.edit_employee(get_jwt_identity(), get_uuid(request), **api.payload), 201 @api.doc('employee_register', security='apikey') @api.expect(employee_registration, validate=True) @api.marshal_with(full_employee, code=201) @api.response(403, description="Non-admins can not register new employees") @api.response(404, description="SubUnit not found") @api.response(409, description="Employee with given email already exists") @api.response(422, description="Incorrect password given") @jwt_required def post(self): """Register a new employee (only for admins)""" return employee_service.register_employee(get_jwt_identity(), **api.payload), 201
class ApprovePost(OptionsResource): @api.doc("approve_post", security='apikey', params=required_query_params({"id": "Post ID"})) @api.marshal_with(full_post, code=201) @api.response(404, description="Post not found") @api.response(403, description="Have no privileges to approve this post") @jwt_required def post(self): """Approve a post (only for moderators and admins)""" return post_service.set_post_status(get_jwt_identity(), get_uuid(request), PostStatus.posted), 201 @api.doc("disapprove_post", security='apikey', params=required_query_params({"id": "Post ID"})) @api.marshal_with(full_post, code=201) @api.response(404, description="Post not found") @api.response(403, description="Have no privileges to disapprove this post") @jwt_required def delete(self): """Disapprove a post (only for moderators and admins)""" return post_service.set_post_status( get_jwt_identity(), get_uuid(request), PostStatus.under_consideration), 201
class Attachment(OptionsResource): @api.doc("attachment_upload", security='apikey') @api.marshal_with(attachment, code=201) @api.response(400, description="Cannot get file from request") @api.response(413, description="Attachment size is too large") @api.expect(parser, validate=True) @jwt_required def post(self): """Upload an attachment to the server""" return attachment_service.save_attachment( get_jwt_identity(), request.files.get('file')), 201 @api.doc("attachment_download", params=required_query_params({"id": "Attachment ID"}), security='apikey') @api.response(200, description="Success (response contains a requested file)") @api.response(404, description="Attachment not found") @jwt_required def get(self): """Download an attachment from server""" return attachment_service.get_attachment(get_uuid(request)) @api.doc("attachment_remove", params=required_query_params({"id": "Attachment ID"}), security='apikey') @api.response(201, description="Success") @api.response(403, description="Can not delete attachments of other users") @api.response(404, description="Attachment not found") @jwt_required def delete(self): """Delete an attachment from server""" return attachment_service.delete_attachment(get_jwt_identity(), get_uuid(request)), 201
class Post(OptionsResource): @api.doc("create_post", security='apikey') @api.marshal_with(full_post, code=201) @api.response(404, description="Attachment not found") @api.expect(post_create, validate=True) @jwt_required def post(self): """Create a post""" return post_service.create_post(get_jwt_identity(), **api.payload), 201 @api.doc("edit_post", security='apikey', params=required_query_params({"id": "Post ID"})) @api.marshal_with(full_post, code=201) @api.response(404, description="Post or attachment not found") @api.response(403, description="Have no privileges to edit this post") @api.response(422, description="All fields are null") @api.expect(post_edit, validate=True) @jwt_required def put(self): """Edit a post""" return post_service.edit_post(get_jwt_identity(), get_uuid(request), **api.payload), 201 @api.doc("get_post", security='apikey', params=required_query_params({"id": "Post ID"})) @api.marshal_with(full_post, code=200) @api.response(404, description="Post not found") @jwt_required def get(self): """Get a post by ID""" return post_service.get_post(get_uuid(request)), 200 @api.doc("delete_post", security='apikey', params=required_query_params({ "id": "Post ID", "with_attachments": "Delete also every attachment of the post" })) @api.response(201, description="Success") @api.response( 403, description="Can not remove other users` posts or attachments") @api.response(404, description="Post not found") @jwt_required def delete(self): """Remove a post""" return post_service.delete_post(get_jwt_identity(), get_uuid(request)), 201
class ArchivePost(OptionsResource): @api.doc("archive_post", security='apikey', params=required_query_params({"id": "Post ID"})) @api.marshal_with(full_post, code=201) @api.response(404, description="Post not found") @api.response(403, description="Have no privileges to archive this post") @jwt_required def post(self): """Archive a post (only for moderators and admins)""" return post_service.set_post_status(get_jwt_identity(), get_uuid(request), PostStatus.archived), 201 @api.doc("get_archived_posts", security='apikey', params=required_query_params({'page': 'page number'})) @api.marshal_with(counted_posts_list, code=200) @jwt_required def get(self): """Get archived posts""" return post_service.get_archived_posts(get_page(request)), 200 @api.doc("unarchive_post", security='apikey', params=required_query_params({ "id": "Post ID", "status": { 'description': "Status to give after unarchiving", "enum": [i.name for i in PostStatus if i != PostStatus.archived] } })) @api.marshal_with(full_post, code=201) @api.response(404, description="Post not found") @api.response(403, description="Have no privileges to unarchive this post") @api.response(400, description="Incorrect status value") @jwt_required def delete(self): """Unarchive a post (only for moderators and admins)""" try: new_status = PostStatus[request.args.get('status', '')] if new_status == PostStatus.archived: raise KeyError except KeyError: return abort(400, "Incorrect status value") return post_service.set_post_status(get_jwt_identity(), get_uuid(request), new_status), 201
class PostStat(OptionsResource): @api.doc("get_posts_statistics", security='apikey', params=update_dict( required_query_params({ "start_year": "Year to start from", "start_month": "Month to start from", "end_year": "Year to finish with", "end_month": "Month to finish with" }), {"ids": "SubUnit IDs, separated by commas"})) @api.response(code=200, description="Success", model=posts_statistics) @api.response(code=400, description="Incorrect (non-integer) date parameters") @api.response(code=422, description="Invalid date given") @jwt_required def get(self): """Get statistics of posts of the each subunit""" start_year = request.args.get("start_year", '') start_month = request.args.get("start_month", '') end_year = request.args.get("end_year", '') end_month = request.args.get("end_month", '') ids_raw = query_param_to_set("ids") if not all( param.isdigit() for param in (start_year, start_month, end_year, end_month)): abort(400, "Date values must be integers") return post_service.get_statistics( *(int(param) for param in ( start_year, start_month, end_year, end_month, )), subunit_ids=[get_uuid(e_id) for e_id in ids_raw] if ids_raw and all(ids_raw) else None), 200
class BiggestPost(OptionsResource): @api.doc("get_biggest_post", security='apikey', params=required_query_params({ "day": f"Date in '{DATETIME_FORMAT}' format (example: '2020-12-31')", "include_archived": { 'description': "Search in archived posts or not", "enum": ['true', 'false'] } })) @api.marshal_with(full_post, code=200) @api.response(404, description="Post not found") @api.response(422, description="Can not parse parameters") @jwt_required def get(self): """Get biggest post by date""" try: day = date.fromisoformat(request.args.get("day", '')) except ValueError: return abort(422, "Incorrect date format") if request.args.get("include_archived", '').lower() == 'true': include_archived = True elif request.args.get("include_archived", '').lower() == 'false': include_archived = False else: return abort(422, "Incorrect 'include_archived' parameter") return post_service.get_biggest_post(day, include_archived), 200
class Post(OptionsResource): @api.doc("get_employee_posts", security='apikey', params=required_query_params({"id": "Employee ID"})) @api.marshal_with(full_post, code=200, as_list=True) @api.response(404, description="Employee not found") @jwt_required def get(self): """Get all employee's posts""" return post_service.get_all_employee_posts(get_uuid(request)), 200
class OrgAnnouncements(OptionsResource): @api.doc("get_org_announcements", security='apikey', params=required_query_params({'page': 'page number'})) @api.marshal_with(counted_posts_list, code=200) @jwt_required def get(self): """Get announcements feed of all organization""" return post_service.get_feed(PostType.organization_announcement, get_page(request)), 200
class AuthRefresh(OptionsResource): @api.doc('get_multiple_employees', security='apikey', params=required_query_params( {'ids': 'Employee IDs, separated by commas'} )) @api.marshal_with(full_employee, code=200, as_list=True) @jwt_required def get(self): """Get multiple employees at a time""" ids = query_param_to_set("ids") for employee_id in ids: get_uuid(employee_id) return employee_service.get_multiple_employees(ids), 200
class Subunit(OptionsResource): @api.doc('get_subunit', security='apikey', params=required_query_params({'id': 'SubUnit ID'})) @api.marshal_with(full_subunit, code=200) @api.response(404, description="SubUnit not found") @jwt_required def get(self): """Get info about subunit""" return subunit_service.get_subunit(get_uuid(request)), 200 @api.doc('edit_subunit', security='apikey', params=required_query_params({'id': 'SubUnit ID'})) @api.marshal_with(full_subunit, code=201) @api.response(404, description="SubUnit or leader not found") @api.response(403, description="Non-admin tried to change a subunit") @api.response(409, description="SubUnit with this name or email already exists") @api.response(422, description="All fields are null") @api.expect(subunit_edit, validate=True) @jwt_required def put(self): """Change info about subunit (only for admins)""" return subunit_service.edit_subunit(get_jwt_identity(), get_uuid(request), **api.payload), 201 @api.doc('add_subunit', security='apikey') @api.marshal_with(full_subunit, code=201) @api.response(403, description="Non-admin tried to create a subunit") @api.response(404, description="Leader not found") @api.response(409, description="SubUnit with this name or email already exists") @api.expect(subunit_create, validate=True) @jwt_required def post(self): """Create a new subunit (only for admins)""" return subunit_service.create_subunit(get_jwt_identity(), **api.payload), 201
class ApprovePost(OptionsResource): @api.doc("return_post", security='apikey', params=required_query_params({"id": "Post ID"})) @api.marshal_with(full_post, code=201) @api.response(404, description="Post not found") @api.response(403, description="Have no privileges to return this post") @jwt_required def post(self): """Return a post for further improvements (only for moderators and admins)""" return post_service.set_post_status( get_jwt_identity(), get_uuid(request), PostStatus.returned_for_improvement), 201
class SubunitAnnouncements(OptionsResource): @api.doc("get_subunit_announcements", security='apikey', params=required_query_params({ 'page': 'page number', "id": "ID of the subunit" })) @api.marshal_with(counted_posts_list, code=200) @jwt_required def get(self): """Get announcements feed of the subunit""" return post_service.get_feed(PostType.subunit_announcement, get_page(request), get_uuid(request)), 200
class UserAttachments(OptionsResource): @api.doc("get_employee_attachments", params=required_query_params({ "page": "page number", "id": "Employee`s ID" }), security='apikey') @api.marshal_with(counted_attachments_list, code=200) @api.response(404, description="Employee not found") @jwt_required def get(self): """Get list of employee`s attachments""" return attachment_service.get_all_attachments(get_uuid(request), get_page(request)), 200
class AuthRefresh(OptionsResource): @api.doc('fired_employees_of_subunit', security='apikey', params=required_query_params( {'id': 'SubUnit ID', "types": "Types of employees, separated by commas"} )) @api.marshal_with(full_employee, code=200, as_list=True) @api.response(404, description="SubUnit not found") @jwt_required def get(self): """Get fired users of the subunit""" types_raw = query_param_to_set("types") types = set() for employee_type in types_raw: try: types.add(EmployeeType(employee_type)) except ValueError: abort(400, f"Incorrect employee type '{employee_type}'") return employee_service.get_fired_moderators(get_uuid(request), types), 200