diff --git a/poetry.lock b/poetry.lock index 594513f..eccb2a9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -786,6 +786,14 @@ optional = false python-versions = "*" version = "5.3.1" +[[package]] +category = "main" +description = "PyZip is a package for handling zip-in-memory content as a dictionary." +name = "pyzip" +optional = false +python-versions = "*" +version = "0.2.0" + [[package]] category = "dev" description = "Alternative regular expression module, to replace re." @@ -1027,7 +1035,7 @@ python-versions = "*" version = "4.4.28" [metadata] -content-hash = "1f318bc4c8d62b545037d45083cc00373624eed3ded4f31ed9baf6b8570c9a4c" +content-hash = "79db42891299f61d4e4c8bb21f59f1ca196eee0eb5bb268779674c77d1b22ba5" lock-version = "1.1" python-versions = "^3.8" @@ -1510,6 +1518,9 @@ pyyaml = [ {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] +pyzip = [ + {file = "pyzip-0.2.0.tar.gz", hash = "sha256:c0b10776d798e4be9d5fe6eec541dd0a9740b6550b12fd4cfa238a085686a298"}, +] regex = [ {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, {file = "regex-2020.7.14-cp27-cp27m-win_amd64.whl", hash = "sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644"}, diff --git a/pyproject.toml b/pyproject.toml index fdcfe81..bbb72d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,7 @@ nanoid = "^2.0.0" python-slugify = "^4.0.1" fastapi_utils = "^0.2.1" fastapi-etag = "^0.2.2" +pyzip = "^0.2.0" [tool.poetry.dev-dependencies] black = "^19.10b0" diff --git a/schoolsyst_api/accounts/users.py b/schoolsyst_api/accounts/users.py index 19c2ba9..5ec116c 100644 --- a/schoolsyst_api/accounts/users.py +++ b/schoolsyst_api/accounts/users.py @@ -210,22 +210,3 @@ async def delete_current_user( db.collection(c).delete_match({"owner_key": user.key}) return Response(status_code=status.HTTP_204_NO_CONTENT) - - -@router.get("/personal_data_archive") -async def get_personal_data_archive( - user: User = Depends(get_current_confirmed_user), - db: StandardDatabase = Depends(database.get), -) -> dict: - """ - Get an archive of all of the data linked to the user. - """ - data = {} - # The user's data - data["user"] = db.collection("users").get(user.key) - # the data of which the user is the owner for every collection - for c in COLLECTIONS: - if c == "users": - continue - data[c] = [batch for batch in db.collection(c).find({"owner_key": user.key})] - return data diff --git a/schoolsyst_api/main.py b/schoolsyst_api/main.py index dcbd73d..55e4dbd 100644 --- a/schoolsyst_api/main.py +++ b/schoolsyst_api/main.py @@ -2,6 +2,7 @@ import schoolsyst_api.grades.routes import schoolsyst_api.homework.routes +import schoolsyst_api.personal_archive.routes import schoolsyst_api.schedule.routes import schoolsyst_api.settings.routes import schoolsyst_api.statistics.routes @@ -31,6 +32,7 @@ api.add_middleware(**cors.middleware_params) # Include routes api.include_router(accounts.router, tags=["Accounts"]) +api.include_router(schoolsyst_api.personal_archive.routes.router, tags=["Accounts"]) api.include_router(schoolsyst_api.subjects.routes.router, tags=["Subjects"]) api.include_router(schoolsyst_api.homework.routes.router, tags=["Homework"]) api.include_router(schoolsyst_api.settings.routes.router, tags=["Settings"]) diff --git a/schoolsyst_api/personal_archive/__init__.py b/schoolsyst_api/personal_archive/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/schoolsyst_api/personal_archive/models.py b/schoolsyst_api/personal_archive/models.py new file mode 100644 index 0000000..4d7c637 --- /dev/null +++ b/schoolsyst_api/personal_archive/models.py @@ -0,0 +1,23 @@ +from typing import List + +from schoolsyst_api.accounts.models import User +from schoolsyst_api.grades.models import Grade +from schoolsyst_api.homework.models import Homework +from schoolsyst_api.learn.models import Quiz +from schoolsyst_api.models import BaseModel +from schoolsyst_api.notes.models import Note +from schoolsyst_api.schedule.models import Event, EventMutation +from schoolsyst_api.settings.models import Settings +from schoolsyst_api.subjects.models import Subject + + +class PersonalArchive(BaseModel): + subjects: List[Subject] + users: List[User] + settings: List[Settings] + quizzes: List[Quiz] + notes: List[Note] + grades: List[Grade] + homework: List[Homework] + events: List[Event] + event_mutations: List[EventMutation] diff --git a/schoolsyst_api/personal_archive/routes.py b/schoolsyst_api/personal_archive/routes.py new file mode 100644 index 0000000..c84a107 --- /dev/null +++ b/schoolsyst_api/personal_archive/routes.py @@ -0,0 +1,47 @@ +from arango.database import StandardDatabase +from fastapi import Depends, Response, status +from fastapi_utils.inferring_router import InferringRouter +from pyzip import PyZip +from schoolsyst_api import database +from schoolsyst_api.accounts.models import User +from schoolsyst_api.accounts.users import get_current_confirmed_user +from schoolsyst_api.database import COLLECTIONS +from schoolsyst_api.personal_archive.models import PersonalArchive + +router = InferringRouter() + + +@router.get( + "/personal_data_archive", + status_code=status.HTTP_201_CREATED, + description=f"""\ +Get an archive of all the data owned by the user. +The response is a zip file containing a JSON response, which is +an object associating keys {', '.join(COLLECTIONS)} +to lists of the corresponding objects.""", +) +async def get_personal_data_archive( + filename: str = "schoolsyst_data_archive.zip", + user: User = Depends(get_current_confirmed_user), + db: StandardDatabase = Depends(database.get), +): + """ + Get an archive of all of the data linked to the user. + """ + data = {} + # The user's data + data["users"] = [db.collection("users").get(user.key)] + # the data of which the user is the owner for every collection + for c in COLLECTIONS: + if c == "users": + continue + data[c] = [batch for batch in db.collection(c).find({"owner_key": user.key})] + # zip the data + zip_file = PyZip() + zip_file["data.json"] = PersonalArchive(**data).json(by_alias=True).encode("utf-8") + return Response( + content=zip_file.to_bytes(), + status_code=status.HTTP_201_CREATED, + headers={"Content-Disposition": f"attachment; filename={filename}"}, + media_type="application/zip", + )