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 create_project_skills
Browse files Browse the repository at this point in the history
  • Loading branch information
Tiebe-Vercoutter committed May 20, 2022
2 parents f721bb3 + a22fcb7 commit 9a5d864
Show file tree
Hide file tree
Showing 127 changed files with 2,328 additions and 1,046 deletions.
9 changes: 8 additions & 1 deletion backend/src/app/exceptions/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .crud import DuplicateInsertException
from .editions import ReadOnlyEditionException
from .parsing import MalformedUUIDError
from .projects import StudentInConflictException, FailedToAddProjectRoleException
from .projects import StudentInConflictException, FailedToAddProjectRoleException, NoStrictlyPositiveNumberOfSlots
from .register import FailedToAddNewUserException, InvalidGitHubCode
from .students_email import FailedToAddNewEmailException
from .webhooks import WebhookProcessException
Expand Down Expand Up @@ -140,3 +140,10 @@ def failed_to_add_new_email_exception(_request: Request, _exception: FailedToAdd
status_code=status.HTTP_400_BAD_REQUEST,
content={'message': 'Something went wrong while creating a new email'}
)

@app.exception_handler(NoStrictlyPositiveNumberOfSlots)
def none_strict_postive_number_of_slots(_request: Request, _exception: NoStrictlyPositiveNumberOfSlots):
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={'message': 'The amount of slots per role has to be a strictly positive integer'}
)
4 changes: 4 additions & 0 deletions backend/src/app/exceptions/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ class FailedToAddProjectRoleException(Exception):
"""
Exception raised when a project_role can't be added for some reason
"""


class NoStrictlyPositiveNumberOfSlots(Exception):
"""Exception raised when roles aren't strictly positive"""
22 changes: 22 additions & 0 deletions backend/src/app/logic/answers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from src.database.models import Student
from src.app.schemas.answers import Questions, QuestionAndAnswer, File


async def gives_question_and_answers(student: Student) -> Questions:
"""transfers the student questions into a return model of Questions"""
# return Questions(questions=student.questions)
q_and_as: list[QuestionAndAnswer] = []
for question in student.questions:
answers: list[str] = []
for answer in question.answers:
if answer.answer:
answers.append(answer.answer)

files: list[File] = []
for file in question.files:
files.append(File(filename=file.file_name,
mime_type=file.mime_type, url=file.url))

q_and_as.append(QuestionAndAnswer(
question=question.question, answers=answers, files=files))
return Questions(q_and_a=q_and_as)
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
5 changes: 4 additions & 1 deletion backend/src/app/logic/invites.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ async def create_mailto_link(db: AsyncSession, edition: Edition, email_address:
# Create endpoint for the user to click on
link = f"{settings.FRONTEND_URL}/register/{encoded_link}"

with open('templates/invites.txt', 'r', encoding="utf-8") as file:
message = file.read().format(invite_link=link)

return NewInviteLink(mail_to=generate_mailto_string(
recipient=email_address.email, subject=f"Open Summer Of Code {edition.year} invitation",
body=link
body=message
), invite_link=link)
9 changes: 7 additions & 2 deletions backend/src/app/logic/projects.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.app.exceptions.projects import NoStrictlyPositiveNumberOfSlots
import src.app.logic.partners as partners_logic
import src.database.crud.projects as crud
from src.app.schemas.projects import (
Expand Down Expand Up @@ -67,13 +68,17 @@ async def get_project_roles(db: AsyncSession, project: Project) -> ProjectRoleRe

async def create_project_role(db: AsyncSession, project: Project, input_project_role: InputProjectRole) -> ProjectRole:
"""Create a project role"""
return await crud.create_project_role(db, project, input_project_role)
if input_project_role.slots > 0:
return await crud.create_project_role(db, project, input_project_role)
raise NoStrictlyPositiveNumberOfSlots


async def patch_project_role(db: AsyncSession, project_role_id: int, input_project_role: InputProjectRole) \
-> ProjectRole:
"""Update a project role"""
return await crud.patch_project_role(db, project_role_id, input_project_role)
if input_project_role.slots > 0:
return await crud.patch_project_role(db, project_role_id, input_project_role)
raise NoStrictlyPositiveNumberOfSlots


async def get_conflicts(db: AsyncSession, edition: Edition) -> ConflictStudentList:
Expand Down
51 changes: 29 additions & 22 deletions backend/src/app/logic/students.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,29 @@ async def remove_student(db: AsyncSession, student: Student) -> None:
await delete_student(db, student)


async def _get_student_with_suggestions(db: AsyncSession, student: Student) -> StudentModel:
nr_of_yes_suggestions = len(await get_suggestions_of_student_by_type(
db, student.student_id, DecisionEnum.YES))
nr_of_no_suggestions = len(await get_suggestions_of_student_by_type(
db, student.student_id, DecisionEnum.NO))
nr_of_maybe_suggestions = len(await get_suggestions_of_student_by_type(
db, student.student_id, DecisionEnum.MAYBE))
suggestions = SuggestionsModel(
yes=nr_of_yes_suggestions, no=nr_of_no_suggestions, maybe=nr_of_maybe_suggestions)
return StudentModel(student_id=student.student_id,
first_name=student.first_name,
last_name=student.last_name,
preferred_name=student.preferred_name,
email_address=student.email_address,
phone_number=student.phone_number,
alumni=student.alumni,
finalDecision=student.decision,
wants_to_be_student_coach=student.wants_to_be_student_coach,
edition_id=student.edition_id,
skills=student.skills,
nr_of_suggestions=suggestions)


async def get_students_search(db: AsyncSession, edition: Edition,
commons: CommonQueryParams, user: User) -> ReturnStudentList:
"""return all students"""
Expand All @@ -42,33 +65,17 @@ async def get_students_search(db: AsyncSession, edition: Edition,

students: list[StudentModel] = []
for student in students_orm:
students.append(StudentModel(
student_id=student.student_id,
first_name=student.first_name,
last_name=student.last_name,
preferred_name=student.preferred_name,
email_address=student.email_address,
phone_number=student.phone_number,
alumni=student.alumni,
finalDecision=student.decision,
wants_to_be_student_coach=student.wants_to_be_student_coach,
edition_id=student.edition_id,
skills=student.skills))
nr_of_yes_suggestions = len(await get_suggestions_of_student_by_type(
db, student.student_id, DecisionEnum.YES))
nr_of_no_suggestions = len(await get_suggestions_of_student_by_type(
db, student.student_id, DecisionEnum.NO))
nr_of_maybe_suggestions = len(await get_suggestions_of_student_by_type(
db, student.student_id, DecisionEnum.MAYBE))
students[-1].nr_of_suggestions = SuggestionsModel(
yes=nr_of_yes_suggestions, no=nr_of_no_suggestions, maybe=nr_of_maybe_suggestions)
student_model = await _get_student_with_suggestions(db, student)
students.append(student_model)
return ReturnStudentList(students=students)


def get_student_return(student: Student, edition: Edition) -> ReturnStudent:

async def get_student_return(db: AsyncSession, student: Student, edition: Edition) -> ReturnStudent:
"""return a student"""
if student.edition == edition:
return ReturnStudent(student=student)
student_model = await _get_student_with_suggestions(db, student)
return ReturnStudent(student=student_model)

raise NoResultFound

Expand Down
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
14 changes: 8 additions & 6 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,8 @@ 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)],
status_code=status.HTTP_201_CREATED
)
async def post_project_role(
input_project_role: InputProjectRole,
Expand All @@ -116,8 +117,9 @@ async def post_project_role(

@projects_router.patch(
"/{project_id}/roles/{project_role_id}",
status_code=status.HTTP_200_OK,
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 All @@ -136,4 +138,4 @@ async def delete_project_role(
project_role_id: int,
db: AsyncSession = Depends(get_session)):
"""Delete a project role"""
return await logic.delete_project_role(db, project_role_id)
await logic.delete_project_role(db, project_role_id)
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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .answers import students_answers_router
Loading

0 comments on commit 9a5d864

Please sign in to comment.