From cae1eeaedebbb93265a73860673b99b46d4d64d6 Mon Sep 17 00:00:00 2001 From: Sam Peters Date: Fri, 12 Mar 2021 15:44:12 -0800 Subject: [PATCH 1/9] Finished docs for Me resource --- server/resources/me.py | 81 ++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/server/resources/me.py b/server/resources/me.py index dc0c8713..691ebb9c 100644 --- a/server/resources/me.py +++ b/server/resources/me.py @@ -16,10 +16,14 @@ def get(self): User: type: object properties: - sub: + _id: type: string description: Unique user identifier example: abcde12345 + anonymousId: + type: string + description: Secondary unique user identifier + example: d1e2f3g4h5 email: type: string description: Email address @@ -32,45 +36,78 @@ def get(self): type: string description: Last name example: Figgis - instructor: - type: boolean - default: false - description: Boolean representing if the user is an instructor on the platform - example: cyrilfiggis@gmail.com - permissions: + picture: + type: string + description: URL of the user's avatar picture + example: https://avatars.githubusercontent.com/u/111111111?v=4 + courses: type: array items: - $ref: '#/definitions/CoursePermissions' + $ref: '#/definitions/UserCourse' - CoursePermissions: + UserCourse: type: object properties: course_id: type: string - description: ID of the course these permissions are for + description: ID of the course the user joined example: vytxeTZskVKR7C7WgdSP3d - post_question: + course_name: + type: string + description: Name associated with the course + example: "CIS499 Advanced Debugging" + nickname: + type: string + description: Course nickname + example: "CIS499" + color: + type: string + description: Accent color used in course specific ui + example: "#ee55ee" + canPost: type: boolean - description: If the user is allowed to post a question + description: If the user can post in the course default: true example: true - create_announcement: + seePrivate: type: boolean - description: If the user is allowed to post an announcement + description: If the user can see private posts in the course default: false example: false - post_response: + canPin: type: boolean - description: If the user is allowed to post a response to another post - default: true + description: If the user user can pin posts + default: false + example: false + canRemove: + type: boolean + description: If the user can remove posts from the course + default: false + example: false + canEndorse: + type: boolean + description: If the user can endorse posts in the course + default: false + example: true + viewAnonymous: + type: boolean + description: If the user can view the identity of anonymous posters + default: false example: true - 403Message: + admin: + type: boolean + description: If the user is an administrator of the course + default: false + example: false + + 403 Response: type: object + description: Response to authorized requests properties: - msg: - type: string - description: Reason the request did not succeed or was rejected - example: "Resource access restricted" + errors: + type: array + description: List of authorization errors + example: ["Resource access restricted: missing course permission(s) admin, seePrivate"] responses: 200: From c500fc72e8af107b08d531412c3bbb2ffddb278c Mon Sep 17 00:00:00 2001 From: Alec Springel Date: Fri, 12 Mar 2021 15:49:03 -0800 Subject: [PATCH 2/9] merged doc changes --- server/flasgger/courses.yml | 51 +++++++++++++++++++++++++++++++++++ server/flasgger/responses.yml | 14 ++++++++++ server/flasgger/user.yml | 28 +++++++++++++++++++ server/resources/courses.py | 23 ++++++++++++++++ server/resources/me.py | 3 --- 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 server/flasgger/courses.yml create mode 100644 server/flasgger/responses.yml create mode 100644 server/flasgger/user.yml diff --git a/server/flasgger/courses.yml b/server/flasgger/courses.yml new file mode 100644 index 00000000..759825d8 --- /dev/null +++ b/server/flasgger/courses.yml @@ -0,0 +1,51 @@ +CoursePermissions: + type: object + properties: + courseid: + type: string + description: Unique course identifier, also used for joining courses + example: oFAeuzdT4VwKf3dHUFGhwu + course_name: + type: string + description: Name of course + example: CIS 422 + canPost: + type: boolean + default: true + description: Course permission - can create new posts + example: true + seePrivate: + type: boolean + default: false + description: Course permission - can see other users private posts + example: false + canPin: + type: boolean + default: false + description: Course permission - can pin posts for the course + example: false + canRemove: + type: boolean + default: false + description: Course permission - can remove posts from the course + example: false + canEndorse: + type: boolean + default: false + description: Course permission - can endorse comments as the 'best' answer + example: false + viewAnonymous: + type: boolean + default: false + description: Course permission - can create new posts + example: false + admin: + type: boolean + default: false + description: Course permission - has all course permissions granted + example: false + color: + type: string + default: #162B55 + description: Color for the user's course card + example: #162B55 diff --git a/server/flasgger/responses.yml b/server/flasgger/responses.yml new file mode 100644 index 00000000..94c1ef9e --- /dev/null +++ b/server/flasgger/responses.yml @@ -0,0 +1,14 @@ +400Message: + type: object + properties: + errors: + type: list + description: List of errors related to failed request + example: ["Invalid courseid"] +403Message: + type: object + properties: + msg: + type: string + description: Reason the request did not succeed or was rejected + example: "Resource access restricted" diff --git a/server/flasgger/user.yml b/server/flasgger/user.yml new file mode 100644 index 00000000..e004b06e --- /dev/null +++ b/server/flasgger/user.yml @@ -0,0 +1,28 @@ +User: + type: object + properties: + sub: + type: string + description: Unique user identifier + example: abcde12345 + email: + type: string + description: Email address + example: cyrilfiggis@gmail.com + first: + type: string + description: First name + example: Cyril + last: + type: string + description: Last name + example: Figgis + instructor: + type: boolean + default: false + description: Boolean representing if the user is an instructor on the platform + example: cyrilfiggis@gmail.com + permissions: + type: array + items: + $ref: "#/definitions/CoursePermissions" diff --git a/server/resources/courses.py b/server/resources/courses.py index 8c6fb7f2..8881deab 100644 --- a/server/resources/courses.py +++ b/server/resources/courses.py @@ -16,6 +16,29 @@ class Courses(Resource): @permission_layer([]) def post(self): + """ + Creates a new course and responds with the instructor's permissions for the course + --- + tags: + - Courses + definitions: + import: "./flasgger/courses.yml" + import: "./flasgger/responses.yml" + + responses: + 200: + description: Stored user data for the currently logged in user + schema: + $ref: '#/definitions/CoursePermissions' + 400: + description: Array of errors gathered from request + schema: + $ref: '#/definitions/400Message' + 403: + description: Unable to retrieve current user data + schema: + $ref: '#/definitions/403Message' + """ # Get json for POST requests request.get_json(force=True) # Parse arguments diff --git a/server/resources/me.py b/server/resources/me.py index 691ebb9c..8a435bae 100644 --- a/server/resources/me.py +++ b/server/resources/me.py @@ -118,8 +118,5 @@ def get(self): description: Unable to retrieve current user data schema: $ref: '#/definitions/403Message' - - - """ return current_user.to_son().to_dict() From c25d6047c60d8eb2548585322424c7844c589045 Mon Sep 17 00:00:00 2001 From: Alec Springel Date: Fri, 12 Mar 2021 15:58:39 -0800 Subject: [PATCH 3/9] added yml files and imports --- server/flasgger/courses.yml | 51 ----------------- server/flasgger/responses.yml | 16 ++++-- server/flasgger/user.yml | 73 ++++++++++++++++++++++--- server/resources/courses.py | 12 ++-- server/resources/me.py | 100 ++-------------------------------- 5 files changed, 83 insertions(+), 169 deletions(-) diff --git a/server/flasgger/courses.yml b/server/flasgger/courses.yml index 759825d8..e69de29b 100644 --- a/server/flasgger/courses.yml +++ b/server/flasgger/courses.yml @@ -1,51 +0,0 @@ -CoursePermissions: - type: object - properties: - courseid: - type: string - description: Unique course identifier, also used for joining courses - example: oFAeuzdT4VwKf3dHUFGhwu - course_name: - type: string - description: Name of course - example: CIS 422 - canPost: - type: boolean - default: true - description: Course permission - can create new posts - example: true - seePrivate: - type: boolean - default: false - description: Course permission - can see other users private posts - example: false - canPin: - type: boolean - default: false - description: Course permission - can pin posts for the course - example: false - canRemove: - type: boolean - default: false - description: Course permission - can remove posts from the course - example: false - canEndorse: - type: boolean - default: false - description: Course permission - can endorse comments as the 'best' answer - example: false - viewAnonymous: - type: boolean - default: false - description: Course permission - can create new posts - example: false - admin: - type: boolean - default: false - description: Course permission - has all course permissions granted - example: false - color: - type: string - default: #162B55 - description: Color for the user's course card - example: #162B55 diff --git a/server/flasgger/responses.yml b/server/flasgger/responses.yml index 94c1ef9e..2a9ded2e 100644 --- a/server/flasgger/responses.yml +++ b/server/flasgger/responses.yml @@ -1,14 +1,18 @@ -400Message: +400Response: type: object properties: errors: type: list description: List of errors related to failed request example: ["Invalid courseid"] -403Message: +403Response: type: object + description: Response to authorized requests properties: - msg: - type: string - description: Reason the request did not succeed or was rejected - example: "Resource access restricted" + errors: + type: array + description: List of authorization errors + example: + [ + "Resource access restricted: missing course permission(s) admin, seePrivate", + ] diff --git a/server/flasgger/user.yml b/server/flasgger/user.yml index e004b06e..5b38505a 100644 --- a/server/flasgger/user.yml +++ b/server/flasgger/user.yml @@ -1,10 +1,14 @@ User: type: object properties: - sub: + _id: type: string description: Unique user identifier example: abcde12345 + anonymousId: + type: string + description: Secondary unique user identifier + example: d1e2f3g4h5 email: type: string description: Email address @@ -17,12 +21,65 @@ User: type: string description: Last name example: Figgis - instructor: - type: boolean - default: false - description: Boolean representing if the user is an instructor on the platform - example: cyrilfiggis@gmail.com - permissions: + picture: + type: string + description: URL of the user's avatar picture + example: https://avatars.githubusercontent.com/u/111111111?v=4 + courses: type: array items: - $ref: "#/definitions/CoursePermissions" + $ref: "#/definitions/UserCourse" +UserCourse: + type: object + properties: + course_id: + type: string + description: ID of the course the user joined + example: vytxeTZskVKR7C7WgdSP3d + course_name: + type: string + description: Name associated with the course + example: "CIS499 Advanced Debugging" + nickname: + type: string + description: Course nickname + example: "CIS499" + color: + type: string + description: Accent color used in course specific ui + example: "#ee55ee" + canPost: + type: boolean + description: If the user can post in the course + default: true + example: true + seePrivate: + type: boolean + description: If the user can see private posts in the course + default: false + example: false + canPin: + type: boolean + description: If the user user can pin posts + default: false + example: false + canRemove: + type: boolean + description: If the user can remove posts from the course + default: false + example: false + canEndorse: + type: boolean + description: If the user can endorse posts in the course + default: false + example: true + viewAnonymous: + type: boolean + description: If the user can view the identity of anonymous posters + default: false + example: true + admin: + type: boolean + description: If the user is an administrator of the course + default: false + example: false diff --git a/server/resources/courses.py b/server/resources/courses.py index 8881deab..0fe690a4 100644 --- a/server/resources/courses.py +++ b/server/resources/courses.py @@ -20,24 +20,20 @@ def post(self): Creates a new course and responds with the instructor's permissions for the course --- tags: - - Courses - definitions: - import: "./flasgger/courses.yml" - import: "./flasgger/responses.yml" - + - Courses responses: 200: description: Stored user data for the currently logged in user schema: - $ref: '#/definitions/CoursePermissions' + $ref: '#/definitions/UserCourse' 400: description: Array of errors gathered from request schema: - $ref: '#/definitions/400Message' + $ref: '#/definitions/400Response' 403: description: Unable to retrieve current user data schema: - $ref: '#/definitions/403Message' + $ref: '#/definitions/403Response' """ # Get json for POST requests request.get_json(force=True) diff --git a/server/resources/me.py b/server/resources/me.py index 8a435bae..806b1392 100644 --- a/server/resources/me.py +++ b/server/resources/me.py @@ -13,101 +13,9 @@ def get(self): tags: - User definitions: - User: - type: object - properties: - _id: - type: string - description: Unique user identifier - example: abcde12345 - anonymousId: - type: string - description: Secondary unique user identifier - example: d1e2f3g4h5 - email: - type: string - description: Email address - example: cyrilfiggis@gmail.com - first: - type: string - description: First name - example: Cyril - last: - type: string - description: Last name - example: Figgis - picture: - type: string - description: URL of the user's avatar picture - example: https://avatars.githubusercontent.com/u/111111111?v=4 - courses: - type: array - items: - $ref: '#/definitions/UserCourse' - - UserCourse: - type: object - properties: - course_id: - type: string - description: ID of the course the user joined - example: vytxeTZskVKR7C7WgdSP3d - course_name: - type: string - description: Name associated with the course - example: "CIS499 Advanced Debugging" - nickname: - type: string - description: Course nickname - example: "CIS499" - color: - type: string - description: Accent color used in course specific ui - example: "#ee55ee" - canPost: - type: boolean - description: If the user can post in the course - default: true - example: true - seePrivate: - type: boolean - description: If the user can see private posts in the course - default: false - example: false - canPin: - type: boolean - description: If the user user can pin posts - default: false - example: false - canRemove: - type: boolean - description: If the user can remove posts from the course - default: false - example: false - canEndorse: - type: boolean - description: If the user can endorse posts in the course - default: false - example: true - viewAnonymous: - type: boolean - description: If the user can view the identity of anonymous posters - default: false - example: true - admin: - type: boolean - description: If the user is an administrator of the course - default: false - example: false - - 403 Response: - type: object - description: Response to authorized requests - properties: - errors: - type: array - description: List of authorization errors - example: ["Resource access restricted: missing course permission(s) admin, seePrivate"] + import: "./flasgger/responses.yml" + import: "./flasgger/courses.yml" + import: "./flasgger/user.yml" responses: 200: @@ -117,6 +25,6 @@ def get(self): 403: description: Unable to retrieve current user data schema: - $ref: '#/definitions/403Message' + $ref: '#/definitions/403Response' """ return current_user.to_son().to_dict() From b6b9ad4d4b48211dad692dd4403ca9002da920be Mon Sep 17 00:00:00 2001 From: Alec Springel Date: Fri, 12 Mar 2021 16:14:59 -0800 Subject: [PATCH 4/9] Added shared.yml to flasgger --- server/flasgger/responses.yml | 2 +- server/flasgger/shared.yml | 33 +++++++++++++++++++++++++++++++++ server/resources/me.py | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 server/flasgger/shared.yml diff --git a/server/flasgger/responses.yml b/server/flasgger/responses.yml index 2a9ded2e..09b1f008 100644 --- a/server/flasgger/responses.yml +++ b/server/flasgger/responses.yml @@ -10,7 +10,7 @@ description: Response to authorized requests properties: errors: - type: array + type: list description: List of authorization errors example: [ diff --git a/server/flasgger/shared.yml b/server/flasgger/shared.yml new file mode 100644 index 00000000..96e7b2d4 --- /dev/null +++ b/server/flasgger/shared.yml @@ -0,0 +1,33 @@ +Reactions: + type: object + description: Reaction types with arrays of _ids of the users who reacted + properties: + likes: + type: list + description: List of users who have liked the content + example: ["abcde12345"] +PostedBy: + type: object + description: Information about the user who posted the content + properties: + first: + type: string + description: First name of the user who posted the content + example: Alec + last: + type: string + description: Last name of the user who posted the content + example: Springel + _id: + type: string + description: _id or anonymousId of user who posted the content + example: abcde12345 + anonymous: + type: boolean + default: false + description: Whether or not the content is posted anonymously + example: false + picture: + type: string + description: Profile photo URL + example: "https://google.com/user123/photo123" diff --git a/server/resources/me.py b/server/resources/me.py index 806b1392..2942762d 100644 --- a/server/resources/me.py +++ b/server/resources/me.py @@ -16,6 +16,7 @@ def get(self): import: "./flasgger/responses.yml" import: "./flasgger/courses.yml" import: "./flasgger/user.yml" + import: "./flasgger/shared.yml" responses: 200: From bd6e6e5f12d40bddaae841ce6aef83843e99ac31 Mon Sep 17 00:00:00 2001 From: Alec Springel Date: Fri, 12 Mar 2021 16:37:56 -0800 Subject: [PATCH 5/9] Added post docs --- server/flasgger/posts.yml | 57 +++++++++++++++++++++++++++++++++++++++ server/resources/me.py | 1 + server/resources/posts.py | 19 +++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 server/flasgger/posts.yml diff --git a/server/flasgger/posts.yml b/server/flasgger/posts.yml new file mode 100644 index 00000000..81d5515f --- /dev/null +++ b/server/flasgger/posts.yml @@ -0,0 +1,57 @@ +Post: + type: object + description: Posts with content created by users + properties: + _id: + type: string + description: Id of the user who created the post + example: abcde12345 + courseid: + type: string + description: Id of the course the post was created in + example: oFAeuzdT4VwKf3dHUFGhwu + postedby: + $ref: "#/definitions/PostedBy" + title: + type: string + description: Title of the post + example: Question about homework 3? + content: + type: string + description: Content of the post + example: This homework doesn't make any sense to me. What chapters does this cover in the book? + isInstructor: + type: boolean + default: false + description: Whether or not the post was created by an instructor + example: false + isPinned: + type: boolean + default: false + description: Whether or not the post is pinned + example: false + isPrivate: + type: boolean + default: false + description: Whether or not the post is private + example: false + instructorCommented: + type: boolean + default: false + description: Whether or not the instructor has responded to the post + example: false + reactions: + $ref: "#/definitions/Reactions" + comments: + type: integer + description: Number of comments on the post + default: 0 + example: 3 + createdDate: + type: string + description: Date the post was created + example: 2021-03-12 20:40:00.752000 + updatedDate: + type: string + description: Date the post was was last responded to or modified + example: 2021-03-13 21:20:00.322000 diff --git a/server/resources/me.py b/server/resources/me.py index 2942762d..61f5c932 100644 --- a/server/resources/me.py +++ b/server/resources/me.py @@ -17,6 +17,7 @@ def get(self): import: "./flasgger/courses.yml" import: "./flasgger/user.yml" import: "./flasgger/shared.yml" + import: "./flasgger/posts.yml" responses: 200: diff --git a/server/resources/posts.py b/server/resources/posts.py index 19aad7b1..0c4bca73 100644 --- a/server/resources/posts.py +++ b/server/resources/posts.py @@ -10,6 +10,25 @@ class Posts(Resource): def post(self, course_id=None): + """ + Creates a new post + --- + tags: + - Posts + responses: + 200: + description: Responds with the newly created post + schema: + $ref: '#/definitions/Post' + 400: + description: Array of errors gathered from request + schema: + $ref: '#/definitions/400Response' + 403: + description: Unable to retrieve current user data + schema: + $ref: '#/definitions/403Response' + """ course = current_user.get_course(course_id) if not course: return {"errors": ["You have not joined this course"]}, 403 From 82c4144fa4af3864065c474eda37a555d21028e6 Mon Sep 17 00:00:00 2001 From: Alec Springel Date: Fri, 12 Mar 2021 17:38:04 -0800 Subject: [PATCH 6/9] Added post resource to api docs --- server/flasgger/requests.yml | 21 ++++++ server/resources/me.py | 1 + server/resources/posts.py | 129 ++++++++++++++++++++++++++++++++++- 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 server/flasgger/requests.yml diff --git a/server/flasgger/requests.yml b/server/flasgger/requests.yml new file mode 100644 index 00000000..48abe7fc --- /dev/null +++ b/server/flasgger/requests.yml @@ -0,0 +1,21 @@ +POSTPostBody: + type: object + properties: + title: + type: string + description: Title of post + example: Question about homework 3? + content: + type: string + description: Content of the post + example: This homework doesn't make any sense to me. What chapters does this cover in the book? + isPrivate: + type: boolean + default: false + description: Whether or not the post is private + example: false + isAnonymous: + type: boolean + default: false + description: Whether or not the post is anonymous + example: false diff --git a/server/resources/me.py b/server/resources/me.py index 61f5c932..72003f9f 100644 --- a/server/resources/me.py +++ b/server/resources/me.py @@ -18,6 +18,7 @@ def get(self): import: "./flasgger/user.yml" import: "./flasgger/shared.yml" import: "./flasgger/posts.yml" + import: "./flasgger/requests.yml" responses: 200: diff --git a/server/resources/posts.py b/server/resources/posts.py index 0c4bca73..8d1fa6a3 100644 --- a/server/resources/posts.py +++ b/server/resources/posts.py @@ -14,7 +14,18 @@ def post(self, course_id=None): Creates a new post --- tags: - - Posts + - Posts + parameters: + - in: path + name: course_id + description: Id of the course to post to + required: true + - name: body + in: body + required: true + description: Content and post options + schema: + $ref: '#/definitions/POSTPostBody' responses: 200: description: Responds with the newly created post @@ -71,6 +82,47 @@ def post(self, course_id=None): return result, 200 def get(self, course_id=None): + """ + Creates a new post + --- + tags: + - Posts + parameters: + - in: path + name: course_id + required: true + description: course id from which to retrieve posts + - in: query + name: filterby + schema: + type: string + enum: ['instructor', 'me', 'myupvoted'] + required: false + description: Filter posts by category + - in: query + name: sortby + schema: + type: string + enum: ['newest', 'oldest'] + required: false + default: 'newest' + description: Sort posts by age + responses: + 200: + description: Responds with array of posts + schema: + type: array + items: + $ref: '#/definitions/Post' + 400: + description: Array of errors gathered from request + schema: + $ref: '#/definitions/400Response' + 403: + description: Unable to retrieve current user data + schema: + $ref: '#/definitions/403Response' + """ # Get the search input and the current course req = request.args.get('search') page = request.args.get('page', default=0, type=int) @@ -135,6 +187,51 @@ def get(self, course_id=None): return result, 200 def delete(self, course_id=None): + """ + Creates a new post + --- + tags: + - Posts + parameters: + - in: path + name: course_id + required: true + description: course id from which to retrieve posts + - name: body + in: body + required: true + description: Content and post options + schema: + type: object + properties: + _id: + type: string + description: Id of the post + example: abcde12345 + responses: + 200: + description: Responds with success or failure + schema: + type: object + properties: + deleted: + type: boolean + description: Whether or not the post was deleted + example: true + 400: + description: Array of errors gathered from request + schema: + $ref: '#/definitions/400Response' + 403: + description: Unable to delete the post + schema: + type: object + properties: + deleted: + type: boolean + description: Whether or not the post was deleted + example: false + """ # Parse arguments parser = reqparse.RequestParser() parser.add_argument('_id') @@ -164,6 +261,36 @@ def delete(self, course_id=None): raise Exception(f'No post with id') def put(self, course_id): + """ + Edits a post + --- + tags: + - Posts + parameters: + - in: path + name: course_id + description: Id of the course to post to + required: true + - name: body + in: body + required: true + description: Content and post options + schema: + $ref: '#/definitions/POSTPostBody' + responses: + 200: + description: Responds with the newly edited post + schema: + $ref: '#/definitions/Post' + 400: + description: Array of errors gathered from request + schema: + $ref: '#/definitions/400Response' + 403: + description: Unable to retrieve current user data + schema: + $ref: '#/definitions/403Response' + """ # Parse the request parser = reqparse.RequestParser() parser.add_argument('title') From d40a220846b1ef5578776de991a4c623f8378a6e Mon Sep 17 00:00:00 2001 From: Alec Springel Date: Fri, 12 Mar 2021 17:59:56 -0800 Subject: [PATCH 7/9] Reaction and course docs --- server/resources/courses.py | 14 +++++++++++- server/resources/reactions.py | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/server/resources/courses.py b/server/resources/courses.py index 0fe690a4..24e28b49 100644 --- a/server/resources/courses.py +++ b/server/resources/courses.py @@ -20,7 +20,19 @@ def post(self): Creates a new course and responds with the instructor's permissions for the course --- tags: - - Courses + - Courses + parameters: + - name: body + in: body + required: true + description: Course creation options + schema: + type: object + properties: + course: + type: string + description: Name of the course + example: CIS 422 responses: 200: description: Stored user data for the currently logged in user diff --git a/server/resources/reactions.py b/server/resources/reactions.py index b8300adc..42996bc2 100644 --- a/server/resources/reactions.py +++ b/server/resources/reactions.py @@ -6,6 +6,49 @@ class Reactions(Resource): def put(self): + """ + Responds with a reaction to a post, comment, or reply + --- + tags: + - Reactions + parameters: + - in: query + name: postid + schema: + type: string + example: "postid123" + required: true + description: Id of the post to react to + - in: query + name: commentid + schema: + type: string + example: "commentid321" + required: true + description: Id of the comment to react to + - in: query + name: replyid + schema: + type: string + example: "replyid321" + required: true + description: Id of the reply to react to + responses: + 200: + description: Responds with reactions object + schema: + type: array + items: + $ref: '#/definitions/Reactions' + 400: + description: Array of errors gathered from request + schema: + $ref: '#/definitions/400Response' + 403: + description: Unable to retrieve current user data + schema: + $ref: '#/definitions/403Response' + """ # Parse arguments postid = request.args.get('postid') commentid = request.args.get('commentid') From eb5ba3e82771a9726798c5eefd70eb5da5e04f4f Mon Sep 17 00:00:00 2001 From: Sam Peters Date: Fri, 12 Mar 2021 18:04:16 -0800 Subject: [PATCH 8/9] Work on api docs --- server/flasgger/comments.yml | 47 ++++++++++++++ server/flasgger/replies.yml | 36 +++++++++++ server/flasgger/responses.yml | 3 +- server/resources/comments.py | 117 ++++++++++++++++++++++++++++++++-- server/resources/me.py | 2 + server/resources/replies.py | 31 ++++++++- 6 files changed, 226 insertions(+), 10 deletions(-) create mode 100644 server/flasgger/comments.yml create mode 100644 server/flasgger/replies.yml diff --git a/server/flasgger/comments.yml b/server/flasgger/comments.yml new file mode 100644 index 00000000..7f1c1b63 --- /dev/null +++ b/server/flasgger/comments.yml @@ -0,0 +1,47 @@ +Comment: + type: object + description: Comment on a post + properties: + post_id: + required: true + type: string + description: Id of the parent post + example: abcde12345 + content: + required: true + type: string + description: Comment content + example: I also have that question! + postedby: + required: true + $ref: "#/definitions/PostedBy" + endorsed: + required: true + type: boolean + description: If the instructor endorsed this comment + default: false + example: true + replies: + required: true + type: array + items: + $ref: "#/definitions/Reply" + reactions: + required: true + $ref: "#/definitions/Reactions" + +CommentBody: + type: object + description: A new comment sent from a client + properties: + content: + required: true + type: string + description: Comment content + example: I also have that question! + isAnonymous: + required: true + type: boolean + description: If the user wants the comment to be anonymous + default: false + example: true \ No newline at end of file diff --git a/server/flasgger/replies.yml b/server/flasgger/replies.yml new file mode 100644 index 00000000..0dd17e4b --- /dev/null +++ b/server/flasgger/replies.yml @@ -0,0 +1,36 @@ +Reply: + type: object + description: Reply to a comment + properties: + _id: + type: string + required: true + description: Reply ID + example: ofjaepwofj324 + content: + type: string + required: true + description: Comment content + example: That is a great comment. Wow! + postedby: + required: true + $ref: "#/definitions/PostedBy" + reactions: + required: true + $ref: "#/definitions/Reactions" + +ReplyBody: + type: object + description: A new reply sent from a client + properties: + content: + required: true + type: string + description: Reply content + example: That's a great comment! + isAnonymous: + required: true + type: boolean + description: If the user wants the reply to be anonymous + default: false + example: true \ No newline at end of file diff --git a/server/flasgger/responses.yml b/server/flasgger/responses.yml index 09b1f008..66e5ecd5 100644 --- a/server/flasgger/responses.yml +++ b/server/flasgger/responses.yml @@ -1,5 +1,6 @@ 400Response: type: object + description: Response to bad requests properties: errors: type: list @@ -7,7 +8,7 @@ example: ["Invalid courseid"] 403Response: type: object - description: Response to authorized requests + description: Response to unauthorized requests properties: errors: type: list diff --git a/server/resources/comments.py b/server/resources/comments.py index 4de4a364..582bb760 100644 --- a/server/resources/comments.py +++ b/server/resources/comments.py @@ -7,7 +7,27 @@ class Comments(Resource): def get(self, post_id=None): - # Get all comments on post + """ + Retrieves all the comments responding to a specific post + --- + parameters: + - in: path + description: Id of a post + name: post_id + required: true + tags: + - Comments + responses: + 200: + description: Returns list of comments + schema: + type: array + items: + $ref: '#/definitions/Comment' + 400: + schema: + $ref: '#/definitions/400Response' + """ post = self.retrieve_post(post_id) if post is None: return abort(400, errors=["Bad post id"]) @@ -15,8 +35,31 @@ def get(self, post_id=None): return [self.serialize(comment) for comment in Comment.objects.raw({'post_id': post_id})] def post(self, post_id=None): - # Add comment to post - # Retrieving post + """ + Creates a new comment + --- + tags: + - Comments + parameters: + - in: path + description: Id of a post + name: post_id + required: true + - name: body + in: body + description: Submitted comment data + required: true + schema: + $ref: '#/definitions/CommentBody' + responses: + 200: + description: Returns created comment + schema: + $ref: '#/definitions/Comment' + 400: + schema: + $ref: '#/definitions/400Response' + """ print("here") post = self.retrieve_post(post_id) if post is None: @@ -53,8 +96,31 @@ def post(self, post_id=None): return result, 200 def put(self, post_id=None): - # Update comment - # Parse the request + """ + Updates a comment + --- + tags: + - Comments + parameters: + - in: path + description: Id of a post + name: post_id + required: true + - name: body + in: body + description: Submitted comment data + required: true + schema: + $ref: '#/definitions/CommentBody' + responses: + 200: + description: Returns updated comment + schema: + $ref: '#/definitions/Comment' + 400: + schema: + $ref: '#/definitions/400Response' + """ post = self.retrieve_post(post_id) parser = reqparse.RequestParser() @@ -89,8 +155,45 @@ def put(self, post_id=None): raise Exception(f'No comment with id') def delete(self, post_id=None): - # Delete comment - # Grabbing comment id + """ + Deletes a comment + --- + tags: + - Comments + parameters: + - in: path + description: Id of a post + name: post_id + required: true + - name: body + in: body + description: Data needed to delete comment + required: true + schema: + type: object + properties: + _id: + type: string + description: Id of the comment + example: abcde12345 + responses: + 200: + description: Returns successful delete + schema: + type: object + properties: + deleted: + type: bool + example: True + 403: + description: Returns unsuccessful delete + schema: + type: object + properties: + deleted: + type: bool + example: False + """ post = self.retrieve_post(post_id) parser = reqparse.RequestParser() parser.add_argument('_id') diff --git a/server/resources/me.py b/server/resources/me.py index 61f5c932..02e904f7 100644 --- a/server/resources/me.py +++ b/server/resources/me.py @@ -18,6 +18,8 @@ def get(self): import: "./flasgger/user.yml" import: "./flasgger/shared.yml" import: "./flasgger/posts.yml" + import: "./flasgger/comments.yml" + import: "./flasgger/replies.yml" responses: 200: diff --git a/server/resources/replies.py b/server/resources/replies.py index a322bd18..6b91f9a0 100644 --- a/server/resources/replies.py +++ b/server/resources/replies.py @@ -7,8 +7,35 @@ class Replies(Resource): def post(self, post_id=None, comment_id=None): - # Add comment to post - # Retrieving post + """ + Creates a new reply + --- + tags: + - Replies + parameters: + - in: path + description: Id of a post + name: post_id + required: true + - in: path + description: Id of a comment + name: comment_id + required: true + - name: body + in: body + description: Submitted reply data + required: true + schema: + $ref: '#/definitions/ReplyBody' + responses: + 200: + description: Returns created reply + schema: + $ref: '#/definitions/Reply' + 400: + schema: + $ref: '#/definitions/400Response' + """ post = self.retrieve_post(post_id) if post is None: return abort(400, errors=["Bad post id"]) From e5be0b37ed5d5b570cb920aba48ebd6d242640b8 Mon Sep 17 00:00:00 2001 From: Sam Peters Date: Fri, 12 Mar 2021 18:43:10 -0800 Subject: [PATCH 9/9] Added api documentation for home and join resources --- server/resources/comments.py | 2 +- server/resources/home.py | 14 +++++- server/resources/join.py | 82 +++++++++++++++++++++++++++++++++++- server/resources/posts.py | 6 +-- server/resources/replies.py | 74 +++++++++++++++++++++++++++++++- 5 files changed, 169 insertions(+), 9 deletions(-) diff --git a/server/resources/comments.py b/server/resources/comments.py index 582bb760..16a16993 100644 --- a/server/resources/comments.py +++ b/server/resources/comments.py @@ -167,7 +167,7 @@ def delete(self, post_id=None): required: true - name: body in: body - description: Data needed to delete comment + description: Data needed to delete a comment required: true schema: type: object diff --git a/server/resources/home.py b/server/resources/home.py index 05eefec7..c9ddc038 100644 --- a/server/resources/home.py +++ b/server/resources/home.py @@ -9,7 +9,19 @@ class Home(Resource): def get(self): - + """ + Retrieves all the posts in a users feed + --- + tags: + - Other + responses: + 200: + description: Returns list of posts + schema: + type: array + items: + $ref: '#/definitions/Post' + """ # TODO: should I add this? Would you be able to handle this format on the front end or should I change it? if len(current_user.courses) == 0: return [] diff --git a/server/resources/join.py b/server/resources/join.py index 74b7ab7f..f33fa330 100644 --- a/server/resources/join.py +++ b/server/resources/join.py @@ -6,7 +6,53 @@ class Join(Resource): def post(self): - # Parse arguments + """ + Begins adding user to course + --- + tags: + - Other + parameters: + - name: body + in: body + description: Course the user wants to join + required: true + schema: + type: object + properties: + course_name: + type: string + description: Name of the course + example: CIS 499 Advanced Debugging + access_code: + type: string + description: Access code for the course + example: ihuaweoliawfeh + responses: + 200: + description: Returns additional course information + schema: + type: object + properties: + course_name: + type: string + description: Name of the course + example: CIS 499 Advanced Debugging + course_id: + type: string + description: Id of the course + example: qewruiopq12313 + first: + type: string + description: Instructor first name + example: Sam + last: + type: string + description: Instructor last name + example: Peters + 400: + schema: + $ref: '#/definitions/400Response' + """ parser = reqparse.RequestParser() parser.add_argument('course_name') parser.add_argument('access_code') @@ -43,7 +89,39 @@ def post(self): return {"course_id": course._id, "course": course.course, "first": instructor.first, "last": instructor.last}, 200 def put(self): - # Parse arguments + """ + Confirms adding user to course + --- + tags: + - Other + parameters: + - name: body + in: body + description: Course the user wants to join + required: true + schema: + type: object + properties: + course_id: + type: string + description: Id of the course + example: abcde12389 + responses: + 200: + description: Returns successful delete + schema: + type: object + properties: + success: + required: true + type: string + example: Course joined successfully + course: + $ref: '#/definitions/UserCourse' + 400: + schema: + $ref: '#/definitions/400Response' + """ parser = reqparse.RequestParser() parser.add_argument('course_id') args = parser.parse_args() diff --git a/server/resources/posts.py b/server/resources/posts.py index 8d1fa6a3..5de5c4ff 100644 --- a/server/resources/posts.py +++ b/server/resources/posts.py @@ -83,7 +83,7 @@ def post(self, course_id=None): def get(self, course_id=None): """ - Creates a new post + Retrieves all the posts in a course --- tags: - Posts @@ -188,7 +188,7 @@ def get(self, course_id=None): def delete(self, course_id=None): """ - Creates a new post + Deletes a post --- tags: - Posts @@ -196,7 +196,7 @@ def delete(self, course_id=None): - in: path name: course_id required: true - description: course id from which to retrieve posts + description: Id of a course - name: body in: body required: true diff --git a/server/resources/replies.py b/server/resources/replies.py index 6b91f9a0..89f397c8 100644 --- a/server/resources/replies.py +++ b/server/resources/replies.py @@ -74,7 +74,35 @@ def post(self, post_id=None, comment_id=None): return result, 200 def put(self, post_id=None, comment_id=None): - # Update comment + """ + Updates a reply + --- + tags: + - Replies + parameters: + - in: path + description: Id of a post + name: post_id + required: true + - in: path + description: Id of a comment + name: comment_id + required: true + - name: body + in: body + description: Submitted reply data + required: true + schema: + $ref: '#/definitions/ReplyBody' + responses: + 200: + description: Returns updated comment + schema: + $ref: '#/definitions/Comment' + 400: + schema: + $ref: '#/definitions/400Response' + """ post = self.retrieve_post(post_id) # Parse the request @@ -112,7 +140,49 @@ def put(self, post_id=None, comment_id=None): return result, 200 def delete(self, post_id=None, comment_id=None): - # Delete comment + """ + Deletes a reply + --- + tags: + - Replies + parameters: + - in: path + description: Id of a post + name: post_id + required: true + - in: path + description: Id of a comment + name: comment_id + required: true + - name: body + in: body + description: Data needed to delete a reply + required: true + schema: + type: object + properties: + _id: + type: string + description: Id of the reply + example: abcde12345 + responses: + 200: + description: Returns successful delete + schema: + type: object + properties: + deleted: + type: bool + example: True + 403: + description: Returns unsuccessful delete + schema: + type: object + properties: + deleted: + type: bool + example: False + """ post = self.retrieve_post(post_id) # Grabbing comment id