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 use_auth
Browse files Browse the repository at this point in the history
  • Loading branch information
stijndcl authored Mar 24, 2022
2 parents 5b05ba0 + 3b70fce commit 4a0b805
Show file tree
Hide file tree
Showing 66 changed files with 1,412 additions and 37 deletions.
17 changes: 0 additions & 17 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,4 @@ assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Additional context**
Add any other context about the problem here.
10 changes: 0 additions & 10 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,4 @@ assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
89 changes: 89 additions & 0 deletions backend/create_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""This script is used to create the very first admin in the database
The first admin's request can't be accepted by anyone, so they have to add
themselves into the database manually.
This script does it automatically to prevent the user from having to
fiddle in the database themselves.
"""
import argparse
import getpass
import sys
import traceback

import sqlalchemy.exc

from src.app.exceptions.validation_exception import ValidationException
from src.database.engine import DBSession
from src.database.crud.register import create_user, create_auth_email
from src.app.logic.security import get_password_hash
from src.app.schemas.validators import validate_email_format


def get_hashed_password() -> str:
"""Let the user input their password
This is safer than making it a command line argument, so the password
can't be found in the history anymore
Note: the password is NOT visible in their terminal,
"getpass()" doesn't display the characters that you enter
This is done twice to make sure they match, mirroring the
frontend asking for confirmation as well
"""
first_pass = getpass.getpass("Password: ")
second_pass = getpass.getpass("Confirm password: ")

# Passwords didn't match, show an error message and exit
if first_pass != second_pass:
print("Passwords did not match. Aborted.", file=sys.stderr)
exit(2)

return get_password_hash(first_pass)


def create_admin(name: str, email: str, pw: str):
"""Create a new user in the database"""
session = DBSession()
transaction = session.begin_nested()

try:
user = create_user(session, name, email)
user.admin = True
session.add(user)
session.commit()

# Add an email auth entry
create_auth_email(session, user, pw)
except sqlalchemy.exc.SQLAlchemyError as e:
# Something went wrong: rollback the transaction & print the error
transaction.rollback()

# Print the traceback of the exception
print(traceback.format_exc())
exit(3)


if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description="Add a new admin into the database.")
parser.add_argument("-N", "--name", type=str, required=True)
parser.add_argument("-E", "--email", type=str, required=True)

args = parser.parse_args()

# Check if email address was malformed
try:
validate_email_format(args.email)
except ValidationException:
print("Malformed email address. Aborted.", file=sys.stderr)
exit(1)

# Let user input their password
pw_hash = get_hashed_password()

# Create new database entry
create_admin(args.name, args.email, pw_hash)

print("Addition successful.")
16 changes: 15 additions & 1 deletion backend/src/app/logic/users.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from sqlalchemy.orm import Session

from src.app.schemas.users import UsersListResponse, AdminPatch
from src.app.schemas.users import UsersListResponse, AdminPatch, UserRequestsResponse
import src.database.crud.users as users_crud


Expand Down Expand Up @@ -48,6 +48,20 @@ def remove_coach(db: Session, user_id: int, edition_id: int):
users_crud.remove_coach(db, user_id, edition_id)


def get_request_list(db: Session, edition_id: int | None):
"""
Query the database for a list of all user requests
and wrap the result in a pydantic model
"""

if edition_id is None:
requests = users_crud.get_all_requests(db)
else:
requests = users_crud.get_all_requests_from_edition(db, edition_id)

return UserRequestsResponse(requests=requests)


def accept_request(db: Session, request_id: int):
"""
Accept user request
Expand Down
12 changes: 11 additions & 1 deletion backend/src/app/routers/users/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

from src.app.routers.tags import Tags
import src.app.logic.users as logic
from src.app.schemas.users import UsersListResponse, AdminPatch
from src.app.schemas.users import UsersListResponse, AdminPatch, UserRequestsResponse
from src.app.utils.dependencies import require_admin

from src.database.database import get_session

users_router = APIRouter(prefix="/users", tags=[Tags.USERS])
Expand Down Expand Up @@ -46,6 +47,15 @@ async def remove_from_edition(user_id: int, edition_id: int, db: Session = Depen
logic.remove_coach(db, user_id, edition_id)


@users_router.get("/requests", response_model=UserRequestsResponse)
async def get_requests(edition: int | None = Query(None), db: Session = Depends(get_session)):
"""
Get pending userrequests
"""

return logic.get_request_list(db, edition)


@users_router.post("/requests/{request_id}/accept", status_code=204, dependencies=[Depends(require_admin)])
async def accept_request(request_id: int, db: Session = Depends(get_session)):
"""
Expand Down
18 changes: 18 additions & 0 deletions backend/src/app/schemas/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,21 @@ class AdminPatch(CamelCaseModel):
"""Body of a patch to change the admin status of a user"""

admin: bool


class UserRequest(CamelCaseModel):
"""Model for a userrequest"""

request_id: int
edition_id: int
user: User

class Config:
orm_mode = True
allow_population_by_field_name = True


class UserRequestsResponse(CamelCaseModel):
"""Model for a list of userrequests"""

requests: list[UserRequest]
1 change: 1 addition & 0 deletions backend/src/database/crud/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from src.database.models import AuthEmail, CoachRequest, User, Edition


def create_user(db: Session, name: str, email: str) -> User:
"""Create a user"""
new_user: User = User(name=name, email=email)
Expand Down
16 changes: 16 additions & 0 deletions backend/src/database/crud/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ def delete_user_as_coach(db: Session, edition_id: int, user_id: int):
user.editions.remove(edition)


def get_all_requests(db: Session):
"""
Get all userrequests
"""

return db.query(CoachRequest).join(User).all()


def get_all_requests_from_edition(db: Session, edition_id: int):
"""
Get all userrequests from a given edition
"""

return db.query(CoachRequest).where(CoachRequest.edition_id == edition_id).join(User).all()


def accept_request(db: Session, request_id: int):
"""
Remove request and add user as coach
Expand Down
Loading

0 comments on commit 4a0b805

Please sign in to comment.