class ColourThemeSerializer(ModelSerializer): """Serializer for the main colour theme.""" class Meta: model = ColourTheme fields = ("id", "company", "primary", "accent", "logo") company = HyperlinkedRelatedReadField( queryset=Company.objects.all(), view_name="company-detail", ) logo = HyperlinkedRelatedReadField( queryset=Image.objects.all(), view_name="company-logo-detail", allow_null=True, ) def get_extra_kwargs(self): """ Filter out the 'company' field when the user is from management. :return: A sequence with the extra field kwargs. :rtype: tuple """ kwargs = ModelSerializer.get_extra_kwargs(self) if not is_management(self.context["request"].user): return kwargs return { **kwargs, "company": { **kwargs.get("company", {}), "read_only": True } }
class SessionSerializer(ModelSerializer): """Serializer for a single session.""" class Meta: model = Session fields = ("id", "set", "value", "theme", "start", "until", "company") theme = HyperlinkedRelatedReadField( queryset=QuestionTheme.objects.all(), view_name="", ) company = HyperlinkedRelatedReadField( queryset=Company.objects.all(), view_name="", ) def validate(self, attrs): """ Verify that a session is chronological and not in the past. :param attrs: The (by fields) validated values :type attrs: dict :return: The completely validated data :rtype: dict """ if attrs["start"] >= attrs["until"]: raise ValidationError("Can not start after the end") if attrs["start"] < datetime.datetime.utcnow(): raise ValidationError("Can not start in the past") return attrs
class CompanySerializer(ModelSerializer): """Serializer for a single company.""" class Meta: model = Company fields = ("id", "name", "theme", "members") theme = HyperlinkedRelatedReadField( read_only=True, view_name="colour-theme-detail", ) members = HyperlinkedRelatedReadField( many=True, read_only=True, view_name="member-detail", ) def get_field_names(self, declared_fields, info): """ Filter out the 'members' field when the user is a employee. :param declared_fields: A mapping of the declared fields in order :type declared_fields: collections.OrderedDict :param info: Additional information about the current models fields :type info: rest_framework.utils.model_meta.FieldInfo :return: A sequence with the fields to serialize :rtype: tuple """ fields = ModelSerializer.get_field_names(self, declared_fields, info) if not is_employee(self.context["request"].user, False): return fields return tuple(field for field in fields if field != "members")
class EmailSerializer(ModelSerializer): """Serializer for emails, these models make dynamic content possible.""" class Meta: model = Email fields = ("id", "subject", "content", "environ", "company") environ = HyperlinkedRelatedReadField( queryset=Email.objects.all(), view_name="", ) company = HyperlinkedRelatedReadField( queryset=Company.objects.all(), view_name="", validators=[DefaultEmailRestrictions()])
class MemberSerializer(ModelSerializer): """Serializer for the membership relation.""" class Meta: model = Member fields = ("id", "account", "company") account = HyperlinkedRelatedReadField( queryset=User.objects.all(), view_name="account-detail", ) company = HyperlinkedRelatedReadField( queryset=Company.objects.all(), view_name="company-detail", )
class QuestionSerializer(ModelSerializer): """Serializer for a single question.""" class Meta: model = Question fields = ("id", "set", "answers", "question") set = HyperlinkedRelatedReadField( queryset=QuestionSet.objects.all(), view_name="" ) answers = HyperlinkedRelatedReadField( queryset=Answers.objects.all(), view_name="" )
class AnswersSerializer(ModelSerializer): """Serializer for a answer set.""" class Meta: model = Answers fields = ("id", "label", "values") values = HyperlinkedRelatedReadField( queryset=Answer.objects.filter(deleted__isnull=True), view_name="", )
class QuestionSetSerializer(ModelSerializer): """Serializer for question sets.""" class Meta: model = QuestionSet fields = ("id", "label", "theme") theme = HyperlinkedRelatedReadField( queryset=QuestionTheme.objects.all(), view_name="", )
class QuestionThemeSerializer(ModelSerializer): """Serializer for the question theme.""" class Meta: model = QuestionTheme fields = ("id", "label", "sets") sets = HyperlinkedRelatedReadField( many=True, queryset=QuestionSet.objects.all(), view_name="", ) sessions = _TimeAwareHyperlinkField( many=True, queryset=Session.objects.all(), view_name="", )
class EnvironmentSerializer(Serializer): """ Custom environment serializer. Just like the variable serializer makes this class sure that no new environments are created. This should only be possible through fixtures. It is allowed though to change the label given to the environment. """ create = None update = None label = CharField(max_length=255) variables = HyperlinkedRelatedReadField(many=True, read_only=True, view_name="") def save(self, **kwargs): """ Custom save method to completely ignore create requests. :param kwargs: Additional keyword arguments (ignored) :type kwargs: any :return: The updated environment instance :rtype: communications.models.Environment """ if self.instance is None: return self.instance self.instance.name = self.validated_data["label"] self.instance.save() return self.instance
class ReflectionSerializer(ModelSerializer): """ Serializer for the reflection of a user. This serializer handles a few ver strict and thorough validations because some of the fields are related through many-to-many fields and they MUST match for the data to make sense. """ class Meta: model = Reflection fields = ("id", "session", "answerer", "question", "description") session = HyperlinkedRelatedReadField( queryset=Session.objects.all(), view_name="", validators=[ SessionIsNowAlive(), SessionHasCompany(), ] ) question = HyperlinkedRelatedReadField( queryset=Question.objects.all(), view_name="", validators=[ QuestionIsAnswered(), QuestionHasCompany(), ] ) answerer = HyperlinkedRelatedReadField( default=CurrentUserDefault(), read_only=True, view_name="account-detail", validators=[ GroupValidator(Groups.employee), ] ) def save(self, **kwargs): """ Overridden to inform management after storing the data. :param kwargs: The additional data to save :type kwargs: any :return: The newly created reflection instance :rtype: activities.models.Reflection """ # XXX TODO: refactor to assigned management member of some sorts? instance = ModelSerializer.save(self, **kwargs) managers = User.objects.filter(groups=Groups.management) context = self.get_context(instance) company = instance.answerer.member.company transport = MultiMailTransport(context, 3, company) transport.finish(transport(manager.email, {}) for manager in managers) return instance def validate(self, attributes): """ Validate that the question has ties to the session. :param attributes: The values to validate :type attributes: dict :return: The validated values to create a reflection :rtype: dict """ session = attributes["session"] question = attributes["question"] clause = Q(set__session=session.id) & Q(id=question.id) if Question.objects.filter(clause).exist(): return attributes raise ValidationError( "The question doesn't have any ties to the session" ) def get_context(self, instance): """ Create the context to use for the email. :param instance: The current reflection instance :type instance: activities.models.Reflection :return: The created context :rtype: dict """ return { "q_id": instance.question.id, "q_set": instance.session.set.label, "q_theme": instance.session.theme.label, "question": instance.question.question, "email": instance.answerer.email, "company": instance.answerer.member.company.name, "description": instance.description, }
class AnsweredSerializer(ModelSerializer): """Serializer for a users 'answered': the answer to a question.""" class Meta: model = Answered fields = ("id", "value", "label", "session", "answerer", "question") extra_kwargs = {"answerer": {"write_only": True}} value = IntegerField( max_value=100, read_only=True, ) answer = HyperlinkedRelatedReadField( queryset=Answer.objects.all(), view_name="", ) session = HyperlinkedRelatedReadField( queryset=Session.objects.all(), view_name="", validators=[ SessionHasCompany(), SessionIsNowAlive(), ] ) answerer = HyperlinkedRelatedReadField( default=CurrentUserDefault(), queryset=User.objects.all(), view_name="", validators=[ GroupValidator(Groups.employee), ] ) question = HyperlinkedRelatedReadField( queryset=Question.objects.all(), view_name="", ) def save(self, **kwargs): """ Overridden to add the copy-query to the value. The value and actual answer are copied in case that the answer set (Answers) is changed. This way we can maintain the actual value and delete the answer, or change it, safely and maintain data integrity. :param kwargs: The additional data to add to validated_data :type kwargs: any :return: The newly created 'Answered' instance :rtype: activities.models.Answered """ return ModelSerializer.save(self, **kwargs, value=self.get_calc()) def get_calc(self): """ Get the query to calculate the value. :return: The query to calculate the value. :rtype: django.db.models.query.QuerySet """ user = self.context["request"].user data = self.validated_data["value"] ques = self.validated_data["question"] return get_value_query(user, data, ques) def validate(self, attributes): """ Validate the answer given and the additional context. Validates that the answered answer can be applied to the question, and that the question is actually found within the session's question set. :param attributes: The values to validate :type attributes: dict :return: The validated values :rtype: dict """ clause = Q(answers__answer=attributes["answered"]) clause = Q(id=attributes["question"]) & clause if not Question.objects.filter(clause).exists(): raise ValidationError( "The given answer is not available to this question" ) clause = Q(set__session=attributes["property"]) clause = Q(id=attributes["question"]) & clause if not Question.objects.filter(clause).exists(): raise ValidationError( "The question doesn't belong to this session" ) return attributes def get_extra_kwargs(self): """ Overridden to hide the answerer for management or employer. This is because a employee may never know who gave answers except when the user created a reflection, but that's handled within the ReflectionSerializer. :return: The extra keyword arguments for the fields :rtype: dict """ extra = ModelSerializer.get_extra_kwargs(self) if is_employee(self.context.request.user): current_arguments = extra.get(extra["answerer"], {}) extra["answerer"] = {**current_arguments, "write_only": False} return extra