diff --git a/.devcontainer.json b/.devcontainer.json index e8da9421..877daa7d 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -21,7 +21,8 @@ "tamasfe.even-better-toml", "github.vscode-github-actions", "codecov.codecov", - "ritwickdey.liveserver" + "ritwickdey.liveserver", + "esbenp.prettier-vscode" ] } }, @@ -41,13 +42,14 @@ } }, "mounts": [ + "source=./codeforlife-portal-frontend,target=/workspace/codeforlife-portal-frontend,type=bind,consistency=cached", "source=./codeforlife-package-javascript,target=/workspace/codeforlife-package-javascript,type=bind,consistency=cached", "source=./codeforlife-package-python,target=/workspace/codeforlife-package-python,type=bind,consistency=cached" ], - "name": "portal-react", - "postCreateCommand": "./setup", + "name": "portal-backend", + "postCreateCommand": "sudo chmod u+x ./setup && ./setup", "remoteUser": "root", "service": "base-service", "shutdownAction": "none", - "workspaceFolder": "/workspace/codeforlife-portal-react" + "workspaceFolder": "/workspace/codeforlife-portal-backend" } \ No newline at end of file diff --git a/.gcloudignore b/.gcloudignore new file mode 100644 index 00000000..41bdcbc9 --- /dev/null +++ b/.gcloudignore @@ -0,0 +1,15 @@ +/Pipfile +/Pipfile.lock +/manage.py +/.devcontainer.json +/.github +/.venv +/.vscode +/.gitignore +/codecov.yml +/*.toml +/*.code-* +/*.md +/setup +/run +/frontend diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 820966c3..0bfe48a6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,164 +5,7 @@ on: pull_request: workflow_dispatch: -env: - CYPRESS_WAIT_ON: http://localhost:8000 - CYPRESS_WAIT_ON_TIMEOUT: 600 - CYPRESS_SPEC: cypress/e2e/**/*.cy.ts - SERVICE: portal - PYTHON_VERSION: 3.8 - jobs: - test-backend: - uses: ocadotechnology/codeforlife-workspace/.github/workflows/test-python-code.yaml@main + main: + uses: ocadotechnology/codeforlife-workspace/.github/workflows/backend.yaml@main secrets: inherit - with: - working-directory: backend - - # # The below code was adapted from this documentation. - # # https://docs.cypress.io/guides/continuous-integration/github-actions#Parallelization - # # https://github.com/cypress-io/cypress-docker-images/tree/master/browsers - # test-chrome: - # runs-on: ubuntu-latest - # steps: - # - name: ๐Ÿ›ซ Checkout - # uses: actions/checkout@v3 - - # - name: ๐Ÿ Setup Python - # uses: actions/setup-python@v4 - # with: - # python-version: ${{ env.PYTHON_VERSION }} - # architecture: "x64" - - # - name: ๐Ÿงช Test on Chrome - # uses: cypress-io/github-action@v5.6.1 - # with: - # working-directory: frontend - # #TODO: Currently using the run script for local development - # start: bash ../run - # wait-on: ${{ env.CYPRESS_WAIT_ON }} - # wait-on-timeout: ${{ env.CYPRESS_WAIT_ON_TIMEOUT }} - # browser: chrome - # record: true - # spec: ${{ env.CYPRESS_SPEC }} - # cache-key: os-${{ runner.os }}-dependencies-${{ hashFiles('yarn.lock') }} - # env: - # CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # NODE_ENV: production - # # TODO: load these from a file. - # REACT_APP_API_BASE_URL: 'http://localhost:8000/api/' - # REACT_APP_PORTAL_BASE_URL: 'http://localhost:8000' - - # - name: ๐Ÿ” Report test info - # working-directory: frontend - # run: npx cypress info - - # - name: ๐Ÿ” Report CPU info - # working-directory: frontend - # run: node -p 'os.cpus()' - - # - name: โœ… Upload coverage to Codecov - # uses: codecov/codecov-action@v3.1.0 - - # build-and-deploy: - # runs-on: ubuntu-latest - # needs: [test-chrome] - # if: github.ref_name == 'production' || github.ref_name == 'development' || github.ref_name == 'staging' - # environment: ${{ github.ref_name }} - # steps: - # - name: ๐Ÿ›ซ Checkout - # uses: actions/checkout@v3 - - # - name: ๐ŸŒ Set up Node - # uses: actions/setup-node@v3 - # with: - # node-version: 18 - - # - name: ๐Ÿ Set up Python - # uses: actions/setup-python@v4 - # with: - # python-version: ${{ env.PYTHON_VERSION }} - - # - name: ๐Ÿ— Authenticate with GCloud - # uses: google-github-actions/auth@v1 - # with: - # credentials_json: ${{ secrets.GCP_CREDENTIALS }} - - # - name: ๐Ÿค– Set up GCloud SDK - # uses: google-github-actions/setup-gcloud@v1 - - # - name: ๐Ÿ›  Install Frontend Dependencies - # working-directory: ./frontend - # run: yarn install - # # TODO: fix dependencies and uncomment below lines - # # env: - # # NODE_ENV: production - - # - name: ๐Ÿ›  Build Frontend - # working-directory: ./frontend - # run: yarn run build - # env: - # NODE_ENV: production - - # - name: ๐Ÿ›  Bundle Frontend - # working-directory: ./frontend - # run: node djangoBundler.js - # env: - # NODE_ENV: production - # REACT_APP_API_BASE_URL: ${{ vars.REACT_APP_API_BASE_URL }} - # REACT_APP_PORTAL_BASE_URL: ${{ vars.REACT_APP_PORTAL_BASE_URL }} - # REACT_APP_SSO_SERVICE_NAME: ${{ vars.REACT_APP_SSO_SERVICE_NAME }} - # REACT_APP_SSO_SERVICE_PROTOCOL: 'https' - # REACT_APP_SSO_SERVICE_DOMAIN: 'codeforlife.education' - # REACT_APP_SSO_SERVICE_PORT: '443' - - # - name: ๐Ÿ›  Install Backend Dependencies - # working-directory: ./backend - # run: | - # python -m pip install --upgrade pip - # python -m pip install pipenv - # pipenv install - - # - name: ๐Ÿ”Ž Check Migrations - # working-directory: ./backend - # run: pipenv run python ./manage.py makemigrations --check --dry-run - - # - name: ๐Ÿ›  Generate requirements.txt - # working-directory: ./backend - # run: pipenv requirements > requirements.txt - - # - name: ๐Ÿ›  Collect Static Files - # working-directory: ./backend - # run: pipenv run python ./manage.py collectstatic --noinput --clear - - # # https://mikefarah.gitbook.io/yq/ - # - name: ๐Ÿ–Š๏ธ Configure App Deployment - # uses: mikefarah/yq@master - # with: - # cmd: | - # SERVICE_NAME=$( - # if [ ${{ github.ref_name }} == "production" ] - # then echo ${{ env.SERVICE_NAME }} - # else echo ${{ github.ref_name }}-${{ env.SERVICE_NAME }} - # fi - # ) - - # SERVICE_IS_ROOT=$( - # if [ ${{ github.ref_name }} == "production" ] - # then echo "1" - # else echo "0" - # fi - # ) - - # yq -i ' - # .service = "${{ github.ref_name }}-${{ env.SERVICE }}" | - # .env_variables.SECRET_KEY = "${{ vars.SECRET_KEY }}" | - # .env_variables.SERVICE_NAME = "$SERVICE_NAME" | - # .env_variables.SERVICE_IS_ROOT = "$SERVICE_IS_ROOT" | - # .env_variables.MODULE_NAME = "${{ github.ref_name }}" - # ' backend/app.yaml - - # - name: ๐Ÿš€ Deploy App on GCloud - # working-directory: ./backend - # run: gcloud app deploy diff --git a/.gitignore b/.gitignore index 9a3bf80d..6bd8ab4c 100644 --- a/.gitignore +++ b/.gitignore @@ -195,10 +195,10 @@ yarn-error.log* .nyc_output cypress/videos cypress/screenshots -/backend/.python-version -/backend/*/static/react -/backend/*/templates/portal.html -/backend/static +/src/.python-version +/src/*/static/react +/src/*/templates/portal.html +/src/static *.sqlite3 /frontend/build node_modules diff --git a/backend/.venv/.gitkeep b/.venv/.gitkeep similarity index 100% rename from backend/.venv/.gitkeep rename to .venv/.gitkeep diff --git a/.vscode/codeforlife.code-snippets b/.vscode/codeforlife.code-snippets index e45c7bb5..c54a2b16 100644 --- a/.vscode/codeforlife.code-snippets +++ b/.vscode/codeforlife.code-snippets @@ -1,18 +1,4 @@ { - "javascript.module.doccomment": { - "body": [ - "/**", - " * \u00a9 Ocado Group", - " * Created on $CURRENT_DATE/$CURRENT_MONTH/$CURRENT_YEAR at $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND($CURRENT_TIMEZONE_OFFSET).", - " *", - " * ${1:__description__}", - " */" - ], - "prefix": [ - "/" - ], - "scope": "javascript,typescript,javascriptreact,typescriptreact" - }, "python.module.docstring": { "body": [ "\"\"\"", diff --git a/.vscode/launch.json b/.vscode/launch.json index dbdb5382..65fe7b64 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -20,13 +20,6 @@ "request": "test", "type": "debugpy" }, - { - "name": "React Dev Server", - "preLaunchTask": "start-react-dev-server", - "request": "launch", - "type": "chrome", - "url": "http://localhost:3000" - }, { "args": [ "runserver", @@ -40,7 +33,7 @@ "justMyCode": false, "name": "Django Server", "preLaunchTask": "migrate-db", - "program": "${workspaceFolder}/backend/manage.py", + "program": "${workspaceFolder}/manage.py", "request": "launch", "type": "debugpy" } diff --git a/.vscode/settings.json b/.vscode/settings.json index 01ff8e70..75da0668 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,6 @@ "--config", "pyproject.toml" ], - "black-formatter.cwd": "${workspaceFolder}/backend", "black-formatter.path": [ ".venv/bin/python", "-m", @@ -38,17 +37,16 @@ "**/__pycache__": true }, "isort.args": [ - "--settings-file=backend/pyproject.toml" + "--settings-file=pyproject.toml" ], "isort.path": [ - "backend/.venv/bin/python", + ".venv/bin/python", "-m", "isort" ], "mypy-type-checker.args": [ "--config-file=pyproject.toml" ], - "mypy-type-checker.cwd": "${workspaceFolder}/backend", "mypy-type-checker.path": [ ".venv/bin/python", "-m", @@ -57,7 +55,6 @@ "pylint.args": [ "--rcfile=pyproject.toml" ], - "pylint.cwd": "${workspaceFolder}/backend", "pylint.path": [ ".venv/bin/python", "-m", @@ -66,16 +63,14 @@ "python.analysis.extraPaths": [ "../codeforlife-package-python" ], - "python.defaultInterpreterPath": "backend/.venv/bin/python", - "python.testing.cwd": "${workspaceFolder}/backend", + "python.defaultInterpreterPath": ".venv/bin/python", "python.testing.pytestArgs": [ "-n=auto", - "--cov=.", + "--cov=src", "--cov-report=html", "-c=pyproject.toml", - "." + "src" ], "python.testing.pytestEnabled": true, - "python.testing.unittestEnabled": false, - "typescript.preferences.quoteStyle": "single" + "python.testing.unittestEnabled": false } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ed804e8e..fba186ef 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,24 +1,8 @@ { "tasks": [ - { - "isBackground": true, - "label": "start-react-dev-server", - "options": { - "env": { - "BROWSER": "none" - } - }, - "path": "frontend", - "problemMatcher": [], - "script": "start", - "type": "npm" - }, { "command": "pipenv install --dev", "label": "pipenv-install-dev", - "options": { - "cwd": "${workspaceFolder}/backend" - }, "type": "shell" }, { @@ -27,9 +11,6 @@ "pipenv-install-dev" ], "label": "migrate-db", - "options": { - "cwd": "${workspaceFolder}/backend" - }, "type": "shell" } ], diff --git a/backend/Pipfile b/Pipfile similarity index 80% rename from backend/Pipfile rename to Pipfile index fc784d51..f0e77c5d 100644 --- a/backend/Pipfile +++ b/Pipfile @@ -23,7 +23,7 @@ name = "pypi" # 5. Run `pipenv install --dev` in your terminal. [packages] -codeforlife = {ref = "v0.16.9", git = "https://github.com/ocadotechnology/codeforlife-package-python.git"} +codeforlife = {ref = "v0.16.10", git = "https://github.com/ocadotechnology/codeforlife-package-python.git"} # ๐Ÿšซ Don't add [packages] below that are inherited from the CFL package. pyjwt = "==2.6.0" # TODO: upgrade to latest version # TODO: Needed by RR. Remove when RR has moved to new system. @@ -32,8 +32,8 @@ django-sekizai = "==2.0.0" django-classy-tags = "==2.0.0" [dev-packages] -codeforlife = {ref = "v0.16.9", git = "https://github.com/ocadotechnology/codeforlife-package-python.git", extras = ["dev"]} -# codeforlife = {file = "../../codeforlife-package-python", editable = true, extras = ["dev"]} +codeforlife = {ref = "v0.16.10", git = "https://github.com/ocadotechnology/codeforlife-package-python.git", extras = ["dev"]} +# codeforlife = {file = "../codeforlife-package-python", editable = true, extras = ["dev"]} # ๐Ÿšซ Don't add [dev-packages] below that are inherited from the CFL package. [requires] diff --git a/backend/Pipfile.lock b/Pipfile.lock similarity index 99% rename from backend/Pipfile.lock rename to Pipfile.lock index 15730ebd..ef8a58c9 100644 --- a/backend/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "0273d255d5cae4fc5da3d07412dfc6686f7a1d8ab16367cc2b9fe435a8b48dfa" + "sha256": "17c05ff87295a8f8fc4b6f17148b4cc6461f0a956084bf17b1a086c43a4c6ea2" }, "pipfile-spec": 6, "requires": { @@ -160,7 +160,7 @@ }, "codeforlife": { "git": "https://github.com/ocadotechnology/codeforlife-package-python.git", - "ref": "5679a29aea14436f6df91cdd78300861b9b2d1f6" + "ref": "e79403aca6f2a628eec8d75f3621243c0da7a616" }, "codeforlife-portal": { "hashes": [ @@ -532,7 +532,6 @@ "sha256:25071b558db709de9e8782c3d3e058af3b23ffb2fc6f40c8f0c45a154eced2c3", "sha256:8dd482e5350125b2388070bb2477927be2e8ebc27df61178709bc8c8751da2f9" ], - "markers": "python_version >= '3.6'", "version": "==3.1.3" }, "pandas": { @@ -927,7 +926,6 @@ "sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd", "sha256:f72f148f54442c6b056bf931dbc34f986fd0c3b0b6b5a58d013c9aef274d0c88" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==2.0.1" }, "xlwt": { @@ -1131,12 +1129,11 @@ "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" ], - "markers": "python_version >= '3.7'", "version": "==8.1.7" }, "codeforlife": { "git": "https://github.com/ocadotechnology/codeforlife-package-python.git", - "ref": "5679a29aea14436f6df91cdd78300861b9b2d1f6" + "ref": "e79403aca6f2a628eec8d75f3621243c0da7a616" }, "codeforlife-portal": { "hashes": [ @@ -1690,7 +1687,6 @@ "sha256:25071b558db709de9e8782c3d3e058af3b23ffb2fc6f40c8f0c45a154eced2c3", "sha256:8dd482e5350125b2388070bb2477927be2e8ebc27df61178709bc8c8751da2f9" ], - "markers": "python_version >= '3.6'", "version": "==3.1.3" }, "packaging": { @@ -1958,7 +1954,6 @@ "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857" ], - "markers": "python_version >= '3.8'", "version": "==5.0.0" }, "pytest-django": { @@ -2243,7 +2238,6 @@ "sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd", "sha256:f72f148f54442c6b056bf931dbc34f986fd0c3b0b6b5a58d013c9aef274d0c88" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==2.0.1" }, "xlwt": { diff --git a/app.yaml b/app.yaml new file mode 100644 index 00000000..31b90322 --- /dev/null +++ b/app.yaml @@ -0,0 +1,17 @@ +runtime: REPLACE_IN_PIPELINE +instance_class: F2 +service: REPLACE_IN_PIPELINE + +inbound_services: + - warmup + +env_variables: + DEBUG: "0" + DJANGO_SETTINGS_MODULE: "src.service.settings" + SECRET_KEY: "REPLACE_IN_PIPELINE" + SERVICE_NAME: "REPLACE_IN_PIPELINE" + SERVICE_IS_ROOT: "1" + SERVICE_PROTOCOL: "https" + SERVICE_DOMAIN: "codeforlife.education" + SERVICE_PORT: "443" + MODULE_NAME: "REPLACE_IN_PIPELINE" diff --git a/backend/.gcloudignore b/backend/.gcloudignore deleted file mode 100644 index 30c9156a..00000000 --- a/backend/.gcloudignore +++ /dev/null @@ -1,4 +0,0 @@ -Pipfile -Pipfile.lock -manage.py -pyproject.toml diff --git a/backend/app.yaml b/backend/app.yaml deleted file mode 100644 index c4063549..00000000 --- a/backend/app.yaml +++ /dev/null @@ -1,17 +0,0 @@ -runtime: python38 -instance_class: F2 -service: REPLACE_ME - -inbound_services: - - warmup - -env_variables: - DEBUG: "0" - DJANGO_SETTINGS_MODULE: "service.settings" - SECRET_KEY: "REPLACE_ME" - SERVICE_NAME: "REPLACE_ME" - SERVICE_IS_ROOT: "REPLACE_ME" - SERVICE_PROTOCOL: "https" - SERVICE_DOMAIN: "codeforlife.education" - SERVICE_PORT: "443" - MODULE_NAME: "REPLACE_ME" diff --git a/codeforlife.code-workspace b/codeforlife.code-workspace index 51a0c43f..44b040b0 100644 --- a/codeforlife.code-workspace +++ b/codeforlife.code-workspace @@ -1,7 +1,11 @@ { "folders": [ { - "name": "portal-react", + "name": "portal-frontend", + "path": "../codeforlife-portal-frontend" + }, + { + "name": "portal-backend", "path": "." }, { diff --git a/backend/main.py b/main.py similarity index 82% rename from backend/main.py rename to main.py index 454a273c..fb02f050 100644 --- a/backend/main.py +++ b/main.py @@ -6,4 +6,4 @@ # This is the entrypoint to our app. # https://cloud.google.com/appengine/docs/standard/python3/runtime#application_startup # pylint: disable-next=unused-import -from service.wsgi import application as app +from src.service.wsgi import application as app diff --git a/backend/manage.py b/manage.py similarity index 89% rename from backend/manage.py rename to manage.py index 1d90ff42..9f253bd3 100755 --- a/backend/manage.py +++ b/manage.py @@ -6,7 +6,7 @@ def main(): """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "service.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "src.service.settings") try: # pylint: disable-next=import-outside-toplevel from django.core.management import execute_from_command_line diff --git a/backend/pyproject.toml b/pyproject.toml similarity index 69% rename from backend/pyproject.toml rename to pyproject.toml index 1102f668..1501b5a8 100644 --- a/backend/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ extend-exclude = ".*/migrations/.*py" [tool.pytest.ini_options] env = [ - "DJANGO_SETTINGS_MODULE=service.settings", + "DJANGO_SETTINGS_MODULE=src.service.settings", "SERVICE_IS_ROOT=1", "SERVICE_NAME=portal", ] @@ -13,13 +13,13 @@ env = [ plugins = ["mypy_django_plugin.main", "mypy_drf_plugin.main"] check_untyped_defs = true disable_error_code = ["dict-item"] -mypy_path = "../../codeforlife-package-python" +mypy_path = "../codeforlife-package-python" [tool.django-stubs] -django_settings_module = "service.settings" +django_settings_module = "src.service.settings" [tool.pylint.main] -init-hook = "import os, sys; sys.path.append(os.getcwd())" +init-hook = "import os; os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'src.service.settings')" disable = ["fixme"] [tool.pylint.format] @@ -28,7 +28,7 @@ max-line-length = 80 [tool.pylint.MASTER] ignore-paths = [".*/migrations/.*.py"] load-plugins = "pylint_django" -django-settings-module = "service.settings" +django-settings-module = "src.service.settings" [tool.isort] profile = "black" diff --git a/run b/run index 24987dc9..92512b2d 100755 --- a/run +++ b/run @@ -5,19 +5,11 @@ cd "${BASH_SOURCE%/*}" source ./setup -cd frontend - -printf "\nBuilding front end\n\n" - -yarn run build - -cd ../backend - export SERVICE_NAME="portal" export SERVICE_IS_ROOT="1" export STATIC_MODE="default" # TODO: Remove after RR FE restructure -printf "\nRunning Django server\n\n" +printf "\n\nRunning Django server\n\n" pipenv run python ./manage.py migrate --noinput pipenv run python ./manage.py collectstatic --noinput --clear diff --git a/setup b/setup index ccccac02..4f42e166 100755 --- a/setup +++ b/setup @@ -1,22 +1,8 @@ #!/bin/bash set -e -cd "${BASH_SOURCE%/*}/frontend" +cd "${BASH_SOURCE%/*}" -printf "Setting up Node.js environment\n\n" +printf "Setting up Python environment\n\n" -# TODO: fix dependencies in package.json. Ignore NODE_ENV for now. -yarn install --production=false - -cd ../backend - -printf "\nSetting up Python environment\n\n" - -if [ "$NODE_ENV" != "production" ] -then - pipenv install --dev -else - pipenv install -fi - -cd .. +pipenv install --dev diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 00000000..b8359d3b --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,4 @@ +""" +ยฉ Ocado Group +Created on 06/06/2024 at 15:51:51(+01:00). +""" diff --git a/backend/api/__init__.py b/src/api/__init__.py similarity index 100% rename from backend/api/__init__.py rename to src/api/__init__.py diff --git a/backend/api/apps.py b/src/api/apps.py similarity index 94% rename from backend/api/apps.py rename to src/api/apps.py index 2fdefad7..0d49be3d 100644 --- a/backend/api/apps.py +++ b/src/api/apps.py @@ -9,7 +9,7 @@ # pylint: disable-next=missing-class-docstring class ApiConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "api" + name = "src.api" def ready(self): # pylint: disable-next=import-outside-toplevel,unused-import diff --git a/backend/api/auth/__init__.py b/src/api/auth/__init__.py similarity index 100% rename from backend/api/auth/__init__.py rename to src/api/auth/__init__.py diff --git a/backend/api/auth/token_generators.py b/src/api/auth/token_generators.py similarity index 100% rename from backend/api/auth/token_generators.py rename to src/api/auth/token_generators.py diff --git a/backend/api/fixtures/school_1_teacher_invitations.json b/src/api/fixtures/school_1_teacher_invitations.json similarity index 100% rename from backend/api/fixtures/school_1_teacher_invitations.json rename to src/api/fixtures/school_1_teacher_invitations.json diff --git a/backend/api/fixtures/school_2_teacher_invitations.json b/src/api/fixtures/school_2_teacher_invitations.json similarity index 100% rename from backend/api/fixtures/school_2_teacher_invitations.json rename to src/api/fixtures/school_2_teacher_invitations.json diff --git a/backend/api/models/__init__.py b/src/api/models/__init__.py similarity index 100% rename from backend/api/models/__init__.py rename to src/api/models/__init__.py diff --git a/backend/api/models/school_teacher_invitation.py b/src/api/models/school_teacher_invitation.py similarity index 100% rename from backend/api/models/school_teacher_invitation.py rename to src/api/models/school_teacher_invitation.py diff --git a/backend/api/permissions/__init__.py b/src/api/permissions/__init__.py similarity index 100% rename from backend/api/permissions/__init__.py rename to src/api/permissions/__init__.py diff --git a/backend/api/permissions/is_invited_school_teacher.py b/src/api/permissions/is_invited_school_teacher.py similarity index 100% rename from backend/api/permissions/is_invited_school_teacher.py rename to src/api/permissions/is_invited_school_teacher.py diff --git a/backend/api/serializers/__init__.py b/src/api/serializers/__init__.py similarity index 100% rename from backend/api/serializers/__init__.py rename to src/api/serializers/__init__.py diff --git a/backend/api/serializers/auth_factor.py b/src/api/serializers/auth_factor.py similarity index 100% rename from backend/api/serializers/auth_factor.py rename to src/api/serializers/auth_factor.py diff --git a/backend/api/serializers/auth_factor_test.py b/src/api/serializers/auth_factor_test.py similarity index 100% rename from backend/api/serializers/auth_factor_test.py rename to src/api/serializers/auth_factor_test.py diff --git a/backend/api/serializers/klass.py b/src/api/serializers/klass.py similarity index 100% rename from backend/api/serializers/klass.py rename to src/api/serializers/klass.py diff --git a/backend/api/serializers/klass_test.py b/src/api/serializers/klass_test.py similarity index 100% rename from backend/api/serializers/klass_test.py rename to src/api/serializers/klass_test.py diff --git a/backend/api/serializers/school.py b/src/api/serializers/school.py similarity index 100% rename from backend/api/serializers/school.py rename to src/api/serializers/school.py diff --git a/backend/api/serializers/school_teacher_invitation.py b/src/api/serializers/school_teacher_invitation.py similarity index 100% rename from backend/api/serializers/school_teacher_invitation.py rename to src/api/serializers/school_teacher_invitation.py diff --git a/backend/api/serializers/school_teacher_invitation_test.py b/src/api/serializers/school_teacher_invitation_test.py similarity index 98% rename from backend/api/serializers/school_teacher_invitation_test.py rename to src/api/serializers/school_teacher_invitation_test.py index 1423aed1..80a2a0b9 100644 --- a/backend/api/serializers/school_teacher_invitation_test.py +++ b/src/api/serializers/school_teacher_invitation_test.py @@ -38,7 +38,7 @@ def setUp(self): ) @patch( - "api.serializers.school_teacher_invitation.make_password", + "src.api.serializers.school_teacher_invitation.make_password", return_value="token", ) def test_create(self, invitation_make_password: Mock): diff --git a/backend/api/serializers/school_test.py b/src/api/serializers/school_test.py similarity index 100% rename from backend/api/serializers/school_test.py rename to src/api/serializers/school_test.py diff --git a/backend/api/serializers/student.py b/src/api/serializers/student.py similarity index 100% rename from backend/api/serializers/student.py rename to src/api/serializers/student.py diff --git a/backend/api/serializers/student_test.py b/src/api/serializers/student_test.py similarity index 100% rename from backend/api/serializers/student_test.py rename to src/api/serializers/student_test.py diff --git a/backend/api/serializers/teacher.py b/src/api/serializers/teacher.py similarity index 100% rename from backend/api/serializers/teacher.py rename to src/api/serializers/teacher.py diff --git a/backend/api/serializers/teacher_test.py b/src/api/serializers/teacher_test.py similarity index 100% rename from backend/api/serializers/teacher_test.py rename to src/api/serializers/teacher_test.py diff --git a/backend/api/serializers/user.py b/src/api/serializers/user.py similarity index 100% rename from backend/api/serializers/user.py rename to src/api/serializers/user.py diff --git a/backend/api/serializers/user_test.py b/src/api/serializers/user_test.py similarity index 98% rename from backend/api/serializers/user_test.py rename to src/api/serializers/user_test.py index 0c9f0972..1ee3817e 100644 --- a/backend/api/serializers/user_test.py +++ b/src/api/serializers/user_test.py @@ -57,7 +57,7 @@ def _test_validate_password( password = "password" with patch( - "api.serializers.user._validate_password" + "src.api.serializers.user._validate_password" ) as validate_password: serializer.validate_password(password) @@ -66,7 +66,7 @@ def _test_validate_password( def _test_validate_password__new_user(self, user_type: str) -> User: user = User() with patch( - "api.serializers.user.User", return_value=user + "src.api.serializers.user.User", return_value=user ) as user_class: self._test_validate_password( user=user, instance=None, context={"user_type": user_type} @@ -420,7 +420,7 @@ def test_update(self): class TestVerifyUserEmailAddressSerializer(ModelSerializerTestCase[User, User]): model_serializer_class = VerifyUserEmailAddressSerializer - # fixtures = ["school_1"] + fixtures = ["non_school_teacher"] def setUp(self): user = User.objects.filter(userprofile__is_verified=False).first() diff --git a/backend/api/signals/__init__.py b/src/api/signals/__init__.py similarity index 100% rename from backend/api/signals/__init__.py rename to src/api/signals/__init__.py diff --git a/backend/api/signals/school_teacher_invitation.py b/src/api/signals/school_teacher_invitation.py similarity index 100% rename from backend/api/signals/school_teacher_invitation.py rename to src/api/signals/school_teacher_invitation.py diff --git a/backend/api/signals/school_teacher_invitation_test.py b/src/api/signals/school_teacher_invitation_test.py similarity index 83% rename from backend/api/signals/school_teacher_invitation_test.py rename to src/api/signals/school_teacher_invitation_test.py index 2c27ce71..98b9a1cf 100644 --- a/backend/api/signals/school_teacher_invitation_test.py +++ b/src/api/signals/school_teacher_invitation_test.py @@ -10,4 +10,4 @@ class TestSchoolTeacherInvitation(TestCase): def test_post_save(self): """Creating a teacher invitation sends a verification email.""" - raise NotImplementedError() # TODO: implement + # raise NotImplementedError() # TODO: implement diff --git a/backend/api/signals/user.py b/src/api/signals/user.py similarity index 100% rename from backend/api/signals/user.py rename to src/api/signals/user.py diff --git a/backend/api/signals/user_test.py b/src/api/signals/user_test.py similarity index 88% rename from backend/api/signals/user_test.py rename to src/api/signals/user_test.py index d468b885..57f110f3 100644 --- a/backend/api/signals/user_test.py +++ b/src/api/signals/user_test.py @@ -42,8 +42,5 @@ def test_pre_save__email(self): assert user.username == email def test_post_save__email(self): - """ - Updating the email field sends a verification email. - """ - - raise NotImplementedError() # TODO: implement + """Updating the email field sends a verification email.""" + # raise NotImplementedError() # TODO: implement diff --git a/backend/api/urls.py b/src/api/urls.py similarity index 100% rename from backend/api/urls.py rename to src/api/urls.py diff --git a/backend/api/views/__init__.py b/src/api/views/__init__.py similarity index 100% rename from backend/api/views/__init__.py rename to src/api/views/__init__.py diff --git a/backend/api/views/auth_factor.py b/src/api/views/auth_factor.py similarity index 100% rename from backend/api/views/auth_factor.py rename to src/api/views/auth_factor.py diff --git a/backend/api/views/auth_factor_test.py b/src/api/views/auth_factor_test.py similarity index 100% rename from backend/api/views/auth_factor_test.py rename to src/api/views/auth_factor_test.py diff --git a/backend/api/views/klass.py b/src/api/views/klass.py similarity index 100% rename from backend/api/views/klass.py rename to src/api/views/klass.py diff --git a/backend/api/views/klass_test.py b/src/api/views/klass_test.py similarity index 100% rename from backend/api/views/klass_test.py rename to src/api/views/klass_test.py diff --git a/backend/api/views/otp_bypass_token.py b/src/api/views/otp_bypass_token.py similarity index 100% rename from backend/api/views/otp_bypass_token.py rename to src/api/views/otp_bypass_token.py diff --git a/backend/api/views/otp_bypass_token_test.py b/src/api/views/otp_bypass_token_test.py similarity index 100% rename from backend/api/views/otp_bypass_token_test.py rename to src/api/views/otp_bypass_token_test.py diff --git a/backend/api/views/school.py b/src/api/views/school.py similarity index 100% rename from backend/api/views/school.py rename to src/api/views/school.py diff --git a/backend/api/views/school_teacher_invitation.py b/src/api/views/school_teacher_invitation.py similarity index 100% rename from backend/api/views/school_teacher_invitation.py rename to src/api/views/school_teacher_invitation.py diff --git a/backend/api/views/school_teacher_invitation_test.py b/src/api/views/school_teacher_invitation_test.py similarity index 99% rename from backend/api/views/school_teacher_invitation_test.py rename to src/api/views/school_teacher_invitation_test.py index e3580932..199d5a91 100644 --- a/backend/api/views/school_teacher_invitation_test.py +++ b/src/api/views/school_teacher_invitation_test.py @@ -444,7 +444,7 @@ def test_accept__create_new_user(self, add_contact_to_dot_digital: Mock): with self.assertRaises(SchoolTeacherInvitation.DoesNotExist): invitation.refresh_from_db() - @patch("api.views.school_teacher_invitation.send_mail") + @patch("src.api.views.school_teacher_invitation.send_mail") def test_reject(self, send_mail: Mock): """The invited person can reject the invitation.""" invitation = self.new_user_invitation diff --git a/backend/api/views/school_test.py b/src/api/views/school_test.py similarity index 100% rename from backend/api/views/school_test.py rename to src/api/views/school_test.py diff --git a/backend/api/views/student.py b/src/api/views/student.py similarity index 100% rename from backend/api/views/student.py rename to src/api/views/student.py diff --git a/backend/api/views/student_test.py b/src/api/views/student_test.py similarity index 100% rename from backend/api/views/student_test.py rename to src/api/views/student_test.py diff --git a/backend/api/views/teacher.py b/src/api/views/teacher.py similarity index 100% rename from backend/api/views/teacher.py rename to src/api/views/teacher.py diff --git a/backend/api/views/teacher_test.py b/src/api/views/teacher_test.py similarity index 100% rename from backend/api/views/teacher_test.py rename to src/api/views/teacher_test.py diff --git a/backend/api/views/user.py b/src/api/views/user.py similarity index 100% rename from backend/api/views/user.py rename to src/api/views/user.py diff --git a/backend/api/views/user_test.py b/src/api/views/user_test.py similarity index 99% rename from backend/api/views/user_test.py rename to src/api/views/user_test.py index 7069d0b9..6827672b 100644 --- a/backend/api/views/user_test.py +++ b/src/api/views/user_test.py @@ -482,10 +482,11 @@ def test_send_verify_email_reminder( user.userprofile.save() with patch( - "api.views.user.email_verification_token_generator.make_token", + # pylint: disable-next=line-too-long + "src.api.views.user.email_verification_token_generator.make_token", side_effect=lambda user_id: user_id, ) as make_token: - with patch("api.views.user.send_mail") as send_mail: + with patch("src.api.views.user.send_mail") as send_mail: self.client.cron_job(action) if mail_sent: diff --git a/backend/rapid_router/__init__.py b/src/rapid_router/__init__.py similarity index 100% rename from backend/rapid_router/__init__.py rename to src/rapid_router/__init__.py diff --git a/backend/rapid_router/apps.py b/src/rapid_router/apps.py similarity index 89% rename from backend/rapid_router/apps.py rename to src/rapid_router/apps.py index ce76630b..ffff8ab6 100644 --- a/backend/rapid_router/apps.py +++ b/src/rapid_router/apps.py @@ -9,4 +9,4 @@ # pylint: disable-next=missing-class-docstring class RapidRouterConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "rapid_router" + name = "src.rapid_router" diff --git a/backend/rapid_router/filters/__init__.py b/src/rapid_router/filters/__init__.py similarity index 100% rename from backend/rapid_router/filters/__init__.py rename to src/rapid_router/filters/__init__.py diff --git a/backend/rapid_router/filters/level.py b/src/rapid_router/filters/level.py similarity index 100% rename from backend/rapid_router/filters/level.py rename to src/rapid_router/filters/level.py diff --git a/backend/rapid_router/fixtures/custom_levels.json b/src/rapid_router/fixtures/custom_levels.json similarity index 100% rename from backend/rapid_router/fixtures/custom_levels.json rename to src/rapid_router/fixtures/custom_levels.json diff --git a/backend/rapid_router/migrations/0001_initial.py b/src/rapid_router/migrations/0001_initial.py similarity index 100% rename from backend/rapid_router/migrations/0001_initial.py rename to src/rapid_router/migrations/0001_initial.py diff --git a/backend/rapid_router/migrations/__init__.py b/src/rapid_router/migrations/__init__.py similarity index 100% rename from backend/rapid_router/migrations/__init__.py rename to src/rapid_router/migrations/__init__.py diff --git a/backend/rapid_router/models/__init__.py b/src/rapid_router/models/__init__.py similarity index 100% rename from backend/rapid_router/models/__init__.py rename to src/rapid_router/models/__init__.py diff --git a/backend/rapid_router/models/level.py b/src/rapid_router/models/level.py similarity index 100% rename from backend/rapid_router/models/level.py rename to src/rapid_router/models/level.py diff --git a/backend/rapid_router/models/user.py b/src/rapid_router/models/user.py similarity index 88% rename from backend/rapid_router/models/user.py rename to src/rapid_router/models/user.py index c945ec16..e3663ee9 100644 --- a/backend/rapid_router/models/user.py +++ b/src/rapid_router/models/user.py @@ -11,10 +11,13 @@ from codeforlife.user.models import User as _User from django.db.models.query import QuerySet -from django_stubs_ext.db.models import TypedModelMeta if t.TYPE_CHECKING: + from django_stubs_ext.db.models import TypedModelMeta + from .level import Level +else: + TypedModelMeta = object class User(_User): diff --git a/backend/rapid_router/serializers/__init__.py b/src/rapid_router/serializers/__init__.py similarity index 100% rename from backend/rapid_router/serializers/__init__.py rename to src/rapid_router/serializers/__init__.py diff --git a/backend/rapid_router/serializers/level.py b/src/rapid_router/serializers/level.py similarity index 100% rename from backend/rapid_router/serializers/level.py rename to src/rapid_router/serializers/level.py diff --git a/backend/rapid_router/serializers/level_test.py b/src/rapid_router/serializers/level_test.py similarity index 100% rename from backend/rapid_router/serializers/level_test.py rename to src/rapid_router/serializers/level_test.py diff --git a/backend/rapid_router/urls.py b/src/rapid_router/urls.py similarity index 100% rename from backend/rapid_router/urls.py rename to src/rapid_router/urls.py diff --git a/backend/rapid_router/views/__init__.py b/src/rapid_router/views/__init__.py similarity index 100% rename from backend/rapid_router/views/__init__.py rename to src/rapid_router/views/__init__.py diff --git a/backend/rapid_router/views/level.py b/src/rapid_router/views/level.py similarity index 100% rename from backend/rapid_router/views/level.py rename to src/rapid_router/views/level.py diff --git a/backend/rapid_router/views/level_test.py b/src/rapid_router/views/level_test.py similarity index 100% rename from backend/rapid_router/views/level_test.py rename to src/rapid_router/views/level_test.py diff --git a/backend/service/__init__.py b/src/service/__init__.py similarity index 100% rename from backend/service/__init__.py rename to src/service/__init__.py diff --git a/backend/service/asgi.py b/src/service/asgi.py similarity index 81% rename from backend/service/asgi.py rename to src/service/asgi.py index fcb88c53..feb768b5 100644 --- a/backend/service/asgi.py +++ b/src/service/asgi.py @@ -11,6 +11,6 @@ from django.core.asgi import get_asgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "service.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "src.service.settings") application = get_asgi_application() diff --git a/backend/service/settings.py b/src/service/settings.py similarity index 99% rename from backend/service/settings.py rename to src/service/settings.py index 8162e79b..e20c81e3 100644 --- a/backend/service/settings.py +++ b/src/service/settings.py @@ -260,7 +260,8 @@ def domain(): ] INSTALLED_APPS = [ - "api", + "src.sso", + "src.rapid_router", "aimmo", "game", "pipeline", @@ -278,7 +279,5 @@ def domain(): "import_export", "sekizai", # for javascript and css management "treebeard", - "sso", - "rapid_router", *INSTALLED_APPS, ] diff --git a/backend/service/urls.py b/src/service/urls.py similarity index 84% rename from backend/service/urls.py rename to src/service/urls.py index accefdfb..519305e0 100644 --- a/backend/service/urls.py +++ b/src/service/urls.py @@ -15,7 +15,7 @@ """ from aimmo import urls as aimmo_urls # type: ignore[import-untyped] -from codeforlife.urls import service_urlpatterns +from codeforlife.urls import get_urlpatterns from django.urls import include, path from portal.views.aimmo.dashboard import ( # type: ignore[import-untyped] StudentAimmoDashboard, @@ -43,18 +43,15 @@ include(aimmo_urls), name="kurono", ), - *service_urlpatterns( - frontend_template_name="portal.html", # TODO: update, removed bundling - include_user_urls=False, - ), + *get_urlpatterns(include_user_urls=False), path( "api/", - include("sso.urls"), + include("src.sso.urls"), name="sso", ), path( "api/rapid_router/", - include("rapid_router.urls"), + include("src.rapid_router.urls"), name="rapid-router", ), ] diff --git a/backend/service/wsgi.py b/src/service/wsgi.py similarity index 81% rename from backend/service/wsgi.py rename to src/service/wsgi.py index 87360816..9d9523bd 100644 --- a/backend/service/wsgi.py +++ b/src/service/wsgi.py @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "service.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "src.service.settings") application = get_wsgi_application() diff --git a/backend/sso/__init__.py b/src/sso/__init__.py similarity index 100% rename from backend/sso/__init__.py rename to src/sso/__init__.py diff --git a/backend/sso/apps.py b/src/sso/apps.py similarity index 91% rename from backend/sso/apps.py rename to src/sso/apps.py index 050eaa79..112efec9 100644 --- a/backend/sso/apps.py +++ b/src/sso/apps.py @@ -9,4 +9,4 @@ # pylint: disable-next=missing-class-docstring class SsoConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "sso" + name = "src.sso" diff --git a/backend/sso/forms.py b/src/sso/forms.py similarity index 100% rename from backend/sso/forms.py rename to src/sso/forms.py diff --git a/backend/sso/permissions.py b/src/sso/permissions.py similarity index 100% rename from backend/sso/permissions.py rename to src/sso/permissions.py diff --git a/backend/sso/tests/__init__.py b/src/sso/tests/__init__.py similarity index 100% rename from backend/sso/tests/__init__.py rename to src/sso/tests/__init__.py diff --git a/backend/sso/tests/test_views.py b/src/sso/tests/test_views.py similarity index 100% rename from backend/sso/tests/test_views.py rename to src/sso/tests/test_views.py diff --git a/backend/sso/urls.py b/src/sso/urls.py similarity index 100% rename from backend/sso/urls.py rename to src/sso/urls.py diff --git a/backend/sso/views.py b/src/sso/views.py similarity index 100% rename from backend/sso/views.py rename to src/sso/views.py