Skip to content

Commit

Permalink
Merge branch 'master' into robin/redesign-imagecard
Browse files Browse the repository at this point in the history
  • Loading branch information
robines authored Oct 16, 2023
2 parents 35a054f + 7ee78a8 commit 220ebcb
Show file tree
Hide file tree
Showing 54 changed files with 23,170 additions and 17,883 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @emilte @evgiz
* @emilte @evgiz @Mathias-a
21 changes: 11 additions & 10 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,26 @@ jobs:
- name: Check yapf
run: python -m pipenv run yapf --parallel --recursive --diff .

# TODO: broken test - https://github.com/Samfundet/Samfundet4/issues/730
- name: Verify migrations
run: |
python -m pipenv run python manage.py makemigrations --check --dry-run --noinput --verbosity 2
python -m pipenv run python manage.py migrate --verbosity 2
python -m pipenv run migrations:verify
python -m pipenv run migrations:apply
- name: Run tests
run: python -m pipenv run pytest
run: python -m pipenv run pytest:run

- name: Run bandit
run: python -m pipenv run bandit --recursive --ini .bandit .
run: python -m pipenv run bandit:run

- name: Run flake8
run: python -m pipenv run flake8 --config=.flake8 .
run: python -m pipenv run flake8:run

- name: Run mypy
run: python -m pipenv run mypy --config-file mypy.ini .
run: python -m pipenv run mypy:run

- name: Run seeds
run: python -m pipenv run python manage.py seed
run: python -m pipenv run seed:run

job_verify_docker:
name: Verify docker
Expand All @@ -94,10 +95,10 @@ jobs:
echo VITE_CYPRESS_BASE_URL=http://frontend:3000 >> frontend/.env.docker
- name: Build images
run: docker compose build
run: docker compose build backend frontend storybook

- name: Start containers
run: docker compose up -d; sleep 20 # Give additional seconds to boot.
run: docker compose up backend frontend storybook -d; sleep 20 # Give additional seconds to boot.

- name: Check running containers
# Will fail if container isn't running.
Expand All @@ -113,7 +114,7 @@ jobs:
# run: docker compose up cypress

- name: Stop containers
run: docker compose down
run: docker compose down

job_verify_frontend_lint:
name: Verify frontend
Expand Down
2 changes: 2 additions & 0 deletions backend/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
.env
**/.history
*.sqlite3
Dockerfile
.dockerignore
2 changes: 2 additions & 0 deletions backend/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ name = "pypi"
"pipenv:rm" = "pipenv --rm" # Completely remove virtual environment.
"pipenv:shell" = "pipenv shell" # Opens a shell within the virtual environment.
"mypy:run" = "pipenv run mypy --config-file mypy.ini ."
"migrations:make" = "pipenv run python manage.py makemigrations --noinput"
"migrations:verify" = "pipenv run python manage.py makemigrations --check --dry-run --noinput --verbosity 2"
"migrations:apply" = "pipenv run python manage.py migrate"
"bandit:run" = "pipenv run bandit --recursive --ini .bandit ."
"flake8:run" = "pipenv run flake8 --config=.flake8 ."
"yapf:diff" = "pipenv run yapf --parallel --recursive --diff ." # Dry-run yapf on all files in the project.
Expand Down
659 changes: 330 additions & 329 deletions backend/Pipfile.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions backend/root/management/commands/seed_cypress.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def handle(self, *args, **options):

Venue.objects.create(
name='Cypress Area',
slug='cypress-area',
description='Some description',
floor=1,
last_renovated=timezone.now(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.utils.text import slugify

from root.utils.samfundet_random import words

from samfundet.models.general import InformationPage
Expand All @@ -14,7 +16,7 @@ def seed():
for i in range(COUNT):
# Event title and time
title_nb, title_en = words(2, include_english=True)
slug_field = title_nb.lower().replace(' ', '-')
slug_field = slugify(title_nb)

# Make sure slug field is unique
if slug_field in used_slug_fields:
Expand Down
20 changes: 12 additions & 8 deletions backend/root/management/commands/seed_scripts/recruitment.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,27 @@ def seed():

total_recruitments = len(recruitments) * len(organizations)
created_recruitments = 0
recruitment_objects = []

for org_name in organizations:
org = Organization.objects.get(name=org_name)
for recruitment_data in recruitments:
Recruitment.objects.get_or_create(
recruitment_instance = Recruitment(
name_nb=recruitment_data['name_nb'],
name_en=recruitment_data['name_en'],
organization=org,
defaults={
'visible_from': recruitment_data['visible_from'],
'shown_application_deadline': recruitment_data['shown_application_deadline'],
'actual_application_deadline': recruitment_data['actual_application_deadline'],
'reprioritization_deadline_for_applicant': recruitment_data['reprioritization_deadline_for_applicant'],
'reprioritization_deadline_for_groups': recruitment_data['reprioritization_deadline_for_groups'],
}
visible_from=recruitment_data['visible_from'],
shown_application_deadline=recruitment_data['shown_application_deadline'],
actual_application_deadline=recruitment_data['actual_application_deadline'],
reprioritization_deadline_for_applicant=recruitment_data['reprioritization_deadline_for_applicant'],
reprioritization_deadline_for_groups=recruitment_data['reprioritization_deadline_for_groups']
)
recruitment_objects.append(recruitment_instance)

created_recruitments += 1
yield (created_recruitments / total_recruitments) * 100, 'recruitment'

# Using bulk_create to add all recruitment instances to the database
Recruitment.objects.bulk_create(recruitment_objects)

yield 100, f'Created {created_recruitments} recruitments'
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
ADMISSION_DATA = {
'admission_text': 'This is the admission text',
'applicant_priority': 0,
'interview_time': None,
'interview_location': None,
'recruiter_priority': 0,
'recruiter_status': 0
'recruiter_status': 0,
}


Expand Down
11 changes: 11 additions & 0 deletions backend/root/utils/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,14 @@ def from_db(cls, db, field_names, values): # type: ignore # noqa: ANN001,ANN206
setattr(instance, instance._FTM_LOADED_FIELDS_NAME, loaded_fields) # noqa: FKA01

return instance


class FullCleanSaveMixin(Model):
"""Mixin to call full_clean() before save()."""

class Meta:
abstract = True

def save(self, *args: Any, **kwargs: Any) -> None:
self.full_clean()
super().save(*args, **kwargs)
22 changes: 15 additions & 7 deletions backend/samfundet/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
CustomGuardedModelAdmin,
)
from .models.event import (Event, EventGroup, EventRegistration)
from .models.recruitment import (Recruitment, RecruitmentPosition, RecruitmentAdmission, InterviewRoom)
from .models.recruitment import (
Recruitment,
RecruitmentPosition,
RecruitmentAdmission,
InterviewRoom,
Interview,
)
from .models.general import (
Tag,
User,
Expand Down Expand Up @@ -536,24 +542,18 @@ class RecruitmentAdmissionAdmin(CustomGuardedModelAdmin):
'id',
'recruitment_position',
'recruitment',
'interview_time',
'interview_location',
'user',
]
list_display = [
'id',
'recruitment_position',
'recruitment',
'interview_time',
'interview_location',
'user',
]
search_fields = [
'id',
'recruitment_position',
'recruitment',
'interview_time',
'interview_location',
'user',
]
list_select_related = True
Expand All @@ -576,4 +576,12 @@ class InterviewRoomAdmin(CustomGuardedModelAdmin):
list_select_related = ['recruitment', 'gang']


@admin.register(Interview)
class InterviewAdmin(CustomGuardedModelAdmin):
list_filter = ['id', 'notes']
list_display = ['id', 'notes']
search_fields = ['id', 'notes']
list_display_links = ['id', 'notes']


### End: Our models ###
13 changes: 12 additions & 1 deletion backend/samfundet/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from samfundet.models.billig import BilligEvent
from samfundet.models.event import Event, EventAgeRestriction, EventTicketType
from samfundet.models.recruitment import Recruitment, RecruitmentPosition, RecruitmentAdmission
from samfundet.models.general import User, Image, InformationPage, Organization, Gang, BlogPost
from samfundet.models.general import User, Image, InformationPage, Organization, Gang, BlogPost, TextItem

import root.management.commands.seed_scripts.billig as billig_seed
"""
Expand Down Expand Up @@ -193,6 +193,17 @@ def fixture_gang(fixture_organization: Organization) -> Iterator[Gang]:
organization.delete()


@pytest.fixture
def fixture_text_item() -> Iterator[TextItem]:
text_item = TextItem.objects.create(
key='foo',
text_nb='foo',
text_en='foo',
)
yield text_item
text_item.delete()


@pytest.fixture
def fixture_recruitment(fixture_organization: Organization) -> Iterator[Recruitment]:
now = timezone.now()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Generated by Django 4.2.3 on 2023-10-07 22:02

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


class Migration(migrations.Migration):

dependencies = [
('samfundet', '0038_alter_recruitmentadmission_interview_location_and_more'),
]

operations = [
migrations.RemoveField(
model_name='recruitmentadmission',
name='interview_location',
),
migrations.RemoveField(
model_name='recruitmentadmission',
name='interview_time',
),
migrations.RemoveField(
model_name='recruitmentadmission',
name='room',
),
migrations.AddField(
model_name='recruitmentposition',
name='shared_interview_positions',
field=models.ManyToManyField(blank=True, help_text='Positions with shared interview', to='samfundet.recruitmentposition'),
),
migrations.AlterField(
model_name='recruitmentposition',
name='interviewers',
field=models.ManyToManyField(blank=True, help_text='Interviewers for the position', related_name='interviewers', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel(
name='Interview',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('interview_time', models.DateTimeField(blank=True, help_text='The time of the interview', null=True)),
('interview_location', models.CharField(blank=True, help_text='The location of the interview', max_length=255, null=True)),
('notes', models.TextField(blank=True, help_text='Notes for the interview', null=True)),
('room', models.ForeignKey(blank=True, help_text='Room where the interview is held', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interviews', to='samfundet.interviewroom')),
],
),
migrations.AddField(
model_name='recruitmentadmission',
name='interview',
field=models.ForeignKey(blank=True, help_text='The interview for the admission', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='admissions', to='samfundet.interview'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Generated by Django 4.2.6 on 2023-10-14 04:06

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import jsonfield.fields


class Migration(migrations.Migration):

dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('samfundet', '0039_remove_recruitmentadmission_interview_location_and_more'),
]

operations = [
migrations.AlterModelOptions(
name='notification',
options={'ordering': ('-timestamp',), 'verbose_name': 'Notification', 'verbose_name_plural': 'Notifications'},
),
migrations.AlterField(
model_name='notification',
name='action_object_content_type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notify_action_object', to='contenttypes.contenttype', verbose_name='action object content type'),
),
migrations.AlterField(
model_name='notification',
name='action_object_object_id',
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='action object object id'),
),
migrations.AlterField(
model_name='notification',
name='actor_content_type',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notify_actor', to='contenttypes.contenttype', verbose_name='actor content type'),
),
migrations.AlterField(
model_name='notification',
name='actor_object_id',
field=models.CharField(max_length=255, verbose_name='actor object id'),
),
migrations.AlterField(
model_name='notification',
name='data',
field=jsonfield.fields.JSONField(blank=True, null=True, verbose_name='data'),
),
migrations.AlterField(
model_name='notification',
name='deleted',
field=models.BooleanField(db_index=True, default=False, verbose_name='deleted'),
),
migrations.AlterField(
model_name='notification',
name='description',
field=models.TextField(blank=True, null=True, verbose_name='description'),
),
migrations.AlterField(
model_name='notification',
name='emailed',
field=models.BooleanField(db_index=True, default=False, verbose_name='emailed'),
),
migrations.AlterField(
model_name='notification',
name='level',
field=models.CharField(choices=[('success', 'success'), ('info', 'info'), ('warning', 'warning'), ('error', 'error')], default='info', max_length=20, verbose_name='level'),
),
migrations.AlterField(
model_name='notification',
name='public',
field=models.BooleanField(db_index=True, default=True, verbose_name='public'),
),
migrations.AlterField(
model_name='notification',
name='recipient',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL, verbose_name='recipient'),
),
migrations.AlterField(
model_name='notification',
name='target_content_type',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notify_target', to='contenttypes.contenttype', verbose_name='target content type'),
),
migrations.AlterField(
model_name='notification',
name='target_object_id',
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='target object id'),
),
migrations.AlterField(
model_name='notification',
name='timestamp',
field=models.DateTimeField(db_index=True, default=django.utils.timezone.now, verbose_name='timestamp'),
),
migrations.AlterField(
model_name='notification',
name='unread',
field=models.BooleanField(db_index=True, default=True, verbose_name='unread'),
),
migrations.AlterField(
model_name='notification',
name='verb',
field=models.CharField(max_length=255, verbose_name='verb'),
),
]
Loading

0 comments on commit 220ebcb

Please sign in to comment.