Skip to content
This repository has been archived by the owner on May 24, 2022. It is now read-only.

Commit

Permalink
Merge branch 'develop' into stateshistory_list
Browse files Browse the repository at this point in the history
  • Loading branch information
stijndcl authored May 20, 2022
2 parents 5ec5b0f + fcfce12 commit cc8247e
Show file tree
Hide file tree
Showing 52 changed files with 476 additions and 202 deletions.
22 changes: 7 additions & 15 deletions backend/src/app/logic/editions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,16 @@ async def get_edition_by_name(db: AsyncSession, edition_name: str) -> EditionMod


async def create_edition(db: AsyncSession, edition: EditionBase) -> EditionModel:
""" Create a new edition.
Args:
db (Session): connection with the database.
Returns:
Edition: the newly made edition object.
"""
"""Create a new edition."""
return await crud_editions.create_edition(db, edition)


async def delete_edition(db: AsyncSession, edition_name: str):
"""Delete an existing edition.
"""Delete an existing edition."""
await crud_editions.delete_edition(db, edition_name)

Args:
db (Session): connection with the database.
edition_name (str): the name of the edition that needs to be deleted, if found.

Returns: nothing
"""
await crud_editions.delete_edition(db, edition_name)
async def patch_edition(db: AsyncSession, edition: EditionModel, readonly: bool) -> EditionModel:
"""Edit an existing edition"""
await crud_editions.patch_edition(db, edition, readonly)
return edition
6 changes: 3 additions & 3 deletions backend/src/app/logic/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import src.database.crud.users as users_crud
from src.app.schemas.users import UsersListResponse, AdminPatch, UserRequestsResponse, user_model_to_schema, \
FilterParameters, UserRequest
from src.database.models import User
from src.database.models import User, Edition


async def get_users_list(
Expand All @@ -20,9 +20,9 @@ async def get_users_list(
return UsersListResponse(users=[user_model_to_schema(user) for user in users_orm])


async def get_user_editions(db: AsyncSession, user: User) -> list[str]:
async def get_user_editions(db: AsyncSession, user: User) -> list[Edition]:
"""Get all names of the editions this user is coach in"""
return await users_crud.get_user_edition_names(db, user)
return await users_crud.get_user_editions(db, user)


async def edit_admin_status(db: AsyncSession, user_id: int, admin: AdminPatch):
Expand Down
21 changes: 16 additions & 5 deletions backend/src/app/routers/editions/editions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@

from src.app.logic import editions as logic_editions
from src.app.routers.tags import Tags
from src.app.schemas.editions import EditionBase, Edition, EditionList
from src.app.schemas.editions import EditionBase, Edition, EditionList, EditEdition
from src.database.database import get_session
from src.database.models import User
from src.database.models import User, Edition as EditionDB
from .invites import invites_router
from .projects import projects_router
from .register import registration_router
from .students import students_router
from .webhooks import webhooks_router
from ...utils.dependencies import require_admin, require_auth, require_coach, require_coach_ws
# Don't add the "Editions" tag here, because then it gets applied
# to all child routes as well
from ...utils.dependencies import require_admin, require_auth, require_coach, require_coach_ws, get_edition
from ...utils.websockets import DataPublisher, get_publisher

# Don't add the "Editions" tag here, because then it gets applied
# to all child routes as well
editions_router = APIRouter(prefix="/editions")

# Register all child routers
Expand All @@ -45,6 +45,17 @@ async def get_editions(db: AsyncSession = Depends(get_session), user: User = Dep
return EditionList(editions=user.editions)


@editions_router.patch("/{edition_name}", response_class=Response, tags=[Tags.EDITIONS],
dependencies=[Depends(require_admin)], status_code=status.HTTP_204_NO_CONTENT)
async def patch_edition(edit_edition: EditEdition, edition: EditionDB = Depends(get_edition),
db: AsyncSession = Depends(get_session)):
"""Change the readonly status of an edition
Note that this route is not behind "get_editable_edition", because otherwise you'd never be able
to change the status back to False
"""
await logic_editions.patch_edition(db, edition, edit_edition.readonly)


@editions_router.get(
"/{edition_name}",
response_model=Edition,
Expand Down
4 changes: 2 additions & 2 deletions backend/src/app/routers/editions/invites/invites.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from src.app.logic.invites import create_mailto_link, delete_invite_link, get_pending_invites_page
from src.app.routers.tags import Tags
from src.app.utils.dependencies import get_edition, get_invite_link, require_admin, get_latest_edition
from src.app.utils.dependencies import get_edition, get_invite_link, require_admin, get_editable_edition
from src.app.schemas.invites import InvitesLinkList, EmailAddress, NewInviteLink, InviteLink as InviteLinkModel
from src.database.database import get_session
from src.database.models import Edition, InviteLink as InviteLinkDB
Expand All @@ -24,7 +24,7 @@ async def get_invites(db: AsyncSession = Depends(get_session), edition: Edition
@invites_router.post("", status_code=status.HTTP_201_CREATED, response_model=NewInviteLink,
dependencies=[Depends(require_admin)])
async def create_invite(email: EmailAddress, db: AsyncSession = Depends(get_session),
edition: Edition = Depends(get_latest_edition)):
edition: Edition = Depends(get_editable_edition)):
"""
Create a new invitation link for the current edition.
"""
Expand Down
10 changes: 5 additions & 5 deletions backend/src/app/routers/editions/projects/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from src.app.schemas.projects import (
ProjectList, Project, InputProject, ConflictStudentList, QueryParamsProjects
)
from src.app.utils.dependencies import get_edition, get_project, require_admin, require_coach, get_latest_edition
from src.app.utils.dependencies import get_edition, get_project, require_admin, require_coach, get_editable_edition
from src.app.utils.websockets import live
from src.database.database import get_session
from src.database.models import Edition, Project as ProjectModel, User
Expand Down Expand Up @@ -40,7 +40,7 @@ async def get_projects(
async def create_project(
input_project: InputProject,
db: AsyncSession = Depends(get_session),
edition: Edition = Depends(get_latest_edition)):
edition: Edition = Depends(get_editable_edition)):
"""Create a new project"""
return await logic.create_project(db, edition,
input_project)
Expand Down Expand Up @@ -79,7 +79,7 @@ async def get_project_route(project: ProjectModel = Depends(get_project)):
@projects_router.patch(
"/{project_id}",
status_code=status.HTTP_204_NO_CONTENT, response_class=Response,
dependencies=[Depends(require_admin), Depends(get_latest_edition), Depends(live)]
dependencies=[Depends(require_admin), Depends(get_editable_edition), Depends(live)]
)
async def patch_project(
input_project: InputProject,
Expand All @@ -104,7 +104,7 @@ async def get_project_roles(project: ProjectModel = Depends(get_project), db: As
@projects_router.post(
"/{project_id}/roles",
response_model=ProjectRoleSchema,
dependencies=[Depends(require_admin), Depends(get_latest_edition), Depends(live)]
dependencies=[Depends(require_admin), Depends(get_editable_edition), Depends(live)]
)
async def post_project_role(
input_project_role: InputProjectRole,
Expand All @@ -117,7 +117,7 @@ async def post_project_role(
@projects_router.patch(
"/{project_id}/roles/{project_role_id}",
response_model=ProjectRoleSchema,
dependencies=[Depends(require_admin), Depends(get_latest_edition), Depends(get_project), Depends(live)]
dependencies=[Depends(require_admin), Depends(get_editable_edition), Depends(get_project), Depends(live)]
)
async def patch_project_role(
input_project_role: InputProjectRole,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from src.app.routers.tags import Tags
from src.app.schemas.projects import InputArgumentation, ReturnProjectRoleSuggestion
from src.app.utils.dependencies import (
require_coach, get_latest_edition, get_student,
require_coach, get_editable_edition, get_student,
get_project_role, get_edition
)
from src.app.utils.websockets import live
Expand Down Expand Up @@ -35,7 +35,7 @@ async def remove_student_from_project(
@project_students_router.patch(
"/{student_id}",
status_code=status.HTTP_204_NO_CONTENT, response_class=Response,
dependencies=[Depends(get_latest_edition), Depends(live)]
dependencies=[Depends(get_editable_edition), Depends(live)]
)
async def change_project_role(
argumentation: InputArgumentation,
Expand All @@ -52,7 +52,7 @@ async def change_project_role(
@project_students_router.post(
"/{student_id}",
status_code=status.HTTP_201_CREATED,
dependencies=[Depends(get_latest_edition), Depends(live)],
dependencies=[Depends(get_editable_edition), Depends(live)],
response_model=ReturnProjectRoleSuggestion
)
async def add_student_to_project(
Expand Down
6 changes: 3 additions & 3 deletions backend/src/app/routers/editions/register/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from src.app.logic.register import create_request_email, create_request_github
from src.app.routers.tags import Tags
from src.app.schemas.register import EmailRegister, GitHubRegister
from src.app.utils.dependencies import get_latest_edition, get_http_session
from src.app.utils.dependencies import get_editable_edition, get_http_session
from src.database.database import get_session
from src.database.models import Edition

Expand All @@ -16,7 +16,7 @@

@registration_router.post("/email", status_code=status.HTTP_201_CREATED)
async def register_email(register_data: EmailRegister, db: AsyncSession = Depends(get_session),
edition: Edition = Depends(get_latest_edition)):
edition: Edition = Depends(get_editable_edition)):
"""
Register a new account using the email/password format.
"""
Expand All @@ -26,7 +26,7 @@ async def register_email(register_data: EmailRegister, db: AsyncSession = Depend
@registration_router.post("/github", status_code=status.HTTP_201_CREATED)
async def register_github(register_data: GitHubRegister, db: AsyncSession = Depends(get_session),
http_session: ClientSession = Depends(get_http_session),
edition: Edition = Depends(get_latest_edition)):
edition: Edition = Depends(get_editable_edition)):
"""Register a new account using GitHub OAuth."""
access_token_data = await get_github_access_token(http_session, register_data.code)
user_email = await get_github_profile(http_session, access_token_data.access_token)
Expand Down
6 changes: 3 additions & 3 deletions backend/src/app/routers/editions/students/students.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
ReturnStudentMailList, NewEmail, EmailsSearchQueryParams,
ListReturnStudentMailList
)
from src.app.utils.dependencies import get_latest_edition, get_student, get_edition, require_admin, require_auth
from src.app.utils.dependencies import get_editable_edition, get_student, get_edition, require_admin, require_auth
from src.app.utils.websockets import live
from src.database.database import get_session
from src.database.models import Student, Edition, User
Expand Down Expand Up @@ -47,7 +47,7 @@ async def get_students(db: AsyncSession = Depends(get_session),
async def send_emails(
new_email: NewEmail,
db: AsyncSession = Depends(get_session),
edition: Edition = Depends(get_latest_edition)):
edition: Edition = Depends(get_editable_edition)):
"""
Send a email to a list of students.
"""
Expand Down Expand Up @@ -92,7 +92,7 @@ async def get_student_by_id(edition: Edition = Depends(get_edition), student: St

@students_router.put(
"/{student_id}/decision",
dependencies=[Depends(require_admin), Depends(live), Depends(get_latest_edition)],
dependencies=[Depends(require_admin), Depends(live), Depends(get_editable_edition)],
status_code=status.HTTP_204_NO_CONTENT
)
async def make_decision(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from starlette.responses import Response

from src.app.routers.tags import Tags
from src.app.utils.dependencies import get_latest_edition, require_auth, get_student, get_suggestion
from src.app.utils.dependencies import get_editable_edition, require_auth, get_student, get_suggestion
from src.app.utils.websockets import live
from src.database.database import get_session
from src.database.models import Student, User, Suggestion
Expand All @@ -22,7 +22,7 @@
"",
status_code=status.HTTP_201_CREATED,
response_model=SuggestionResponse,
dependencies=[Depends(live), Depends(get_latest_edition)]
dependencies=[Depends(live), Depends(get_editable_edition)]
)
async def create_suggestion(new_suggestion: NewSuggestion, student: Student = Depends(get_student),
db: AsyncSession = Depends(get_session), user: User = Depends(require_auth)):
Expand Down Expand Up @@ -51,7 +51,7 @@ async def delete_suggestion(db: AsyncSession = Depends(get_session), user: User
@students_suggestions_router.put(
"/{suggestion_id}",
status_code=status.HTTP_204_NO_CONTENT,
dependencies=[Depends(get_student), Depends(live), Depends(get_latest_edition)]
dependencies=[Depends(get_student), Depends(live), Depends(get_editable_edition)]
)
async def edit_suggestion(new_suggestion: NewSuggestion, db: AsyncSession = Depends(get_session),
user: User = Depends(require_auth), suggestion: Suggestion = Depends(get_suggestion)):
Expand Down
4 changes: 2 additions & 2 deletions backend/src/app/routers/editions/webhooks/webhooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from src.app.logic.webhooks import process_webhook
from src.app.routers.tags import Tags
from src.app.schemas.webhooks import WebhookEvent, WebhookUrlResponse
from src.app.utils.dependencies import get_edition, require_admin, get_latest_edition
from src.app.utils.dependencies import get_edition, require_admin, get_editable_edition
from src.database.crud.webhooks import get_webhook, create_webhook
from src.database.database import get_session
from src.database.models import Edition
Expand All @@ -20,7 +20,7 @@ async def valid_uuid(uuid: str, database: AsyncSession = Depends(get_session)):

@webhooks_router.post("", response_model=WebhookUrlResponse, status_code=status.HTTP_201_CREATED,
dependencies=[Depends(require_admin)])
async def new(edition: Edition = Depends(get_latest_edition), database: AsyncSession = Depends(get_session)):
async def new(edition: Edition = Depends(get_editable_edition), database: AsyncSession = Depends(get_session)):
"""Create a new webhook for an edition"""
return await create_webhook(database, edition)

Expand Down
4 changes: 3 additions & 1 deletion backend/src/app/routers/login/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from src.app.logic.security import authenticate_user_email, create_tokens, authenticate_user_github
from src.app.logic.users import get_user_editions
from src.app.routers.tags import Tags
from src.app.schemas.editions import Edition
from src.app.schemas.login import Token
from src.app.schemas.users import user_model_to_schema
from src.app.utils.dependencies import get_user_from_refresh_token, get_http_session
Expand Down Expand Up @@ -61,7 +62,8 @@ async def generate_token_response_for_user(db: AsyncSession, user: User) -> Toke
access_token, refresh_token = create_tokens(user)

user_data: dict = user_model_to_schema(user).__dict__
user_data["editions"] = await get_user_editions(db, user)
editions = await get_user_editions(db, user)
user_data["editions"] = list(map(Edition.from_orm, editions))

return Token(
access_token=access_token,
Expand Down
5 changes: 3 additions & 2 deletions backend/src/app/routers/users/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import src.app.logic.users as logic
from src.app.routers.tags import Tags
from src.app.schemas.editions import Edition
from src.app.schemas.login import UserData
from src.app.schemas.users import UsersListResponse, AdminPatch, UserRequestsResponse, user_model_to_schema, \
FilterParameters
Expand Down Expand Up @@ -32,8 +33,8 @@ async def get_users(
async def get_current_user(db: AsyncSession = Depends(get_session), user: UserDB = Depends(get_user_from_access_token)):
"""Get a user based on their authorization credentials"""
user_data = user_model_to_schema(user).__dict__
user_data["editions"] = await logic.get_user_editions(db, user)

editions = await logic.get_user_editions(db, user)
user_data["editions"] = list(map(Edition.from_orm, editions))
return user_data


Expand Down
8 changes: 8 additions & 0 deletions backend/src/app/schemas/editions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Edition(CamelCaseModel):
edition_id: int
name: str
year: int
readonly: bool

class Config:
"""Set to ORM mode"""
Expand All @@ -35,3 +36,10 @@ class EditionList(CamelCaseModel):
class Config:
"""Set to ORM mode"""
orm_mode = True


class EditEdition(CamelCaseModel):
"""Input schema to edit an edition
Only supported operation is patching the readonly status
"""
readonly: bool
3 changes: 2 additions & 1 deletion backend/src/app/schemas/login.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from src.app.schemas.editions import Edition
from src.app.schemas.users import User
from src.app.schemas.utils import BaseModel


class UserData(User):
"""User information that can be passed to frontend"""
editions: list[str] = []
editions: list[Edition] = []


class Token(BaseModel):
Expand Down
12 changes: 11 additions & 1 deletion backend/src/app/schemas/projects.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from dataclasses import dataclass

from pydantic import BaseModel
from pydantic import BaseModel, validator

from src.app.schemas.skills import Skill
from src.app.schemas.utils import CamelCaseModel
from src.app.schemas.validators import validate_url


class User(CamelCaseModel):
Expand Down Expand Up @@ -82,6 +83,7 @@ class Project(CamelCaseModel):
"""Represents a Project from the database to return when a GET request happens"""
project_id: int
name: str
info_url: str | None

coaches: list[User]
partners: list[Partner]
Expand All @@ -101,6 +103,7 @@ class ConflictProject(CamelCaseModel):
"""A project to be used in ConflictStudent"""
project_id: int
name: str
info_url: str | None

class Config:
"""Config Class"""
Expand Down Expand Up @@ -154,9 +157,16 @@ class InputProjectRole(BaseModel):
class InputProject(BaseModel):
"""Used for passing the details of a project when creating/patching a project"""
name: str
info_url: str | None
partners: list[str]
coaches: list[int]

@validator('info_url')
@classmethod
def is_url(cls, info_url: str | None):
"""Validate url"""
return validate_url(info_url)


class InputArgumentation(BaseModel):
"""Used for creating/patching a student role"""
Expand Down
Loading

0 comments on commit cc8247e

Please sign in to comment.