def header(name, value):
    # View decorator that sets a response header.
    #
    # Example:
    # @header('X-Powered-By', 'Django')
    # def view(request, ...):
    #     ....
    #
    # For class-based views use:
    # @method_decorator(header('X-Powered-By', 'Django'))
    # def get(self, request, ...)
    #     ...
    def decorator(func):
        @wraps(func, assigned=available_attrs(func))
        def inner(request, *args, **kwargs):
            response = func(request, *args, **kwargs)
            response[name] = value
            return response

        return inner

    return decorator def x_ua_compatible(ie):
    return header('X-UA-Compatible', ie) class Announcement(models.Model):
    class Meta(object):
        verbose_name_plural = "Announcements"

    STYLE_CHOICES = (
        ('default', 'Default'),
        ('primary', 'Primary'),
        ('success', 'Success'),
        ('info', 'Success'),
        ('warning', 'Warning'),
        ('danger', 'Danger'),
    )

    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, unique=True)
    enabled = models.BooleanField(default=1, db_index=True)
    style = models.CharField(max_length=50, choices=STYLE_CHOICES, default='warning')
    content = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.title) class Attribute(models.Model):
    class Meta(object):
        verbose_name_plural = "Attributes"
        unique_together = ("template", "name")
        ordering = ['template', 'rank', 'pk']

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256)
    template = models.ForeignKey(Template, related_name='attributes', on_delete=models.CASCADE)
    rank = models.IntegerField(default=1, db_index=True)
    desc = models.TextField(verbose_name="Description")
    desc_class = models.CharField(max_length=256, default="", blank=True, verbose_name="Description CSS Class")

    def __str__(self):
        return str(self.template) + " - " + self.name class Rating(models.Model):
    class Meta(object):
        verbose_name_plural = "Ratings"
        unique_together = ("attribute", "name")
        ordering = ['attribute', 'rank', 'pk']

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256)
    attribute = models.ForeignKey(Attribute, related_name='ratings', on_delete=models.CASCADE)
    rank = models.IntegerField(default=1, db_index=True)
    colour = models.CharField(max_length=256, null=True, blank=True)
    desc = models.TextField(verbose_name="Description")
    desc_class = models.CharField(max_length=256, default="", blank=True, verbose_name="Description CSS Class")

    def __str__(self):
        return str(self.attribute) + " - " + self.name class Assessment(models.Model):
    class Meta(object):
        verbose_name_plural = "Assessments"
        ordering = ['-pk']

    STATUS_CHOICES = (
        ('TODO', 'To Do'),
        ('DONE', 'Done'),
    )

    id = models.AutoField(primary_key=True)
    team = models.ForeignKey(Team, related_name="assessments", db_index=True, on_delete=models.CASCADE)
    template = models.ForeignKey(Template, related_name="assessments", on_delete=models.PROTECT)
    status = models.CharField(
        max_length=128,
        choices=STATUS_CHOICES,
        default='TODO',
        blank=False,
    )
    tags = models.ManyToManyField(Tag, )
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.team) + " - " + str(self.template) + " - " + str(self.id) class Measurement(models.Model):
    class Meta(object):
        unique_together = (("assessment", "attribute"),)
        verbose_name_plural = "Measurements"

    assessment = models.ForeignKey(Assessment, related_name="measurements", on_delete=models.CASCADE)
    attribute = models.ForeignKey(Attribute, related_name="measurements", on_delete=models.PROTECT)
    rating = models.ForeignKey(Rating, related_name="measurements", on_delete=models.PROTECT)
    target_rating = models.ForeignKey(Rating, blank=True, null=True, related_name="target_measurements", on_delete=models.PROTECT)
    observations = models.TextField(null=True, blank=True)
    action = models.TextField(null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.assessment) + " - " + self.rating.attribute.name + " - " + self.rating.name

    def clean(self):
        if self.assessment.template.id != self.attribute.template.id:
            raise ValidationError(_('Measurement attributes must be for the same template as the assessment'))

        if self.attribute.id != self.rating.attribute.id:
            raise ValidationError(_('Measurement rating must be for the same attribute'))
        if self.assessment.template.id != self.rating.attribute.template.id:
            raise ValidationError(_('Measurement ratings must be for the same template as the assessment'))

        if self.target_rating is not None:
            if self.attribute.id != self.target_rating.attribute.id:
                raise ValidationError(_('Measurement target rating must be for the same attribute'))
            if self.assessment.template.id != self.target_rating.attribute.template.id:
                raise ValidationError(_('Measurement target ratings must be for the same template as the assessment')) class Tag(models.Model):
    class Meta(object):
        verbose_name_plural = "Tags"
        ordering = ['name']

    id = models.AutoField(primary_key=True)
    name = models.SlugField(unique=True, validators=[validate_tag], db_index=True)

    def __str__(self):
        return self.name class Team(models.Model):
    class Meta(object):
        verbose_name_plural = "Teams"
        ordering = ['pk']

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256, unique=True)
    short_desc = models.CharField(max_length=256, verbose_name="Description")
    tags = models.ManyToManyField(Tag, )
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name class Template(models.Model):
    class Meta(object):
        verbose_name_plural = "Templates"
        ordering = ['pk', ]

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=256, unique=True)
    taggable = models.BooleanField(default=0)
    enabled = models.BooleanField(default=1, db_index=True)
    short_desc = models.CharField(max_length=256, verbose_name="Description")

    def __str__(self):
        return self.name class AnnouncementSerializer(serializers.ModelSerializer):
    class Meta(object):
        model = Announcement
        fields = ('id', 'created', 'updated', 'title', 'content', 'enabled', 'style') class AssessmentCreateSerializer(serializers.ModelSerializer):
    template = serializers.PrimaryKeyRelatedField(queryset=Template.objects.all())
    team = serializers.PrimaryKeyRelatedField(queryset=Team.objects.all())
    tags = serializers.PrimaryKeyRelatedField(many=True, allow_null=True, queryset=Tag.objects.all())

    class Meta(object):
        model = Assessment
        fields = ('id', 'created', 'updated', 'template', 'tags', 'status', 'team') class AssessmentSerializer(serializers.ModelSerializer):
    tags = serializers.PrimaryKeyRelatedField(many=True, allow_null=True, queryset=Tag.objects.all())

    class Meta(object):
        model = Assessment
        depth = 2
        fields = ('id', 'created', 'updated', 'template', 'tags', 'status', 'team') class AttributeSerializer(serializers.ModelSerializer):
    ratings = RatingSerializer(many=True, read_only=True)

    class Meta(object):
        model = Attribute
        fields = ('id', 'name', 'desc', 'desc_class', 'rank', 'ratings') class MeasurementCreateSerializer(serializers.ModelSerializer):
    assessment = serializers.PrimaryKeyRelatedField(queryset=Assessment.objects.all())
    attribute = serializers.PrimaryKeyRelatedField(queryset=Attribute.objects.all())
    rating = serializers.PrimaryKeyRelatedField(queryset=Rating.objects.all())
    target_rating = serializers.PrimaryKeyRelatedField(
        allow_null=True,
        queryset=Rating.objects.all(),
        required=False
    )
    observations = serializers.CharField(allow_null=True, allow_blank=True)
    action = serializers.CharField(allow_null=True, allow_blank=True)

    class Meta(object):
        model = Measurement
        fields = ('id', 'created', 'updated', 'assessment', 'attribute', 'rating', 'target_rating', 'observations', 'action') class RatingSerializer(serializers.ModelSerializer):
    class Meta(object):
        model = Rating
        fields = ('id', 'name', 'desc', 'desc_class', 'rank', 'colour') class TagSerializer(serializers.ModelSerializer):
    class Meta(object):
        model = Tag
        fields = ('id', 'name') class TeamCreateSerializer(serializers.ModelSerializer):
    tags = serializers.PrimaryKeyRelatedField(many=True, allow_null=True, queryset=Tag.objects.all())

    class Meta(object):
        model = Team
        fields = ('id', 'created', 'updated', 'name', 'short_desc', 'tags') class TeamSerializer(serializers.ModelSerializer):
    assessments = AssessmentSimpleSerializer(many=True, read_only=True)
    tags = serializers.PrimaryKeyRelatedField(many=True, allow_null=True, queryset=Tag.objects.all())

    class Meta(object):
        model = Team
        fields = ('id', 'created', 'updated', 'name', 'short_desc', 'tags', 'assessments')
        depth = 2 class TemplateSerializer(serializers.ModelSerializer):
    attributes = AttributeSerializer(many=True, read_only=True)

    class Meta(object):
        model = Template
        fields = ('id', 'name', 'short_desc', 'taggable', 'enabled', 'attributes')
from datetime import datetime
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.shortcuts import render
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets, filters, status, schemas
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.response import Response
from rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer
from .headers import header, x_ua_compatible
from .models import Announcement, Attribute, Rating, Assessment, Measurement, Tag, Team, Template
from .serializers import AnnouncementSerializer, AssessmentCreateSerializer, AssessmentSerializer, AttributeSerializer, \
    MeasurementCreateSerializer, RatingSerializer, TagSerializer, TeamCreateSerializer, TeamSerializer, \
    TemplateSerializer
import django_excel as excel
import rest_framework.exceptions



schema_view = schemas.get_schema_view(
    title='Measure Mate API',
    renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer]
)


@x_ua_compatible('IE=edge')
@header('Cache-control', 'no-cache')
def home(request):
    return render(request, 'index.html')


@login_required
def export_data(request):
    now = datetime.utcnow()
    timestamp = now.strftime('%Y-%m-%d_%H-%M-%SZ')
    return excel.make_response_from_tables(

        [Team, Assessment, Measurement, Tag, Template, Attribute, Rating],