This repository has been archived by the owner on Jan 22, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* create subfolder for course tests * added table for share codes * loading env variables * added default value to function parameters * added endpoint for join_codes * added tests for join_codes * fixed: linting * fixed typo: * fixed import conftest * fixed merge with singular model naming * unused file
- Loading branch information
1 parent
b3e18b0
commit 7dc3923
Showing
12 changed files
with
258 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
backend/project/endpoints/courses/join_codes/course_join_code.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
""" | ||
This file will contain the api endpoints for the /courses/<course_id>/join_codes url | ||
""" | ||
|
||
from os import getenv | ||
from urllib.parse import urljoin | ||
from dotenv import load_dotenv | ||
|
||
from flask_restful import Resource | ||
from project.utils.query_agent import query_by_id_from_model, delete_by_id_from_model | ||
from project.models.course_share_code import CourseShareCode | ||
from project.endpoints.courses.join_codes.join_codes_utils import check_course_exists | ||
|
||
load_dotenv() | ||
API_URL = getenv("API_HOST") | ||
RESPONSE_URL = urljoin(f"{API_URL}/", "courses") | ||
|
||
class CourseJoinCode(Resource): | ||
""" | ||
This class will handle post and delete queries to | ||
the /courses/course_id/join_codes url, only an admin of a course can do this | ||
""" | ||
|
||
@check_course_exists | ||
def get(self, course_id, join_code): | ||
""" | ||
This function will return all the join codes of a course | ||
""" | ||
|
||
return query_by_id_from_model( | ||
CourseShareCode, | ||
"join_code", | ||
join_code, | ||
urljoin(f"{RESPONSE_URL}/", f"{str(course_id)}/", "join_codes") | ||
) | ||
|
||
@check_course_exists | ||
def delete(self, course_id, join_code): | ||
""" | ||
Api endpoint for adding new join codes to a course, can only be done by the teacher | ||
""" | ||
|
||
return delete_by_id_from_model( | ||
CourseShareCode, | ||
"join_code", | ||
join_code, | ||
urljoin(f"{RESPONSE_URL}/", f"{str(course_id)}/", "join_codes") | ||
) |
55 changes: 55 additions & 0 deletions
55
backend/project/endpoints/courses/join_codes/course_join_codes.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
""" | ||
This file will contain the api endpoints for the /courses/<course_id>/join_codes url | ||
""" | ||
|
||
from os import getenv | ||
from urllib.parse import urljoin | ||
from dotenv import load_dotenv | ||
|
||
from flask_restful import Resource | ||
from flask import request | ||
from project.utils.query_agent import query_selected_from_model, insert_into_model | ||
from project.models.course_share_code import CourseShareCode | ||
from project.endpoints.courses.courses_utils import get_course_abort_if_not_found | ||
|
||
load_dotenv() | ||
API_URL = getenv("API_HOST") | ||
RESPONSE_URL = urljoin(f"{API_URL}/", "courses") | ||
|
||
class CourseJoinCodes(Resource): | ||
""" | ||
This class will handle post and delete queries to | ||
the /courses/course_id/join_codes url, only an admin of a course can do this | ||
""" | ||
|
||
def get(self, course_id): | ||
""" | ||
This function will return all the join codes of a course | ||
""" | ||
|
||
get_course_abort_if_not_found(course_id) | ||
|
||
return query_selected_from_model( | ||
CourseShareCode, | ||
urljoin(f"{RESPONSE_URL}/", f"{str(course_id)}/", "join_codes"), | ||
select_values=["join_code", "expiry_time"], | ||
filters={"course_id": course_id} | ||
) | ||
|
||
def post(self, course_id): | ||
""" | ||
Api endpoint for adding new join codes to a course, can only be done by the teacher | ||
""" | ||
|
||
get_course_abort_if_not_found(course_id) | ||
|
||
data = request.get_json() | ||
data["course_id"] = course_id | ||
|
||
return insert_into_model( | ||
CourseShareCode, | ||
data, | ||
urljoin(f"{RESPONSE_URL}/", f"{str(course_id)}/", "join_codes"), | ||
"join_code", | ||
required_fields=["for_admins"] | ||
) |
24 changes: 24 additions & 0 deletions
24
backend/project/endpoints/courses/join_codes/join_codes_config.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
""" | ||
This file is used to configure the join codes endpoints. | ||
It is used to define the routes for the join codes blueprint and the | ||
corresponding api endpoints. | ||
The join codes blueprint is used to define the routes for the join codes api | ||
endpoints and the join codes api is used to define the routes for the join codes | ||
api endpoints. | ||
""" | ||
|
||
from flask import Blueprint | ||
from flask_restful import Api | ||
|
||
from project.endpoints.courses.join_codes.course_join_codes import CourseJoinCodes | ||
from project.endpoints.courses.join_codes.course_join_code import CourseJoinCode | ||
|
||
join_codes_bp = Blueprint("join_codes", __name__) | ||
join_codes_api = Api(join_codes_bp) | ||
|
||
join_codes_bp.add_url_rule("/courses/<int:course_id>/join_codes", | ||
view_func=CourseJoinCodes.as_view('course_join_codes')) | ||
|
||
join_codes_bp.add_url_rule("/courses/<int:course_id>/join_codes/<string:join_code>", | ||
view_func=CourseJoinCode.as_view('course_join_code')) |
14 changes: 14 additions & 0 deletions
14
backend/project/endpoints/courses/join_codes/join_codes_utils.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
""" | ||
This module contains functions that are used by the join codes resources. | ||
""" | ||
|
||
from project.endpoints.courses.courses_utils import get_course_abort_if_not_found | ||
|
||
def check_course_exists(func): | ||
""" | ||
Middleware to check if the course exists before handling the request | ||
""" | ||
def wrapper(self, course_id, join_code, *args, **kwargs): | ||
get_course_abort_if_not_found(course_id) | ||
return func(self, course_id, join_code, *args, **kwargs) | ||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
""" | ||
Course Share Code Model | ||
""" | ||
|
||
|
||
from dataclasses import dataclass | ||
import uuid | ||
from sqlalchemy import Integer, Column, ForeignKey, Date, Boolean | ||
from sqlalchemy.dialects.postgresql import UUID | ||
from project import db | ||
|
||
@dataclass | ||
class CourseShareCode(db.Model): | ||
""" | ||
This class will contain the model for the course share codes | ||
""" | ||
__tablename__ = "course_join_codes" | ||
|
||
join_code: int = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) | ||
course_id: int = Column(Integer, ForeignKey("courses.course_id"), nullable=False) | ||
expiry_time: str = Column(Date, nullable=True) | ||
for_admins: bool = Column(Boolean, nullable=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
""" | ||
This file contains the tests for the share link endpoints of the course resource. | ||
""" | ||
|
||
from project.models.course import Course | ||
|
||
class TestCourseShareLinks: | ||
""" | ||
Class that will respond to the /courses/course_id/students link | ||
teachers should be able to assign and remove students from courses, | ||
and everyone should be able to list all students assigned to a course | ||
""" | ||
|
||
def test_get_share_links(self, db_with_course, client): | ||
"""Test whether the share links are accessible""" | ||
example_course = db_with_course.query(Course).first() | ||
response = client.get(f"courses/{example_course.course_id}/join_codes") | ||
assert response.status_code == 200 | ||
|
||
def test_post_share_links(self, db_with_course, client): | ||
"""Test whether the share links are accessible to post to""" | ||
example_course = db_with_course.query(Course).first() | ||
response = client.post( | ||
f"courses/{example_course.course_id}/join_codes", | ||
json={"for_admins": True}) | ||
assert response.status_code == 201 | ||
|
||
def test_delete_share_links(self, share_code_admin, client): | ||
"""Test whether the share links are accessible to delete""" | ||
response = client.delete( | ||
f"courses/{share_code_admin.course_id}/join_codes/{share_code_admin.join_code}") | ||
assert response.status_code == 200 | ||
|
||
def test_get_share_links_404(self, client): | ||
"""Test whether the share links are accessible""" | ||
response = client.get("courses/0/join_codes") | ||
assert response.status_code == 404 | ||
|
||
def test_post_share_links_404(self, client): | ||
"""Test whether the share links are accessible to post to""" | ||
response = client.post("courses/0/join_codes", json={"for_admins": True}) | ||
assert response.status_code == 404 | ||
|
||
def test_delete_share_links_404(self, client): | ||
"""Test whether the share links are accessible to delete""" | ||
response = client.delete("courses/0/join_codes/0") | ||
assert response.status_code == 404 | ||
|
||
def test_for_admins_required(self, db_with_course, client): | ||
"""Test whether the for_admins field is required""" | ||
example_course = db_with_course.query(Course).first() | ||
response = client.post(f"courses/{example_course.course_id}/join_codes", json={}) | ||
assert response.status_code == 400 |