from rest_framework import serializers from authentication.models import ExtendedUser from inventory.models import Event from inventory.shared_serializers import BasicItemSerializer from mail.api_v2 import AttachmentSerializer from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingVoucher from tickets.shared_serializers import BasicIssueSerializer class CommentSerializer(serializers.ModelSerializer): def validate(self, attrs): if 'comment' not in attrs or attrs['comment'] == '': raise serializers.ValidationError('comment cannot be empty') return attrs class Meta: model = Comment fields = ('id', 'comment', 'timestamp', 'issue_thread') class StateSerializer(serializers.Serializer): text = serializers.SerializerMethodField() value = serializers.SerializerMethodField() def get_text(self, obj): return obj['text'] def get_value(self, obj): return obj['value'] class ShippingVoucherSerializer(serializers.ModelSerializer): class Meta: model = ShippingVoucher fields = ('id', 'voucher', 'type', 'timestamp', 'issue_thread', 'used_at') read_only_fields = ('id', 'timestamp', 'used_at') class IssueSerializer(BasicIssueSerializer): timeline = serializers.SerializerMethodField() last_activity = serializers.SerializerMethodField() related_items = BasicItemSerializer(many=True, read_only=True) class Meta: model = IssueThread fields = ('id', 'timeline', 'name', 'state', 'assigned_to', 'last_activity', 'uuid', 'related_items', 'event') read_only_fields = ('id', 'timeline', 'last_activity', 'uuid', 'related_items') def to_internal_value(self, data): ret = super().to_internal_value(data) if 'state' in data: ret['state'] = data['state'] return ret def validate(self, attrs): if 'state' in attrs: if attrs['state'] not in [x[0] for x in STATE_CHOICES]: raise serializers.ValidationError('invalid state') return attrs @staticmethod def get_last_activity(self): try: last_state_change = self.state_changes.order_by('-timestamp').first().timestamp \ if self.state_changes.count() > 0 else None last_comment = self.comments.order_by('-timestamp').first().timestamp if self.comments.count() > 0 else None last_mail = self.emails.order_by('-timestamp').first().timestamp if self.emails.count() > 0 else None last_assignment = self.assignments.order_by('-timestamp').first().timestamp if \ self.assignments.count() > 0 else None last_relation = self.item_relation_changes.order_by('-timestamp').first().timestamp if \ self.item_relation_changes.count() > 0 else None args = [x for x in [last_state_change, last_comment, last_mail, last_assignment, last_relation] if x is not None] return max(args) except AttributeError: return None @staticmethod def get_timeline(obj): timeline = [] for comment in obj.comments.all(): timeline.append({ 'type': 'comment', 'id': comment.id, 'timestamp': comment.timestamp, 'comment': comment.comment, }) for state_change in obj.state_changes.all(): timeline.append({ 'type': 'state', 'id': state_change.id, 'timestamp': state_change.timestamp, 'state': state_change.state, }) for email in obj.emails.all(): timeline.append({ 'type': 'mail', 'id': email.id, 'timestamp': email.timestamp, 'sender': email.sender, 'recipient': email.recipient, 'subject': email.subject, 'body': email.body, 'attachments': AttachmentSerializer(email.attachments.all(), many=True).data, }) for assignment in obj.assignments.all(): timeline.append({ 'type': 'assignment', 'id': assignment.id, 'timestamp': assignment.timestamp, 'assigned_to': assignment.assigned_to.username, }) for relation in (obj.item_relation_changes.all()): timeline.append({ 'type': 'item_relation', 'id': relation.id, 'status': relation.status, 'timestamp': relation.timestamp, 'item': BasicItemSerializer(relation.item).data, }) for shipping_voucher in obj.shipping_vouchers.all(): timeline.append({ 'type': 'shipping_voucher', 'id': shipping_voucher.id, 'timestamp': shipping_voucher.used_at, 'voucher': shipping_voucher.voucher, 'voucher_type': shipping_voucher.type, }) return sorted(timeline, key=lambda x: x['timestamp']) class SearchResultSerializer(serializers.Serializer): search_score = serializers.IntegerField() item = IssueSerializer() def to_representation(self, instance): return {**IssueSerializer(instance['item']).data, 'search_score': instance['search_score']} class Meta: model = IssueThread