Recruitment for Abakus.
Table of contents
- Environments
- Local development
- Creating admissions
- Interview scheduling worker
- Permissions
- Run tests
- Code style
Â
opptak.abakus.no
OAuth through abakus.no
opptak-staging.abakus.no
OAuth through abakus.no
Â
To run this project, you need
- python 3.12
- Docker OR a
postgresqldatabase - poetry (installation guide)
- Node and yarn
When working in development you want to have LEGO running (both frontend and backend). This allows you to create an OAuth2 application from the settings menu in the webapp.
To do this, you need a total of 4 terminals (or shells if you like).
Run LEGO by following the README here.
Run LEGO-WEBAPP by following the README here.
Install the projects dependencies with
$ poetry installThis command will also create a virtual environment in which the dependencies are installed, if one has not already been created and activated.
Then, run the following command
$ make dev_settingsThe docker-compose.yml file provides a postgresql database. This uses a different port than LEGO, so you can run it in parallel as follows.
$ docker-compose up -dThe .env file with secret keys is not included, but an example.env file has been provided in ./admissions/settings, so that you can simply rename the file and fill in the values.
Create a local OAuth2 application in LEGO and put its client ID and secret in your copied .env file. Never commit real OAuth credentials.
Credential-shaped OAuth values have existed in this repository's history. Treat any matching LEGO application credentials as compromised: revoke them in LEGO, create a replacement client, and update the deployment secret store. Removing a value from the current tree or rewriting Git history does not replace credential rotation.
If you want to configure another one, go to the OAuth2 tab in the user settings menu in the running dev version of lego-webapp. Open or create an application, and enter the values you find into your .env file. If you are creating a new OAuth2 application, enter http://127.0.0.1:5002/complete/lego/ as the redirect URL.
# Create a copy of the example env file (run from the root of the project)
$ cp admissions/settings/example.env admissions/settings/.env
# Edit the file and change the KEY and SECRET
AUTH_LEGO_KEY="Client ID from OAuth2"
AUTH_LEGO_SECRET="Client Secret from OAuth2"
AUTH_LEGO_API_URL="http://127.0.0.1:8000/"After creating and configuring your ./admissions/settings/.env file you are ready to initialize the local development data and run the server.
# Start PostgreSQL, apply migrations, and load Admissions development fixtures
$ make initialize_development
# Run the Django server and interview-scheduling worker together
$ make devThe command is safe to repeat for local development.
It refreshes the known Admissions fixture rows without flushing the database.
It initializes Admissions only.
The existing fixture loader also normalizes admission dates for all local
Admissions, including custom Admissions created during development.
To populate LEGO users and events, run LEGO's initialize_development management
command from the LEGO checkout after its services are running.
If coding over long periods of time, or you want to flush the database, stop
make dev, runpoetry run python manage.py flush, and startmake devagain.
In the last terminal you are ready to start the frontend. The frontend requires Node. You simply need to install the requirements and run the dev-server as follows.
# Install dependencies
$ yarn
# Start the dev-server
$ yarn devFinally, you can go to 127.0.0.1:5002 and view the admissions page.
NB: The project has to be accessed through 127.0.0.1, and NOT localhost. This is because accessing both LEGO and admissions from the same hostname creates a conflict some session storage, so the login will not work.
To create an admission, first, open 127.0.0.1:5002 and click the "Logg inn" button at the bottom of the page to authorize as a user with permission to create admissions. Then, click "Administrer opptak" and create an admission. Phew, now you are ready to start developing!
Â
The simplest way to create an admission is through the GUI.
- Navigate to 127.0.0.1:5002
- Log in as a user with permission to create admissions.
- Click "Administrer opptak" at the bottom of the screen
- Success
Currently when running
# Create a custom admission for development
$ poetry run python manage.py create_admissionyou create an admission connected to all groups, if they exist (they are generated the first time you log in). To connect it to a group, you can either do it through the GUI, or create it in the shell.
Note that when creating groups in the shell, you must import the Group model manually, as otherwise it will use the Django Group model instead of our own.
$ poetry run python manage.py shell_plus
> from admissions.admissions.models import Group
> new_group = Group.objects.create(name="GroupA")
> admission = Admission.objects.get(slug="opptak")
> admission.groups.add(new_group)Â
Interview schedules are produced by a constraint solver that can take a while on
large admissions, so solving runs in a separate worker process instead of
the web request. The frontend enqueues a SolveJob, the worker picks up pending
jobs and runs them, and the frontend polls for the result.
Each solve may search for up to five minutes. Easy cases still return as soon as an optimal plan is found; the limit only gives harder cases more time. Queue time is tracked separately and does not consume this search budget.
make dev starts the worker together with Django. If Django is started directly
with manage.py runserver, you must also run the worker — without it, solve jobs
stay PENDING forever.
# Only needed when Django was started without `make dev`
$ poetry run python manage.py run_solver_workerIn production, run this as a long-lived process/container next to the web server. A single instance is enough; jobs are claimed with row locks, so you can run more than one safely.
Â
The project gives permissions based on group memberships imported from LEGO.
The local membership snapshot is replaced atomically at OAuth login. LEGO role
changes are therefore not live within an existing session; for an urgent
revocation, invalidate that user's admissions session in addition to changing
the LEGO role. Production sessions expire after the configured
SESSION_COOKIE_AGE (one hour by default).
Candidate applications do not currently have an automatic post-admission retention deadline. A deployment must define an approved retention period and deletion procedure before treating storage cleanup as automatic. Solver jobs are cleaned separately and are not a substitute for deleting applications.
| Model | Action | Requirement |
|---|---|---|
| Admission | CREATE | Active Webkom member, or a staff user whose active LEGO role grants admission-management access |
| Admission | EDIT | Active Webkom member, or the admission creator when that creator is still a staff user |
| All applications | VIEW & DELETE | Active LEADER or RECRUITING member of a group in admission.admin_groups, or the Hovedstyret leader/co-leader in any admission |
| Applications to a group | VIEW & DELETE | Active member of a group in admission.groups with role LEADER or RECRUITING |
| Group | EDIT | Active LEADER or RECRUITING member of an admission admin group, or of the group itself |
Â
Run django tests using tox. Note that we point at the admissions database running at :5433 if we are running lego and admissions in parallel
$ DATABASE_PORT=5433 poetry run tox -e testsÂ
This codebase uses the PEP 8 code style. We enforce this with isort, black & flake8.
In addition to the standards outlined in PEP 8, we have a few guidelines
(see setup.cfg for more info):
Frontend colors, spacing, typography, control dimensions, and responsive breakpoints must use the shared tokens in frontend/src/styles/globals.css, frontend/src/styles/designTokens.ts, and tailwind.config.ts. Raw values are reserved for data-dependent grid arithmetic, one-pixel hairlines, intrinsic asset dimensions, and constraints that cannot consume CSS variables, such as media-query declarations. Reusable values must be promoted to a named token instead of repeated locally.
Format the code with black & isort
$ make fixmeTo check if it is formatted properly, run:
$ DATABASE_PORT=5433 poetry run tox -e isort -e flake8 -e black