Skip to content

Commit

Permalink
feat(program_v2): rename otherFields to annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
japsu committed Jun 16, 2024
1 parent be8982a commit 97ba84e
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 57 deletions.
30 changes: 3 additions & 27 deletions backend/program_v2/graphql/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
from graphene_django import DjangoObjectType

from graphql_api.language import DEFAULT_LANGUAGE
from graphql_api.utils import get_message_in_language, resolve_localized_field
from graphql_api.utils import resolve_localized_field

from ..models.dimension import Dimension, DimensionValue, ProgramDimensionValue, ValueOrdering
from ..models.dimension import Dimension, DimensionValue, ProgramDimensionValue

# class ValueOrdering(graphene.Enum):
# DEFAULT = "default"
Expand All @@ -25,9 +25,6 @@ class Meta:
)


ValueOrderingType = graphene.Enum.from_enum(ValueOrdering)


class DimensionType(DjangoObjectType):
title = graphene.String(lang=graphene.String())
resolve_title = resolve_localized_field("title")
Expand All @@ -37,37 +34,16 @@ def resolve_values(
dimension: Dimension,
info,
lang: str = DEFAULT_LANGUAGE,
value_ordering: ValueOrdering | None = None, # type: ignore
):
"""
Get values of a dimension, ordered according to the dimension's `value_ordering`.
NOTE: In order to get the ordering in the correct language, the language needs to be provided.
"""
# XXX pyrekt does not rektify graphene.Enum

dimensions = dimension.values.all()
value_ordering_fmh = dimension.value_ordering if value_ordering is None else value_ordering.value

print("value_ordering_fmh", value_ordering_fmh)

match value_ordering_fmh:
case "manual":
dimensions = dimensions.order_by("order")
case "slug":
dimensions = dimensions.order_by("slug")
case "title":

def key_func(value: DimensionValue) -> str:
return get_message_in_language(value.title, lang) or value.slug

dimensions = sorted(dimensions, key=key_func)

return dimensions
return dimension.get_values(lang)

values = graphene.NonNull(
graphene.List(graphene.NonNull(DimensionValueType)),
lang=graphene.String(),
value_ordering=ValueOrderingType(),
)

class Meta:
Expand Down
30 changes: 21 additions & 9 deletions backend/program_v2/graphql/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def from_program(
"""
link_type_str = link_type.value # type: ignore[attr-defined]
title_specifier = ""
link_other_field = f"internal:links:{link_type_str.lower()}"
link_annotation = f"internal:links:{link_type_str.lower()}"

match link_type:
case ProgramLinkType.CALENDAR:
Expand All @@ -101,21 +101,21 @@ def from_program(
if not include_expired and program.cached_latest_end_time and now() > program.cached_latest_end_time:
href = ""
else:
href = program.other_fields.get(link_other_field, "")
href = program.annotations.get(link_annotation, "")
case ProgramLinkType.FEEDBACK:
# Do not show feedback link if the program has not started yet
if program.cached_earliest_start_time and now() < program.cached_earliest_start_time:
href = ""
else:
href = program.other_fields.get(link_other_field, "")
href = program.annotations.get(link_annotation, "")
case _:
href = program.other_fields.get(link_other_field, "")
href = program.annotations.get(link_annotation, "")

if not href:
return None

titles = get_message_in_language(DEFAULT_TITLES, language) or {}
title = program.other_fields.get(
title = program.annotations.get(
f"{link_type_str.lower()}",
titles.get(link_type_str, ""),
)
Expand All @@ -135,7 +135,7 @@ class ProgramType(DjangoObjectType):

@staticmethod
def resolve_cached_hosts(parent: Program, info):
return parent.other_fields.get("internal:formattedHosts", "")
return parent.annotations.get("internal:formattedHosts", "")

cached_hosts = graphene.NonNull(graphene.String)

Expand Down Expand Up @@ -225,19 +225,31 @@ def resolve_calendar_export_link(program: Program, info):
)

@staticmethod
def resolve_other_fields(parent: Program, info):
def resolve_annotations(parent: Program, info):
"""
Additional fields for the program.
NOTE: For most use cases, you shouldn't use this field
but rather access its data via formattedHosts, links etc.
but rather access its data via cachedHosts, links etc.
This is here mostly to facilitate the GraphQL importer.
TODO: Provide a way to supply internal: fields to the GraphQL importer.
Perhaps make the importer authenticate?
"""

return {k: v for (k, v) in parent.other_fields.items() if v and not k.startswith("internal:")}
return {k: v for (k, v) in parent.annotations.items() if v and not k.startswith("internal:")}

annotations = graphene.NonNull(
GenericScalar,
description=normalize_whitespace(resolve_annotations.__doc__ or ""),
)

@staticmethod
def resolve_other_fields(parent: Program, info):
"""
Deprecated. Use `annotations` instead.
"""
return ProgramType.resolve_annotations(parent, info)

other_fields = graphene.NonNull(
GenericScalar,
Expand Down
6 changes: 3 additions & 3 deletions backend/program_v2/importers/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ def get_end_time(self, programme: Programme) -> datetime:
return self.get_start_time(programme) + self.get_length(programme)

program_unique_fields = ("event", "slug")
program_update_fields = ("title", "description", "other_fields")
program_update_fields = ("title", "description", "annotations")

def get_other_fields(self, programme: Programme) -> dict[str, str]:
def get_annotations(self, programme: Programme) -> dict[str, str]:
return {
"internal:formattedHosts": programme.formatted_hosts,
"internal:links:signup": programme.signup_link,
Expand All @@ -174,7 +174,7 @@ def get_program(self, programme: Programme) -> Program:
slug=programme.slug,
title=programme.title,
description=programme.description,
other_fields={k: v for (k, v) in self.get_other_fields(programme).items() if v},
annotations={k: v for (k, v) in self.get_annotations(programme).items() if v},
)

def get_schedule_items(self, v1_programme: Programme, v2_program) -> list[ScheduleItem]:
Expand Down
6 changes: 3 additions & 3 deletions backend/program_v2/importers/graphql.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
slug
title
description
otherFields
annotations
cachedDimensions
scheduleItems {
startTime
Expand Down Expand Up @@ -98,13 +98,13 @@ def import_graphql(
slug=program_data["slug"],
title=program_data["title"],
description=program_data["description"],
other_fields=program_data["otherFields"],
annotations=program_data["annotations"],
)
for program_data in data["data"]["event"]["program"]["programs"]
],
update_conflicts=True,
unique_fields=["event", "slug"],
update_fields=["title", "description", "other_fields"],
update_fields=["title", "description", "annotations"],
)
logger.info("Imported %d programs for %s", len(programs), event.slug)

Expand Down
10 changes: 5 additions & 5 deletions backend/program_v2/importers/ropecon2024.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,15 +376,15 @@ def get_program_dimension_values(self, programme: Programme) -> dict[str, list[s

return values

def get_other_fields(self, programme: Programme) -> dict[str, str]:
other_fields = super().get_other_fields(programme)
def get_annotations(self, programme: Programme) -> dict[str, str]:
annotations = super().get_annotations(programme)
dimension_values = self.get_program_dimension_values(programme)

is_konsti = len(dimension_values.get("konsti", [])) > 0
if is_konsti:
other_fields["internal:links:signup"] = f"https://ropekonsti.fi/program/item/{programme.slug}"
annotations["internal:links:signup"] = f"https://ropekonsti.fi/program/item/{programme.slug}"

other_fields.update(
annotations.update(
**{
"konsti:rpgSystem": programme.rpg_system,
"ropecon:otherAuthor": programme.other_author,
Expand All @@ -397,4 +397,4 @@ def get_other_fields(self, programme: Programme) -> dict[str, str]:
}
)

return other_fields
return annotations
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.0.6 on 2024-06-16 09:09

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("program_v2", "0017_alter_dimension_options_alter_dimensionvalue_options_and_more"),
]

operations = [
migrations.RenameField(
model_name="program",
old_name="other_fields",
new_name="annotations",
),
]
19 changes: 19 additions & 0 deletions backend/program_v2/models/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from django.db import models

from core.utils import validate_slug
from core.utils.locale_utils import get_message_in_language
from graphql_api.language import DEFAULT_LANGUAGE

from .program import Program

Expand Down Expand Up @@ -84,6 +86,23 @@ def dump_dimensions(cls, event: Event):
for value in dimension.values.all():
print("-", value)

def get_values(self, lang: str = DEFAULT_LANGUAGE) -> list[DimensionValue]:
"""
Use this method instead of self.values.all() when you want the values in the correct order.
NOTE: If value_ordering is TITLE, you need to provide the language.
"""
values = self.values.all()

match self.value_ordering:
case "manual":
return list(values.order_by("order"))
case "slug":
return list(values.order_by("slug"))
case "title":
return sorted(values, key=lambda value: get_message_in_language(value.title, lang) or value.slug)
case _:
raise NotImplementedError(f"Unknown value_ordering: {self.value_ordering}")


class DimensionValue(models.Model):
dimension = models.ForeignKey(Dimension, on_delete=models.CASCADE, related_name="values")
Expand Down
2 changes: 1 addition & 1 deletion backend/program_v2/models/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Program(models.Model):
title = models.CharField(max_length=1023)
slug = models.CharField(max_length=1023, validators=[validate_slug])
description = models.TextField(blank=True)
other_fields = models.JSONField(blank=True, default=dict)
annotations = models.JSONField(blank=True, default=dict)

favorited_by = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="favorite_programs", blank=True)

Expand Down
12 changes: 3 additions & 9 deletions frontend/src/__generated__/graphql.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 97ba84e

Please sign in to comment.