Skip to content

Commit

Permalink
Add speaker availability support in the BE (#4188)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcoacierno authored Nov 30, 2024
1 parent 6d5c60e commit e8e1491
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 24 deletions.
10 changes: 0 additions & 10 deletions backend/api/grants/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
from typing import Optional

import strawberry
from api.participants.types import Participant
from participants.models import Participant as ParticipantModel

from grants.models import Grant as GrantModel

Expand Down Expand Up @@ -36,15 +34,8 @@ class Grant:
travelling_from: Optional[str]
applicant_reply_deadline: Optional[datetime]

participant: Participant

@classmethod
def from_model(cls, grant: GrantModel) -> Grant:
participant = ParticipantModel.objects.filter(
user_id=grant.user_id,
conference=grant.conference,
).first()

return cls(
id=grant.id,
status=Status(grant.status),
Expand All @@ -64,5 +55,4 @@ def from_model(cls, grant: GrantModel) -> Grant:
notes=grant.notes,
travelling_from=grant.travelling_from,
applicant_reply_deadline=grant.applicant_reply_deadline,
participant=Participant.from_model(participant),
)
3 changes: 3 additions & 0 deletions backend/api/participants/types.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Optional

from strawberry.scalars import JSON
import strawberry
from strawberry import ID

Expand All @@ -22,6 +23,7 @@ class Participant:
mastodon_handle: str
speaker_id: strawberry.Private[int]
fullname: str
speaker_availabilities: JSON

_speaker_level: strawberry.Private[str]
_previous_talk_video: strawberry.Private[str]
Expand Down Expand Up @@ -59,4 +61,5 @@ def from_model(cls, instance):
linkedin_url=instance.linkedin_url,
facebook_url=instance.facebook_url,
mastodon_handle=instance.mastodon_handle,
speaker_availabilities=instance.speaker_availabilities or {},
)
6 changes: 6 additions & 0 deletions backend/api/submissions/mutations.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from strawberry.scalars import JSON

from django.db import transaction
import math
import re
Expand Down Expand Up @@ -208,6 +210,7 @@ class SendSubmissionInput(BaseSubmissionInput):
speaker_linkedin_url: str
speaker_facebook_url: str
speaker_mastodon_handle: str
speaker_availabilities: JSON

topic: Optional[ID] = strawberry.field(default=None)
tags: list[ID] = strawberry.field(default_factory=list)
Expand Down Expand Up @@ -236,6 +239,7 @@ class UpdateSubmissionInput(BaseSubmissionInput):
speaker_linkedin_url: str
speaker_facebook_url: str
speaker_mastodon_handle: str
speaker_availabilities: JSON

topic: Optional[ID] = strawberry.field(default=None)
tags: list[ID] = strawberry.field(default_factory=list)
Expand Down Expand Up @@ -307,6 +311,7 @@ def update_submission(
"linkedin_url": input.speaker_linkedin_url,
"facebook_url": input.speaker_facebook_url,
"mastodon_handle": input.speaker_mastodon_handle,
"speaker_availabilities": input.speaker_availabilities,
},
)

Expand Down Expand Up @@ -368,6 +373,7 @@ def send_submission(
"linkedin_url": input.speaker_linkedin_url,
"facebook_url": input.speaker_facebook_url,
"mastodon_handle": input.speaker_mastodon_handle,
"speaker_availabilities": input.speaker_availabilities,
},
)

Expand Down
64 changes: 64 additions & 0 deletions backend/api/submissions/tests/test_edit_submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ def _update_submission(
new_speaker_linkedin_url="",
new_speaker_facebook_url="",
new_speaker_mastodon_handle="",
new_speaker_availabilities=None,
):
new_title = new_title or {"en": "new title to use"}
new_elevator_pitch = new_elevator_pitch or {"en": "This is an elevator pitch"}
new_abstract = new_abstract or {"en": "abstract here"}
short_social_summary = new_short_social_summary or ""
new_speaker_photo = new_speaker_photo or FileFactory().id
new_speaker_availabilities = new_speaker_availabilities or {}

return graphql_client.query(
"""
Expand Down Expand Up @@ -141,6 +143,7 @@ def _update_submission(
"speakerLinkedinUrl": new_speaker_linkedin_url,
"speakerFacebookUrl": new_speaker_facebook_url,
"speakerMastodonHandle": new_speaker_mastodon_handle,
"speakerAvailabilities": new_speaker_availabilities,
}
},
)
Expand Down Expand Up @@ -201,6 +204,67 @@ def test_update_submission(graphql_client, user):
assert participant.linkedin_url == "http://linkedin.com/company/pythonpizza"


def test_update_submission_speaker_availabilities(graphql_client, user):
conference = ConferenceFactory(
topics=("life", "diy"),
languages=("it", "en"),
durations=("10", "20"),
active_cfp=True,
audience_levels=("adult", "senior"),
submission_types=("talk", "workshop"),
)

submission = SubmissionFactory(
speaker_id=user.id,
custom_topic="life",
custom_duration="10m",
custom_audience_level="adult",
custom_submission_type="talk",
languages=["it"],
tags=["python", "ml"],
conference=conference,
speaker_level=Submission.SPEAKER_LEVELS.intermediate,
previous_talk_video="https://www.youtube.com/watch?v=SlPhMPnQ58k",
)

graphql_client.force_login(user)

new_topic = conference.topics.filter(name="diy").first()
new_audience = conference.audience_levels.filter(name="senior").first()
new_tag = SubmissionTagFactory(name="yello")
new_duration = conference.durations.filter(name="20m").first()
new_type = conference.submission_types.filter(name="workshop").first()

response = _update_submission(
graphql_client,
submission=submission,
new_topic=new_topic,
new_audience=new_audience,
new_tag=new_tag,
new_duration=new_duration,
new_type=new_type,
new_speaker_level=Submission.SPEAKER_LEVELS.experienced,
new_speaker_availabilities={
"2023-12-10@am": "unavailable",
"2023-12-11@pm": "unavailable",
"2023-12-12@am": "preferred",
"2023-12-13@am": None,
},
)

submission.refresh_from_db()

assert response["data"]["updateSubmission"]["__typename"] == "Submission"

participant = Participant.objects.first()
assert participant.speaker_availabilities == {
"2023-12-10@am": "unavailable",
"2023-12-11@pm": "unavailable",
"2023-12-12@am": "preferred",
"2023-12-13@am": None,
}


def test_update_submission_with_invalid_facebook_social_url(graphql_client, user):
conference = ConferenceFactory(
topics=("life", "diy"),
Expand Down
11 changes: 11 additions & 0 deletions backend/api/submissions/tests/test_send_submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def _submit_proposal(client, conference, submission, **kwargs):
"speakerFacebookUrl": "https://facebook.com/fake-link",
"speakerMastodonHandle": "fake@mastodon.social",
"tags": [tag.id],
"speakerAvailabilities": {},
}

override_conference = kwargs.pop("override_conference", None)
Expand Down Expand Up @@ -163,6 +164,11 @@ def test_submit_talk(graphql_client, user, django_capture_on_commit_callbacks, m
shortSocialSummary="summary",
speakerBio="my bio",
speakerPhoto=speaker_photo,
speakerAvailabilities={
"2023-10-10@am": "preferred",
"2023-10-11@pm": "unavailable",
"2023-10-12@am": "available",
},
)

assert resp["data"]["sendSubmission"]["__typename"] == "Submission"
Expand Down Expand Up @@ -190,6 +196,11 @@ def test_submit_talk(graphql_client, user, django_capture_on_commit_callbacks, m
participant = Participant.objects.get(conference=conference, user_id=user.id)
assert participant.bio == "my bio"
assert participant.photo_file_id == speaker_photo
assert participant.speaker_availabilities == {
"2023-10-10@am": "preferred",
"2023-10-11@pm": "unavailable",
"2023-10-12@am": "available",
}

assert PrivacyPolicyAcceptanceRecord.objects.filter(
user=user, conference=conference, privacy_policy="cfp"
Expand Down
16 changes: 2 additions & 14 deletions backend/participants/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,7 @@
class ParticipantForm(forms.ModelForm):
class Meta:
model = Participant
fields = [
"conference",
"user",
"photo",
"bio",
"website",
"twitter_handle",
"instagram_handle",
"linkedin_url",
"facebook_url",
"mastodon_handle",
"speaker_level",
"previous_talk_video",
]
fields = "__all__"


@admin.register(Participant)
Expand Down Expand Up @@ -54,6 +41,7 @@ class ParticipantAdmin(admin.ModelAdmin):
"mastodon_handle",
"speaker_level",
"previous_talk_video",
"speaker_availabilities",
),
},
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.1 on 2024-11-28 22:08

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('participants', '0011_alter_participant_photo'),
]

operations = [
migrations.AddField(
model_name='participant',
name='speaker_availabilities',
field=models.JSONField(blank=True, null=True, verbose_name='speaker availabilities'),
),
]
3 changes: 3 additions & 0 deletions backend/participants/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ class SpeakerLevels(models.TextChoices):
previous_talk_video = models.URLField(
_("previous talk video"), blank=True, max_length=2049
)
speaker_availabilities = models.JSONField(
_("speaker availabilities"), null=True, blank=True
)

objects = ParticipantQuerySet().as_manager()

Expand Down

0 comments on commit e8e1491

Please sign in to comment.