diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5be1de0b5d3..5719f3e4fc4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,23 +31,16 @@ "uses": "actions/checkout@v2" }, { - "name": "Set up Python ${{ matrix.python-version }}", - "uses": "actions/setup-python@v5", - "with": { - "python-version": "${{ matrix.python-version }}" - } + "name": "Set up uv", + "uses": "astral-sh/setup-uv@v5" }, { - "name": "Set up pip cache", - "uses": "actions/cache@v4", - "with": { - "path": "~/.cache/pip", - "key": "pip-${{ matrix.python-version }}" - } + "name": "Set up Python ${{ matrix.python-version }}", + "run": "uv python install ${{ matrix.python-version }}" }, { "name": "Set up packages", - "run": "set -e\n\npip install -U pip setuptools wheel\npip install -U \\\n pre-commit coveralls pyyaml pytest-django\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n" + "run": "uv sync --group ci --locked" }, { "name": "Copy secret.py", @@ -55,7 +48,7 @@ }, { "name": "Run pre-commit", - "run": "pre-commit run --all-files" + "run": "uv run pre-commit run --all-files" } ] }, @@ -78,23 +71,16 @@ } }, { - "name": "Set up Python ${{ matrix.python-version }}", - "uses": "actions/setup-python@v5", - "with": { - "python-version": "${{ matrix.python-version }}" - } + "name": "Set up uv", + "uses": "astral-sh/setup-uv@v5" }, { - "name": "Set up pip cache", - "uses": "actions/cache@v4", - "with": { - "path": "~/.cache/pip", - "key": "pip-${{ matrix.python-version }}" - } + "name": "Set up Python ${{ matrix.python-version }}", + "run": "uv python install ${{ matrix.python-version }}" }, { "name": "Set up packages", - "run": "set -e\n\npip install -U pip setuptools wheel\npip install -U \\\n pre-commit coveralls pyyaml pytest-django\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n" + "run": "uv sync --group ci --locked" }, { "name": "Copy secret.py", @@ -102,33 +88,30 @@ }, { "name": "Regenerate workflow YAML file and check for changes", - "run": "./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py" + "run": "uv run ./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py" }, { "name": "Check for changes to CI spec", - "run": "./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py" + "run": "uv run ./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py" }, { "name": "Validate PR commit messages", "if": "github.event_name == 'pull_request'", - "run": "./scripts/validate-commit-messages.py ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}" + "run": "uv run ./scripts/validate-commit-messages.py ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}" }, { "name": "Validate push commit messages", "if": "github.event_name == 'push' && (github.repository_owner != 'tjcsl' || github.ref != 'refs/heads/master' || github.ref != 'refs/heads/dev')", "run": "git fetch origin ${{ github.event.before }} && ./scripts/validate-commit-messages.py ${{ github.event.before }}..${{ github.event.after }}" }, - { - "name": "Install docs dependencies", - "run": "# sphinxcontrib_django imports our django project, so we need the deps\npip install -U -r requirements.txt\ncd docs\npip install -U -r requirements.txt\n" - }, { "name": "Check docs build up to date", "run": "./scripts/build_ensure_no_changes.sh python3 scripts/build_docs.py" }, { "name": "Build docs", - "run": "cd docs\nmake html\n" + "workding_dir": "docs", + "run": "uv run make html" }, { "name": "Push docs", @@ -187,23 +170,16 @@ "uses": "actions/checkout@v2" }, { - "name": "Set up Python ${{ matrix.python-version }}", - "uses": "actions/setup-python@v5", - "with": { - "python-version": "${{ matrix.python-version }}" - } + "name": "Set up uv", + "uses": "astral-sh/setup-uv@v5" }, { - "name": "Set up pip cache", - "uses": "actions/cache@v4", - "with": { - "path": "~/.cache/pip", - "key": "pip-${{ matrix.python-version }}" - } + "name": "Set up Python ${{ matrix.python-version }}", + "run": "uv python install ${{ matrix.python-version }}" }, { "name": "Set up packages", - "run": "set -e\n\npip install -U pip setuptools wheel\npip install -U \\\n pre-commit coveralls pyyaml pytest-django\npip install -U -r requirements.txt\n\necho \"PATH=$PATH\" >> $GITHUB_ENV\n" + "run": "uv sync --group ci --locked" }, { "name": "Copy secret.py", @@ -235,24 +211,24 @@ { "name": "Run tests (Fork)", "if": "github.repository_owner != 'tjcsl'", - "run": "coverage run -a ./manage.py test --noinput --parallel 4" + "run": "uv run coverage run -a ./manage.py test --noinput --parallel 4" }, { "name": "Run tests (PR/Push)", "if": "github.repository_owner == 'tjcsl'", - "run": "coverage run -a ./manage.py test --noinput" + "run": "uv run coverage run -a ./manage.py test --noinput" }, { "name": "Check for unmigrated changes", - "run": "coverage run -a ./manage.py makemigrations --noinput --check" + "run": "uv run coverage run -a ./manage.py makemigrations --noinput --check" }, { "name": "Migrate database", - "run": "coverage run -a ./manage.py migrate" + "run": "uv run coverage run -a ./manage.py migrate" }, { "name": "Collect static files", - "run": "coverage run -a ./manage.py collectstatic --noinput -v 0" + "run": "uv run coverage run -a ./manage.py collectstatic --noinput -v 0" }, { "name": "Report coverage to Coveralls", @@ -264,7 +240,7 @@ { "name": "Build coverage XML file", "if": "github.repository_owner == 'tjcsl' && github.event_name != 'pull_request'", - "run": "coverage xml" + "run": "uv run coverage xml" }, { "name": "Report coverage to Codacy", diff --git a/.python-version b/.python-version new file mode 100644 index 00000000000..cc1923a40b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.8 diff --git a/ci/spec.yml b/ci/spec.yml index 718cf8b33d0..abcb947e175 100644 --- a/ci/spec.yml +++ b/ci/spec.yml @@ -27,12 +27,6 @@ env: node_versions: &node_versions - 14.x - python_setup: &python_setup - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - repo_setup: &repo_setup name: Set up repo uses: actions/checkout@v2 @@ -43,24 +37,17 @@ env: with: fetch-depth: 0 - setup_pip_cache: &setup_pip_cache - name: Set up pip cache - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: pip-${{ matrix.python-version }} + setup_uv_cache: &setup_uv_cache + name: Set up uv + uses: astral-sh/setup-uv@v6 + + python_setup: &python_setup + name: Set up Python ${{ matrix.python-version }} + run: uv python install ${{ matrix.python-version }} setup_packages: &setup_packages name: Set up packages - run: | - set -e - - pip install -U pip setuptools wheel - pip install -U \ - pre-commit coveralls pyyaml pytest-django - pip install -U -r requirements.txt - - echo "PATH=$PATH" >> $GITHUB_ENV + run: uv sync --group ci --locked .copy_secret: ©_secret name: Copy secret.py @@ -77,13 +64,13 @@ jobs: steps: - *repo_setup + - *setup_uv_cache - *python_setup - - *setup_pip_cache - *setup_packages - *copy_secret - name: Run pre-commit - run: 'pre-commit run --all-files' + run: 'uv run pre-commit run --all-files' build: runs-on: ubuntu-latest @@ -96,43 +83,34 @@ jobs: steps: # We need the full history so we can validate commit messages. - *repo_setup_fetch_all + - *setup_uv_cache - *python_setup - - *setup_pip_cache - *setup_packages - *copy_secret - name: Regenerate workflow YAML file and check for changes - run: ./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py + run: uv run ./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py # Check for changes to CI spec - name: Check for changes to CI spec - run: ./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py + run: uv run ./scripts/build_ensure_no_changes.sh ./ci/regen-workflow.py # Validate commit messages - name: Validate PR commit messages # Validate commit messages for PRs if: "github.event_name == 'pull_request'" - run: ./scripts/validate-commit-messages.py ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} + run: uv run ./scripts/validate-commit-messages.py ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} - name: Validate push commit messages # Validate commit messages for forks and branches that aren't dev or master if: "github.event_name == 'push' && (github.repository_owner != 'tjcsl' || github.ref != 'refs/heads/master' || github.ref != 'refs/heads/dev')" run: 'git fetch origin ${{ github.event.before }} && ./scripts/validate-commit-messages.py ${{ github.event.before }}..${{ github.event.after }}' - # Build/push docs - - name: Install docs dependencies - run: | - # sphinxcontrib_django imports our django project, so we need the deps - pip install -U -r requirements.txt - cd docs - pip install -U -r requirements.txt - - name: Check docs build up to date run: ./scripts/build_ensure_no_changes.sh python3 scripts/build_docs.py - name: Build docs - run: | - cd docs - make html + workding_dir: docs + run: uv run make html - name: Push docs # Only run for pushes to the main Ion repo @@ -177,8 +155,8 @@ jobs: steps: - *repo_setup + - *setup_uv_cache - *python_setup - - *setup_pip_cache - *setup_packages - *copy_secret @@ -210,20 +188,21 @@ jobs: sudo apt update sudo apt install -y krb5-user + # Tests - name: Run tests (Fork) if: github.repository_owner != 'tjcsl' - run: coverage run -a ./manage.py test --noinput --parallel 4 + run: uv run coverage run -a ./manage.py test --noinput --parallel 4 - name: Run tests (PR/Push) if: github.repository_owner == 'tjcsl' # Run single-threaded for accurate coverage reporting on Ion GitHub - run: coverage run -a ./manage.py test --noinput + run: uv run coverage run -a ./manage.py test --noinput # Check for unmigrated changes - name: Check for unmigrated changes - run: coverage run -a ./manage.py makemigrations --noinput --check + run: uv run coverage run -a ./manage.py makemigrations --noinput --check - name: Migrate database - run: coverage run -a ./manage.py migrate + run: uv run coverage run -a ./manage.py migrate - name: Collect static files - run: coverage run -a ./manage.py collectstatic --noinput -v 0 + run: uv run coverage run -a ./manage.py collectstatic --noinput -v 0 # Coveralls - name: Report coverage to Coveralls @@ -234,7 +213,7 @@ jobs: # Codacy - name: Build coverage XML file if: github.repository_owner == 'tjcsl' && github.event_name != 'pull_request' - run: coverage xml + run: uv run coverage xml - name: Report coverage to Codacy uses: codacy/codacy-coverage-reporter-action@master if: github.repository_owner == 'tjcsl' && github.event_name != 'pull_request' diff --git a/config/docker/Dockerfile b/config/docker/Dockerfile index 2929ecf8aee..ef96669dda3 100644 --- a/config/docker/Dockerfile +++ b/config/docker/Dockerfile @@ -1,18 +1,22 @@ FROM python:3.8.19-alpine3.18 -ENV TZ America/New_York -ENV C_FORCE_ROOT true +ENV TZ=America/New_York +ENV C_FORCE_ROOT=true +ENV UV_LINK_MODE=copy \ + UV_COMPILE_BYTECODE=1 \ + UV_PYTHON_DOWNLOADS=never \ + UV_PROJECT_ENVIRONMENT=/venv COPY config/krb5.conf /etc/krb5.conf -COPY requirements.txt . -COPY requirements-dev.txt . +COPY pyproject.toml . +COPY uv.lock . + +COPY --from=ghcr.io/astral-sh/uv:0.6 /uv /bin/uv RUN apk update && \ apk add bash git curl build-base libpq-dev freetype-dev libffi-dev ruby-full libmagic krb5 kinit rsync nodejs npm tzdata libxml2-dev libxslt-dev && \ npm install -g sass && \ ln -s /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ - pip3 install -Ir requirements.txt && \ - pip3 install -Ir requirements-dev.txt && \ - rm requirements.txt requirements-dev.txt + uv sync WORKDIR /ion diff --git a/config/docker/docker-compose.yml b/config/docker/docker-compose.yml index 854fb816b02..aa7a6c510fc 100644 --- a/config/docker/docker-compose.yml +++ b/config/docker/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.9' - services: redis: container_name: intranet_redis @@ -56,7 +54,7 @@ services: "/bin/sh", "-c", "git config --global --add safe.directory /ion && \ - celery --app intranet worker -l info --without-gossip --without-mingle --without-heartbeat -Ofair" + uv run celery --app intranet worker -l info --without-gossip --without-mingle --without-heartbeat -Ofair" ] depends_on: - django @@ -73,7 +71,7 @@ services: "/bin/sh", "-c", "git config --global --add safe.directory /ion && \ - celery --app intranet beat -l info" + uv run celery --app intranet beat -l info" ] depends_on: - django diff --git a/config/docker/entrypoint.sh b/config/docker/entrypoint.sh index fdbd9257296..9c7183d5a4e 100755 --- a/config/docker/entrypoint.sh +++ b/config/docker/entrypoint.sh @@ -12,6 +12,6 @@ export PYTHONUNBUFFERED=1 # Don't buffer Django output # Wrap the run command in a loop so that it restarts if it crashes, e.g. due to a syntax error while true do - python3 manage.py run 0.0.0.0:8080 # Custom run command that skips system checks for performance + uv run manage.py run 0.0.0.0:8080 # Custom run command that skips system checks for performance sleep 1 done diff --git a/config/docker/initial_setup.sh b/config/docker/initial_setup.sh index 3786433fc8b..af1e83dc863 100755 --- a/config/docker/initial_setup.sh +++ b/config/docker/initial_setup.sh @@ -9,35 +9,35 @@ echo -e "${BLUE}${BOLD}Copying over secret.py...${CLEAR}" cp -u config/docker/secret.py intranet/settings echo -e "${BLUE}${BOLD}Collecting static...${CLEAR}" -python3 manage.py collectstatic --noinput +uv run manage.py collectstatic --noinput echo -e "${BLUE}${BOLD}Running migrations...${CLEAR}" -python3 manage.py migrate +uv run manage.py migrate echo -e "${BLUE}${BOLD}Copying over scripts...${CLEAR}" cp config/scripts/*.py . echo -e "${BLUE}${BOLD}Generating users and teachers...${CLEAR}" for year in "freshman" "sophomore" "junior" "senior"; do - python3 create_users.py -t student -nw -y $year -n student student1 student2 student3 student4 student5 - python3 create_users.py -t admin -nw -y $year -n admin admin1 admin2 admin3 admin4 admin5 + uv run create_users.py -t student -nw -y $year -n student student1 student2 student3 student4 student5 + uv run create_users.py -t admin -nw -y $year -n admin admin1 admin2 admin3 admin4 admin5 done -python3 create_users.py -nw -ny -t admin -n admin -python3 create_users.py -t admin -c 10 -python3 create_users.py -t student -c 100 -python3 create_users.py -t teacher -c 20 +uv run create_users.py -nw -ny -t admin -n admin +uv run create_users.py -t admin -c 10 +uv run create_users.py -t student -c 100 +uv run create_users.py -t teacher -c 20 echo -e "${BLUE}${BOLD}Creating eighth period activities...${CLEAR}" -python3 create_activities.py -c 10 -python3 create_activities.py -r freshman -c 2 -python3 create_activities.py -r sophomore -c 2 -python3 create_activities.py -r junior -c 2 -python3 create_activities.py -r senior -c 2 -python3 create_activities.py -g admin_all -c 2 +uv run create_activities.py -c 10 +uv run create_activities.py -r freshman -c 2 +uv run create_activities.py -r sophomore -c 2 +uv run create_activities.py -r junior -c 2 +uv run create_activities.py -r senior -c 2 +uv run create_activities.py -g admin_all -c 2 echo -e "${BLUE}${BOLD}Creating eighth period blocks...${CLEAR}" -python3 create_blocks.py -l A B -c 60 -python3 create_blocks.py -l A B C -i 4 -c 15 +uv run create_blocks.py -l A B -c 60 +uv run create_blocks.py -l A B C -i 4 -c 15 echo -e "${BLUE}${BOLD}Cleaning up scripts...${CLEAR}" for file in config/scripts/*.py; do @@ -45,7 +45,7 @@ for file in config/scripts/*.py; do done echo -e "${BLUE}${BOLD}Pulling Sports...${CLEAR}" -python3 -u manage.py import_sports $(date +%m) +uv run python3 -u manage.py import_sports $(date +%m) echo -e "${BLUE}${BOLD}Creating CSL apps...${CLEAR}" -python3 -u manage.py dev_create_cslapps +uv run python3 -u manage.py dev_create_cslapps diff --git a/intranet/apps/eighth/views/routers.py b/intranet/apps/eighth/views/routers.py index 17a219ce554..17556f74692 100644 --- a/intranet/apps/eighth/views/routers.py +++ b/intranet/apps/eighth/views/routers.py @@ -18,4 +18,6 @@ def eighth_redirect_view(request): else: view = "index" # should never happen - return resolve(reverse(view)).func(request) + func, args, kwargs = resolve(reverse(view)) + kwargs["request"] = request + return func(*args, **kwargs) diff --git a/intranet/apps/oauth/migrations/0010_auto_20240918_1233.py b/intranet/apps/oauth/migrations/0010_auto_20240918_1233.py new file mode 100644 index 00000000000..1e88508789a --- /dev/null +++ b/intranet/apps/oauth/migrations/0010_auto_20240918_1233.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.25 on 2024-09-18 16:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('oauth', '0009_cslapplication_post_logout_redirect_uris'), + ] + + operations = [ + migrations.AddField( + model_name='cslapplication', + name='allowed_origins', + field=models.TextField(blank=True, default='', help_text='Allowed origins list to enable CORS, space separated'), + ), + migrations.AddField( + model_name='cslapplication', + name='hash_client_secret', + field=models.BooleanField(default=True), + ), + migrations.AlterField( + model_name='cslapplication', + name='post_logout_redirect_uris', + field=models.TextField(blank=True, default='', help_text='Allowed Post Logout URIs list, space separated'), + ), + ] diff --git a/intranet/settings/__init__.py b/intranet/settings/__init__.py index 2cf7a826416..bad30a72bde 100644 --- a/intranet/settings/__init__.py +++ b/intranet/settings/__init__.py @@ -3,7 +3,6 @@ import os import re import sys -from typing import Any, Dict, List, Tuple # noqa import celery.schedules import pytz @@ -12,11 +11,7 @@ from sentry_sdk.integrations.django import DjangoIntegration from sentry_sdk.integrations.logging import LoggingIntegration -from ..utils import helpers # pylint: disable=wrong-import-position # noqa - -if sys.version_info < (3, 5): - # Require Python 3.5+ - raise Exception("Python 3.5 or higher is required.") +from ..utils import helpers # Month (1-indexed) after which a new school year begins # July = 7 @@ -38,24 +33,24 @@ # When school is scheduled to start and end SCHOOL_START_DATE = datetime.date(start_school_year, - 8, 19 # UPDATE THIS! Value when last updated: August 19, 2024 # noqa: E128 -) # noqa: E124 + 8, 19 # UPDATE THIS! Value when last updated: August 19, 2024 +) SCHOOL_END_DATE = datetime.date(end_school_year, - 6, 11 # UPDATE THIS! Value when last updated: June 11, 2025 # noqa: E128 -) # noqa: E124 + 6, 11 # UPDATE THIS! Value when last updated: June 11, 2025 +) # Dates when hoco starts and ends HOCO_START_DATE = datetime.date(start_school_year, - 9, 21 # UPDATE THIS! Value when last updated: September 21, 2024 # noqa: E128 -) # noqa: E124 + 9, 21 # UPDATE THIS! Value when last updated: September 21, 2024 +) HOCO_END_DATE = datetime.date(start_school_year, - 9, 29 # UPDATE THIS! Value when last updated: September 29, 2024 # noqa: E128 -) # noqa: E124 + 9, 29 # UPDATE THIS! Value when last updated: September 29, 2024 +) # Date of tjSTAR TJSTAR_DATE = datetime.date(end_school_year, - 5, 21 # UPDATE THIS! Value when last updated: May 21, 2024 # noqa: E128 -) # noqa: E124 + 5, 21 # UPDATE THIS! Value when last updated: May 21, 2024 +) # When to start showing the tjSTAR banner TJSTAR_BANNER_START_DATE = TJSTAR_DATE - datetime.timedelta(days=4) diff --git a/intranet/static/js/game.js b/intranet/static/js/game.min.js similarity index 100% rename from intranet/static/js/game.js rename to intranet/static/js/game.min.js diff --git a/intranet/templates/bus/game.html b/intranet/templates/bus/game.html index f082382540c..d39d0985d0f 100644 --- a/intranet/templates/bus/game.html +++ b/intranet/templates/bus/game.html @@ -177,7 +177,7 @@