Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
136 commits
Select commit Hold shift + click to select a range
dee2445
chore: dev init
zzjc1234 Sep 25, 2025
d157917
feat: auto deploy
zzjc1234 Sep 25, 2025
ffb777b
fix: dev.sh
zzjc1234 Sep 25, 2025
60a0a99
feat: docker compose tested
zzjc1234 Sep 25, 2025
0cc296a
Merge branch 'dev' into feat/deployment-script
zzjc1234 Sep 27, 2025
18b0a45
chore: use polling instead of sleep and update doc
A-lexisL Sep 27, 2025
205fecc
chore(Dockerfile): Use Python 3.13 and Debian 13
PACHAKUTlQ Sep 28, 2025
b3a29d2
Merge branch 'dev' into feat/deployment-script
zzjc1234 Sep 29, 2025
0e53795
chore(scripts): reorganzie path of scripts
zzjc1234 Sep 29, 2025
e249863
fix(docker): backend deployment with docker
zzjc1234 Sep 29, 2025
1149dab
build: configure pytest-django and add dev dependencies
SherryShijiarui Jan 3, 2026
8d3ed21
fix: update factory compatibility
SherryShijiarui Jan 3, 2026
a3fc806
fix: increase field lengths and update Django+migrations
SherryShijiarui Jan 3, 2026
54059f0
build: test_auth.py
SherryShijiarui Jan 3, 2026
5459ae8
fix: resolve model naming and factory syntax errors
SherryShijiarui Jan 4, 2026
cbd6269
fix: implement robust data factories for course and student
SherryShijiarui Jan 5, 2026
3ab511e
build: test_auth.py test_course.py test_review.py
SherryShijiarui Jan 5, 2026
bcc4148
fix: test_review.py
SherryShijiarui Jan 5, 2026
6439b8f
fix: add more function to test_auth.py and test_course.py
SherryShijiarui Jan 5, 2026
6a44f11
fix: add more function to test_review.py
SherryShijiarui Jan 5, 2026
706f8c5
fix: add more function to test_vote.py
SherryShijiarui Jan 5, 2026
656cb5d
reset to original database
SherryShijiarui Jan 12, 2026
7a3cf02
reset to original py
SherryShijiarui Jan 12, 2026
2cff119
fix: fix test.review.py
SherryShijiarui Jan 19, 2026
74cb780
fix: push 0012_vote_web_vote_course__b117a9_idx.py
SherryShijiarui Jan 19, 2026
088539c
test: add new vote tests (difficulty, change, cancel) and unauthentic…
liaotian756 Jan 19, 2026
bdf5b2e
add tests(filtering and sorting courses with permission check) TODO: …
liaotian756 Jan 19, 2026
8997bda
fix: fix course_code in factories.py
SherryShijiarui Jan 19, 2026
38da811
fix: make test more precise in test_auth.py
SherryShijiarui Jan 19, 2026
bc0334e
FIX: use the right format of course code
liaotian756 Jan 20, 2026
23d6f05
fix: make test_auth.py more conprehensive with 0 and multiple cases
SherryShijiarui Jan 20, 2026
a314ed8
build: add more fixture to conftest.py
SherryShijiarui Jan 20, 2026
97460ba
build: add more fixture to conftest.py
SherryShijiarui Jan 20, 2026
8d3f870
build: add more fixture to conftest.py and add more test to test_revi…
SherryShijiarui Jan 20, 2026
08bd759
fix: fix course_title in conftest.py and course code in test_review.py
SherryShijiarui Jan 20, 2026
82b7d1f
fix: fix test
SherryShijiarui Jan 20, 2026
c1ca6c4
docs: update frontend setup
A-lexisL Jan 20, 2026
08df2b5
chore: update submodule pointer
A-lexisL Jan 20, 2026
5aec605
build: add base_client in test_review.py and test_vote.py
SherryShijiarui Jan 20, 2026
8f6b224
docs: setup
A-lexisL Jan 21, 2026
546134b
chore: update submodule frontend
A-lexisL Jan 21, 2026
8c77313
Merge pull request #43 from Tech-JI/chore/update-submodule
A-lexisL Jan 21, 2026
fa1f27d
add tests: sort by review_count filter by min_difficulty sort order(a…
SherryShijiarui Jan 20, 2026
5a7a0b1
delete test: pagnition
liaotian756 Jan 22, 2026
62fee0c
Merge branch 'dev' into feat/deployment-script
zzjc1234 Sep 30, 2025
3c1be34
feat: podman support
zzjc1234 Oct 8, 2025
f9d855c
feat: deploy with wsgi
zzjc1234 Oct 9, 2025
6b8cd9e
feat: distroless support
zzjc1234 Oct 9, 2025
f937496
chore: rm old shell script
zzjc1234 Oct 9, 2025
a01539a
fix: dependency
zzjc1234 Feb 17, 2026
10ae7f8
fix: ruff check
zzjc1234 Feb 17, 2026
a7cbe24
test: group API tests by auth state and add coverage
zzjc1234 Feb 17, 2026
2ad2872
test: fix term assertions and fixture comment
zzjc1234 Feb 17, 2026
88ba7f6
build: update uv lockfile
zzjc1234 Feb 17, 2026
e24ef16
fix: make podman stack run backend and frontend
zzjc1234 Feb 18, 2026
197e794
chore: update dependencies
zzjc1234 Feb 18, 2026
3308db1
chore: rm docker compose
zzjc1234 Feb 19, 2026
28c5828
chore: upgrade container version
zzjc1234 Feb 19, 2026
0a49eea
fix: rm docker compability
zzjc1234 Feb 19, 2026
0975000
fix: rm docker keywords
zzjc1234 Feb 19, 2026
ce25e95
fix: rm non ascii
zzjc1234 Feb 19, 2026
8df3106
chore: use the setup on the dev branch
zzjc1234 Feb 19, 2026
a373e43
fix: use uv instead of python3
zzjc1234 Feb 19, 2026
2a2be4b
chore: rewind submodule
zzjc1234 Feb 19, 2026
597267f
chore: use uv instead of python 3
zzjc1234 Feb 19, 2026
2d65641
chore: migrate create_admin and entrypoint
zzjc1234 Feb 19, 2026
71e44ee
chore: update compose
zzjc1234 Feb 19, 2026
b3327c2
chore: add gunicorn
zzjc1234 Feb 19, 2026
c901e49
fix(podman)!: Use env for credentials
PACHAKUTlQ Feb 19, 2026
c5cb3f6
fix(setup): Change non-exist `is_admin` to `is_superuser`
PACHAKUTlQ Feb 19, 2026
f2e70ca
style(dev): Format dev.sh
PACHAKUTlQ Feb 19, 2026
e191212
fix: Use relative paths for entrypoint script as convention
PACHAKUTlQ Feb 19, 2026
309f8c3
feat(podman)!: Rename Dockerfile to Containerfile
PACHAKUTlQ Feb 19, 2026
cc42c81
chore(podman): Add .containerignore
PACHAKUTlQ Feb 19, 2026
cd02f26
fix(setup)!: Remove static file collections
PACHAKUTlQ Feb 20, 2026
48dd31b
fix(setup)!: Install all dependencies groups like dev and lint
PACHAKUTlQ Feb 20, 2026
4cc6fd6
fix(setup): Add executable permission to dev.sh
PACHAKUTlQ Feb 20, 2026
34e890e
chore: add STATIC_ROOT env
A-lexisL Feb 20, 2026
12c698d
revert: adding STATIC_ROOT
A-lexisL Feb 20, 2026
b1aebcc
chore: Remove unused podman-compose
PACHAKUTlQ Feb 21, 2026
c601933
feat(setup): Support redirecting all output to both stdout and a log …
PACHAKUTlQ Feb 21, 2026
20b8f6d
fix(podman): Set default `DB_HOST` as `localhost`
PACHAKUTlQ Feb 21, 2026
7a2fef3
fix(setup): Only copy .env when no existing one
PACHAKUTlQ Feb 21, 2026
5574396
fix(podman)!: Remove unused frontend container
PACHAKUTlQ Feb 21, 2026
9b44db1
fix(podman)!: Enable Containerfile in podman-compose.yaml
PACHAKUTlQ Feb 21, 2026
35a6eb0
fix(setup)!: Use `valkey-cli` instead of `redis-cli`
PACHAKUTlQ Feb 21, 2026
b4c25f8
fix(podman): Respect env in postgres healthcheck
PACHAKUTlQ Feb 21, 2026
f32e1fd
fix!: Use `REDIS__URL` instead of `REDIS_URL` for consistency
PACHAKUTlQ Feb 21, 2026
cc61c0c
style(podman): Use dictionary instead of list
PACHAKUTlQ Feb 21, 2026
3a92304
fix(podman): Run python in unbuffered output mode for real time logging
PACHAKUTlQ Feb 21, 2026
d02e998
Revert "fix(podman): Set default `DB_HOST` as `localhost`"
PACHAKUTlQ Feb 24, 2026
a314977
fix(podman)!: Postgres use data/ dir
PACHAKUTlQ Feb 22, 2026
e71f114
fix(podman)!: Remove unused database env variables
PACHAKUTlQ Feb 22, 2026
ad2ade8
fix!: Use container name as host in .env file to make postgres happy
PACHAKUTlQ Feb 22, 2026
b19e5ab
fix(podman): Create gunicorn socket in /tmp instead of /app due to pe…
PACHAKUTlQ Feb 22, 2026
17d9ca2
fix(podman): Use `python` instead of `python3`
PACHAKUTlQ Feb 22, 2026
72bcbe9
fix(podman): Use `python` instead of `python3`
PACHAKUTlQ Feb 22, 2026
d598370
fix(podman): Podman ignore config.yaml
PACHAKUTlQ Feb 22, 2026
3888efa
fix(podman)!: Build with uv trixie image
PACHAKUTlQ Feb 22, 2026
257493e
chore: Update dependencies
PACHAKUTlQ Feb 23, 2026
ed721fa
fix! Remove scripts/dev.sh and Makefile
PACHAKUTlQ Feb 23, 2026
aa293bb
fix! Rename manage.py to django_manage.py to avoid confusion
PACHAKUTlQ Feb 23, 2026
3e1b61c
fix(podman)!: Stop running migrations in podman entrypoint script
PACHAKUTlQ Feb 23, 2026
44a67aa
refactor(podman)!: Use different compose file for using podman in dev…
PACHAKUTlQ Feb 23, 2026
44a0818
feat: Use an unified script for managing everything
PACHAKUTlQ Feb 23, 2026
ece4880
ci: Ignore the control script
PACHAKUTlQ Feb 23, 2026
ba841d3
style(run): Add new line before return and after exception to satisfy…
PACHAKUTlQ Feb 23, 2026
8470be2
fix(run): Fix mixed program name
PACHAKUTlQ Feb 23, 2026
745c5d3
fix(run): Normalize host to adapt to both podman and django requirements
PACHAKUTlQ Feb 23, 2026
e053469
ci(hook)!: Add more git hooks
PACHAKUTlQ Feb 23, 2026
b082ef1
ci(hook): Update ruff pre-commit hook version
PACHAKUTlQ Feb 23, 2026
96123f4
fix(hook)!: Pin python version to 3.14 to force prek check 3.14 AST
PACHAKUTlQ Feb 23, 2026
a7925f0
fix(run): Make infra commands more intuitive
PACHAKUTlQ Feb 24, 2026
aaecd6f
fix: remove redundant check
A-lexisL Mar 1, 2026
16f1ce4
fix: add back test delete non-existent review
A-lexisL Mar 1, 2026
8f02a9d
refactor: rm unused model_tests
A-lexisL Mar 1, 2026
41c2c6c
Revert "build: update uv lockfile" to not use mirror
A-lexisL Mar 1, 2026
c83f2b9
Merge pull request #40 from Tech-JI/feat/web-view-pytest
A-lexisL Mar 1, 2026
63c9e9c
chore: Add GitHub Actions workflow for testing
A-lexisL Mar 2, 2026
37f8c0b
Rename python-app.yml to pytest.yml
A-lexisL Mar 2, 2026
fc47ab9
chore: setup pgsql service
A-lexisL Mar 2, 2026
ab22540
chore: add secret-key env
A-lexisL Mar 2, 2026
9c943ee
Merge pull request #47 from Tech-JI/chore-pytest-github-action
A-lexisL Mar 2, 2026
e6bd6e0
ci: Add GitHub Actions OCI image builds
PACHAKUTlQ Feb 25, 2026
fc831e9
ci: update dependencies
PACHAKUTlQ Feb 26, 2026
f9b0f5b
Merge branch 'dev' into feat/deployment-script
PACHAKUTlQ May 22, 2026
2a924b4
fix: Explicitly add pythonpath for pytest due to manage.py not found
PACHAKUTlQ Feb 27, 2026
574a0dc
feat: Add pytest in run.py to parse hosts correctly
PACHAKUTlQ Feb 27, 2026
0f28602
fix: pytest CI uses run.py
PACHAKUTlQ Feb 27, 2026
7b03695
style: Format Github Actions YAML
PACHAKUTlQ Feb 27, 2026
ab3a1af
ci(podman): Container ignore .pytest_cache/
PACHAKUTlQ Feb 27, 2026
6502c42
docs(config): Update config docs (rename RESET_PASSWORD and hostname)
PACHAKUTlQ Feb 27, 2026
28dc2ff
docs(setup): Setup guide uses latest run.py workflow
PACHAKUTlQ Feb 27, 2026
b58fca8
docs(setup): Add deployment guide
PACHAKUTlQ Feb 27, 2026
dfc3d97
docsRename setup to usage
PACHAKUTlQ Feb 27, 2026
3d45e01
Merge pull request #23 from Tech-JI/feat/deployment-script
PACHAKUTlQ May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .containerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
config.yaml
run.py
.git
.venv
.env
.ruff_cache
.pytest_cache
frontend
.github
docs
Makefile
.pre-commit-config.yaml
LICENSE
.gitignore
.containerignore
.gitmodules
podman-compose.yaml
__pycache__
*.py[codz]
**/__pycache__
**/*.py[codz]
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ SECRET_KEY=django-insecure-my-local-dev-secret-key
# --- Infrastructure (REQUIRED) ---
# Use a single URL for database and Redis connections.
# Format: driver://user:password@host:port/dbname
DATABASE__URL=postgres://admin:test@127.0.0.1:5432/coursereview
REDIS__URL=redis://localhost:6379/0
DATABASE__URL=postgres://admin:test@db:5432/coursereview
REDIS__URL=redis://cache:6379/0

# --- External Services Secrets (REQUIRED) ---
TURNSTILE_SECRET_KEY=dummy0
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/bot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ on:
public:
pull_request:
branches:
- '*'
- "*"
types: [opened, reopened]
pull_request_review:
types: [edited, dismissed, submitted]
Expand All @@ -46,7 +46,7 @@ on:
types: [assigned, opened, synchronize, reopened]
push:
branches:
- '*'
- "*"
registry_package:
types: [published]
release:
Expand Down
54 changes: 54 additions & 0 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Publish container image

on:
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ghcr.io/tech-ji/coursereview

jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=sha-
type=ref,event=tag
labels: |
org.opencontainers.image.source=https://github.com/Tech-JI/CourseReview
org.opencontainers.image.description=CourseReview Django application

- name: Build and push image
id: push
uses: docker/build-push-action@v7
with:
context: .
file: ./Containerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

- name: Show digest
run: |
echo "Digest: ${{ steps.push.outputs.digest }}"
78 changes: 78 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: pytest

on:
push:
branches: ["dev", "main"]
pull_request:
branches: ["dev", "main"]

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest

services:
db:
image: postgres:18-alpine
env:
POSTGRES_DB: coursereview
POSTGRES_USER: admin
POSTGRES_PASSWORD: test
ports:
- "5432:5432"
options: >-
--health-cmd "pg_isready -U admin -d coursereview"
--health-interval 10s
--health-timeout 5s
--health-retries 5

cache:
image: valkey/valkey:9-alpine
ports:
- "6379:6379"
options: >-
--health-cmd "valkey-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

env:
SECRET_KEY: 02247f40-a769-4c49-9178-4c038048e7ad
DATABASE__URL: postgres://admin:test@db:5432/coursereview
REDIS__URL: redis://cache:6379/0

TURNSTILE_SECRET_KEY: dummy0

QUEST__SIGNUP__API_KEY: dummy1
QUEST__SIGNUP__URL: https://wj.sjtu.edu.cn/q/dummy0
QUEST__SIGNUP__QUESTIONID: "10000000"

QUEST__LOGIN__API_KEY: dummy2
QUEST__LOGIN__URL: https://wj.sjtu.edu.cn/q/dummy1
QUEST__LOGIN__QUESTIONID: "10000001"

QUEST__RESET__API_KEY: dummy3
QUEST__RESET__URL: https://wj.sjtu.edu.cn/q/dummy2
QUEST__RESET__QUESTIONID: "10000002"

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version-file: pyproject.toml

- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true

- name: Install dependencies
run: uv sync --frozen --group dev

- name: Run pytest
run: python run.py test
23 changes: 18 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
repos:
default_language_version:
python: 3.14

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-ast
- id: check-builtin-literals
- id: check-case-conflict
- id: check-illegal-windows-names
- id: check-json
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
- id: detect-private-key
- id: end-of-file-fixer
- id: no-commit-to-branch
- id: pretty-format-json
- id: requirements-txt-fixer
- id: trailing-whitespace

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.5
rev: v0.15.2
hooks:
- id: ruff-check
types_or: [python, pyi]
Expand Down
20 changes: 20 additions & 0 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM ghcr.io/astral-sh/uv:python3.14-trixie-slim AS builder

WORKDIR /app

COPY . /app

RUN UV_PROJECT_ENVIRONMENT=/usr/local \
uv sync --project=/app --frozen --compile-bytecode --no-dev --no-editable --no-managed-python

FROM gcr.io/distroless/base-debian13:nonroot

COPY --from=builder /usr/local /usr/local

COPY --from=builder /app /app

WORKDIR /app

USER nonroot

ENTRYPOINT ["python", "scripts/entrypoint.py"]
81 changes: 0 additions & 81 deletions Makefile

This file was deleted.

2 changes: 1 addition & 1 deletion apps/auth/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def get_survey_details(action: str) -> dict[str, Any] | None:

try:
question_id = int(action_details.get("QUESTIONID"))
except (ValueError, TypeError):
except ValueError, TypeError:
logger.error(
"Could not parse 'QUESTIONID' for action '%s'. Check your settings.", action
)
Expand Down
4 changes: 2 additions & 2 deletions apps/auth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def verify_callback_api(request):
otp_data = json.loads(otp_data_raw.decode("utf-8"))
expected_temp_token = otp_data.get("temp_token")
initiated_at = otp_data.get("initiated_at")
except (json.JSONDecodeError, AttributeError):
except json.JSONDecodeError, AttributeError:
logger.error("Invalid OTP data format in verify_callback_api")
return Response({"error": "Invalid OTP data format"}, status=401)

Expand Down Expand Up @@ -268,7 +268,7 @@ def verify_callback_api(request):
status=401,
)

except (ValueError, TypeError):
except ValueError, TypeError:
logger.error("Error parsing submission timestamp")
return Response({"error": "Invalid submission timestamp"}, status=401)

Expand Down
21 changes: 21 additions & 0 deletions apps/web/migrations/0012_vote_web_vote_course__b117a9_idx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 5.2.8 on 2026-01-19 02:11

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("web", "0011_remove_course_difficulty_score_and_more"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AddIndex(
model_name="vote",
index=models.Index(
fields=["course", "category", "value"],
name="web_vote_course__b117a9_idx",
),
),
]
4 changes: 2 additions & 2 deletions apps/web/models/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def search(self, query):
elif len(department_or_query) not in self.DEPARTMENT_LENGTHS:
# must be query, too long to be department. ignore numbers we may
# have. e.g. "Introduction"
return Course.objects.filter(title__icontains=department_or_query)
return Course.objects.filter(course_title__icontains=department_or_query)
# elif number and subnumber:
# # course with number and subnumber
# # e.g. COSC 089.01
Expand Down Expand Up @@ -140,7 +140,7 @@ class Meta:
]

def __unicode__(self):
return "{}: {}".format(self.short_name(), self.title)
return "{}: {}".format(self.short_name(), self.course_title)

def get_absolute_url(self):
return reverse("course_detail", args=[self.id])
Expand Down
Loading
Loading