Skip to content

Commit

Permalink
Merge pull request #396 from con2/feat/create-dimension
Browse files Browse the repository at this point in the history
Embetter survey dimensions
  • Loading branch information
japsu committed Jan 28, 2024
2 parents 24945a8 + ffd2aa6 commit 62aba4a
Show file tree
Hide file tree
Showing 32 changed files with 1,407 additions and 158 deletions.
21 changes: 21 additions & 0 deletions backend/events/tracon2024/forms/expense-claim-dimensions.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
- slug: event
title:
fi: Tapahtuma
en: Event
is_key_dimension: true
is_shown_to_respondent: true
choices:
- slug: tracon2024
title:
fi: Tracon 2024
en: Tracon 2024
- slug: hitpoint2024
title:
fi: Tracon Hitpoint 2024
en: Tracon Hitpoint 2024
- slug: no-event
title:
fi: Maksu ei liity tapahtumaan
en: The payment is not related to an event

- slug: type
title:
fi: Maksun tyyppi
Expand All @@ -24,6 +44,7 @@
fi: Maksun tila
en: Payment status
is_key_dimension: true
is_shown_to_respondent: true
choices:
- slug: new
color: blue
Expand Down
35 changes: 2 additions & 33 deletions backend/events/tracon2024/forms/expense-claim-fi.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,13 @@
title: Hae kulukorvausta
layout: vertical
description: |
Tällä lomakkeella voit hakea kulukorvausta <strong>vuoden 2024 Traconiin liittyvistä kuluista</strong>,
Tällä lomakkeella voit hakea kulukorvausta Tracon ry:ltä tapahtumaan tai yhdistystoimintaan liittyvästä kulusta,
lähettää Tracon ry:lle laskun tai toimittaa Tracon ry:n pankkikortilla maksetun kulun kuitin.
Täytä lomake huolellisesti ja liitä mukaan kaikki pyydetyt liitteet.
Jos haet kulukorvausta <strong>vuoden 2024 Tracon Hitpoint -tapahtumaan</strong> liittyvistä kuluista,
käytä <a href="/events/hitpoint2024/surveys/expense-claim">Hitpointin kulukorvauslomaketta</a>.
Jos haet kulukorvausta <strong>kulusta, joka ei liity suoraan kumpaankaan tapahtumaan</strong>,
käytä <a href="/events/tracon2024/surveys/expense-claim-traconry-temp">yleistä kulukorvauslomaketta</a>.
Jos sinulla on kysyttävää kulukorvauksista, ota yhteyttä Tracon ry:n rahastonhoitajaan sähköpostitse
osoitteella <em>rahat ät tracon piste fi</em> tai Slackissa <em>@Aketzu</em>.
fields:
- slug: type
type: SingleSelect
title: Kulukorvauksen tyyppi
helpText: |
<strong>Tilisiirto:</strong> Olet maksanut kulun itse ja haet korvausta tilisiirtona.<br/>
<strong>Lasku:</strong> Laskuttaja on lähettänyt Tracon ry:lle laskun, joka maksetaan suoraan laskuttajalle.<br/>
<strong>Korttimaksu:</strong> Olet maksanut kulun Tracon ry:n pankkikortilla. Kirjoita saajan tilinumero -kenttään "-" (viiva).
required: true
choicesFrom:
dimension: type

- slug: title
type: SingleLineText
title: Otsikko
Expand All @@ -49,9 +32,9 @@ fields:
- slug: recipient
type: SingleLineText
title: Saaja
required: true
helpText: |
Kenen tilille korvaus maksetaan? Kirjoita tähän etu- ja sukunimi tai yrityksen nimi.
Jos korvaus maksetaan omalle tilillesi, voit jättää tämän kentän tyhjäksi.
- slug: recipient_iban
type: SingleLineText
Expand All @@ -60,20 +43,6 @@ fields:
helpText: |
Mille tilille korvaus maksetaan? Kirjoita IBAN-tilinumero muodossa FI12 3456 7890 1234 56.
- slug: recipient_bic
type: SingleLineText
title: Saajan pankin SWIFT/BIC-koodi
helpText: |
Minkä pankin tilille korvaus maksetaan? Kirjoita pankin SWIFT/BIC-koodi (esim. HOLVFIHH tai NDEAFIHH).
Jos saajan tili on suomalaisessa pankissa eli tilinumero alkaa FI, voit jättää tämän kentän tyhjäksi.
- slug: reference_number
type: SingleLineText
title: Viitenumero
helpText: |
Jos kulukorvaukseen liittyy lasku jolla on viitenumero, kirjoita se tähän.
Muutoin voit jättää tämän kentän tyhjäksi.
- slug: attachments
type: FileUpload
title: Tositteet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,7 @@ def setup_forms(self):
slug="expense-claim",
defaults=dict(
active_from=now(),
key_fields=["title"],
key_fields=["title", "amount"],
login_required=True,
anonymity="NAME_AND_EMAIL",
),
Expand Down
6 changes: 3 additions & 3 deletions backend/forms/graphql/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from ..models.meta import FormsEventMeta, FormsProfileMeta
from ..models.response import Response
from ..models.survey import Survey
from .response import FullResponseType
from .response import ProfileResponseType
from .survey import SurveyType

DEFAULT_LANGUAGE: str = settings.LANGUAGE_CODE
Expand Down Expand Up @@ -51,7 +51,7 @@ def resolve_responses(meta: FormsProfileMeta, info):

responses = graphene.NonNull(
graphene.List(
graphene.NonNull(FullResponseType),
graphene.NonNull(ProfileResponseType),
),
description=normalize_whitespace(resolve_responses.__doc__ or ""),
)
Expand All @@ -66,7 +66,7 @@ def resolve_response(meta: FormsProfileMeta, info, id: int):
return Response.objects.get(created_by=meta.person.user, id=id)

response = graphene.Field(
FullResponseType,
ProfileResponseType,
id=graphene.String(required=True),
description=normalize_whitespace(resolve_response.__doc__ or ""),
)
38 changes: 38 additions & 0 deletions backend/forms/graphql/mutations/create_survey_dimension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import graphene
from graphene.types.generic import GenericScalar

from access.cbac import graphql_check_access

from ...models.dimension import DimensionDTO
from ...models.survey import Survey
from ..dimension import SurveyDimensionType


class CreateSurveyDimensionInput(graphene.InputObjectType):
event_slug = graphene.String(required=True)
survey_slug = graphene.String(required=True)
form_data = GenericScalar(required=True)


class CreateSurveyDimension(graphene.Mutation):
class Arguments:
input = CreateSurveyDimensionInput(required=True)

dimension = graphene.Field(SurveyDimensionType)

@staticmethod
def mutate(
root,
info,
input: CreateSurveyDimensionInput,
):
survey = Survey.objects.get(event__slug=input.event_slug, slug=input.survey_slug)

# TODO bastardization of graphql_check_access, rethink
graphql_check_access(survey, info, "dimensions", "mutation")

form_data: dict[str, str] = input.form_data # type: ignore
print(form_data)
dimension = DimensionDTO.from_form_data(form_data).save(survey)

return CreateSurveyDimension(dimension=dimension) # type: ignore
4 changes: 2 additions & 2 deletions backend/forms/graphql/mutations/create_survey_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from ...models.response import Response
from ...models.survey import Survey
from ..response import FullResponseType
from ..response import ProfileResponseType


class CreateSurveyResponseInput(graphene.InputObjectType):
Expand All @@ -19,7 +19,7 @@ class CreateSurveyResponse(graphene.Mutation):
class Arguments:
input = CreateSurveyResponseInput(required=True)

response = graphene.Field(FullResponseType)
response = graphene.Field(ProfileResponseType)

@staticmethod
def mutate(
Expand Down
36 changes: 36 additions & 0 deletions backend/forms/graphql/mutations/delete_survey_dimension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import graphene

from access.cbac import graphql_check_access

from ...models.survey import Survey


class DeleteSurveyDimensionInput(graphene.InputObjectType):
event_slug = graphene.String(required=True)
survey_slug = graphene.String(required=True)
dimension_slug = graphene.String(required=True)


class DeleteSurveyDimension(graphene.Mutation):
class Arguments:
input = DeleteSurveyDimensionInput(required=True)

slug = graphene.Field(graphene.String)

@staticmethod
def mutate(
root,
info,
input: DeleteSurveyDimensionInput,
):
survey = Survey.objects.get(event__slug=input.event_slug, slug=input.survey_slug)

# TODO bastardization of graphql_check_access, rethink
graphql_check_access(survey, info, "dimensions", "mutation")

# TODO can_delete

dimension = survey.dimensions.get(slug=input.dimension_slug)
dimension.delete()

return DeleteSurveyDimension(slug=input.survey_slug) # type: ignore
68 changes: 68 additions & 0 deletions backend/forms/graphql/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,71 @@ class Meta:
"form_data",
"created_at",
)


class ProfileResponseType(LimitedResponseType):
@staticmethod
def resolve_form(parent: Response, info):
return parent.form

form = graphene.Field(graphene.NonNull(FormType))

@staticmethod
def resolve_dimensions(parent: Response, info, key_dimensions_only: bool = False):
"""
The respondent will only see values of dimensions that are designated as
being shown to the respondent.
"""
qs = parent.dimensions.filter(dimension__is_shown_to_respondent=True)

if key_dimensions_only:
qs = qs.filter(dimension__is_key_dimension=True)

return qs

dimensions = graphene.List(
graphene.NonNull(ResponseDimensionValueType),
key_dimensions_only=graphene.Boolean(),
)

@staticmethod
def resolve_cached_dimensions(response: Response, info, key_dimensions_only: bool = False):
"""
Returns the dimensions of the response as
a dict of dimension slug -> list of dimension value slugs. If the response
is not related to a survey, there will be no dimensions and an empty dict
will always be returned.
Using this field is more efficient than querying the dimensions field
on the response, as the dimensions are cached on the response object.
The respondent will only see values of dimensions that are designated as
being shown to the respondent.
"""
cached_dimensions = response.cached_dimensions

included_dimensions = response.dimensions.filter(
dimension__slug__in=cached_dimensions.keys(),
dimension__is_shown_to_respondent=True,
)

if key_dimensions_only:
included_dimensions = included_dimensions.filter(dimension__is_key_dimension=True)

included_dimension_slugs = response.dimensions.values_list("dimension__slug", flat=True)

return {k: v for k, v in cached_dimensions.items() if k in included_dimension_slugs}

cached_dimensions = graphene.Field(
GenericScalar,
description=normalize_whitespace(resolve_cached_dimensions.__doc__ or ""),
key_dimensions_only=graphene.Boolean(),
)

class Meta:
model = Response
fields = (
"id",
"form_data",
"created_at",
)
20 changes: 20 additions & 0 deletions backend/forms/migrations/0022_dimension_is_shown_to_respondent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.0.1 on 2024-01-27 16:03

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("forms", "0021_dimension_is_multi_value"),
]

operations = [
migrations.AddField(
model_name="dimension",
name="is_shown_to_respondent",
field=models.BooleanField(
default=False,
help_text="If set, the respondent will see the value of the dimension in the profile survey responses list.",
),
),
]
Loading

0 comments on commit 62aba4a

Please sign in to comment.