diff --git a/backend/samfundet/migrations/0010_recruitment_promo_media.py b/backend/samfundet/migrations/0010_recruitment_promo_media.py new file mode 100644 index 000000000..8aa5e3431 --- /dev/null +++ b/backend/samfundet/migrations/0010_recruitment_promo_media.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.1 on 2024-10-31 19:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('samfundet', '0009_recruitmentpositionsharedinterviewgroup_name_en_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='recruitment', + name='promo_media', + field=models.CharField(blank=True, default=None, help_text='Youtube video id', max_length=11, null=True), + ), + ] diff --git a/backend/samfundet/models/recruitment.py b/backend/samfundet/models/recruitment.py index 20dbd2037..514fcda9d 100644 --- a/backend/samfundet/models/recruitment.py +++ b/backend/samfundet/models/recruitment.py @@ -31,6 +31,7 @@ class Recruitment(CustomBaseModel): organization = models.ForeignKey(null=False, blank=False, to=Organization, on_delete=models.CASCADE, help_text='The organization that is recruiting') max_applications = models.PositiveIntegerField(null=True, blank=True, verbose_name='Max applications per applicant') + promo_media = models.CharField(max_length=11, help_text='Youtube video id', null=True, default=None, blank=True) def resolve_org(self, *, return_id: bool = False) -> Organization | int: if return_id: diff --git a/backend/samfundet/serializers.py b/backend/samfundet/serializers.py index 94da3771c..3e8488380 100644 --- a/backend/samfundet/serializers.py +++ b/backend/samfundet/serializers.py @@ -1,5 +1,6 @@ from __future__ import annotations +import re import itertools from typing import TYPE_CHECKING from collections import defaultdict @@ -739,11 +740,22 @@ class Meta: class RecruitmentSerializer(CustomBaseSerializer): separate_positions = RecruitmentSeparatePositionSerializer(many=True, read_only=True) + promo_media = serializers.CharField(max_length=100, allow_blank=True, allow_null=True) class Meta: model = Recruitment fields = '__all__' + def validate_promo_media(self, value: str | None) -> str | None: + if value is None or value == '': + return None + match = re.search(r'(youtu.*be.*)\/(watch\?v=|embed\/|v|shorts|)(.*?((?=[&#?])|$))', value) + if match: + return match.group(3) + if len(value) == 11: + return value + raise ValidationError('Invalid youtube url') + def to_representation(self, instance: Recruitment) -> dict: data = super().to_representation(instance) data['organization'] = OrganizationSerializer(instance.organization).data diff --git a/frontend/src/Pages/OrganizationRecruitmentPage/OrganizationRecruitmentPage.tsx b/frontend/src/Pages/OrganizationRecruitmentPage/OrganizationRecruitmentPage.tsx index efae692f0..8d2479493 100644 --- a/frontend/src/Pages/OrganizationRecruitmentPage/OrganizationRecruitmentPage.tsx +++ b/frontend/src/Pages/OrganizationRecruitmentPage/OrganizationRecruitmentPage.tsx @@ -16,7 +16,6 @@ import styles from './OrganizationRecruitmentPage.module.scss'; export function OrganizationRecruitmentPage() { const isDesktop = useDesktop(); - const embededId = '-nYQb8_TvQ4'; // TODO: Make this dynamic DO IN ISSUE #1121 for backend. #1274 for frontend const { recruitmentId } = useParams<{ recruitmentId: string }>(); const [viewAllPositions, setViewAllPositions] = useState(true); const { t } = useTranslation(); @@ -77,9 +76,9 @@ export function OrganizationRecruitmentPage() { {dbT(recruitment, 'name')} - {embededId ? ( + {recruitment?.promo_media ? ( <> -