Commit 8fa617f2 authored by Flavio TARSETTI's avatar Flavio TARSETTI
Browse files

Merge branch 'cleanup_reports' into 'django3_migration'

Cleanup reports

See merge request !357
parents ea81206d 95a2b05d
Pipeline #42754 passed with stage
in 15 minutes and 9 seconds
#!/usr/bin/env python
# vim: set fileencoding=utf-8 : # vim: set fileencoding=utf-8 :
#!/usr/bin/env python
# encoding: utf-8 # encoding: utf-8
############################################################################### ###############################################################################
...@@ -30,86 +28,92 @@ ...@@ -30,86 +28,92 @@
# Flavio Tarsetti <flavio.tarsetti@idiap.ch> # Flavio Tarsetti <flavio.tarsetti@idiap.ch>
# Wed May 20 15:46:11 CEST 2015 # Wed May 20 15:46:11 CEST 2015
from django.contrib import admin import simplejson as json
from django import forms from django import forms
from django.contrib import admin
from ..common.texts import Messages from ..common.texts import Messages
from ..ui.forms import CodeMirrorJSONCharField
from ..ui.forms import CodeMirrorRSTCharField
from .models import Report from .models import Report
from ..ui.forms import CodeMirrorRSTCharField, CodeMirrorJSONCharField
from ..ui.forms import NameField
import simplejson as json
class ReportModelForm(forms.ModelForm): class ReportModelForm(forms.ModelForm):
description = CodeMirrorRSTCharField( description = CodeMirrorRSTCharField(
label='Description', label="Description", required=False, help_text=Messages["description"],
required=False,
help_text=Messages['description'],
) )
content = CodeMirrorJSONCharField( content = CodeMirrorJSONCharField(label="Content", help_text=Messages["json"],)
label='Content',
help_text=Messages['json'],
)
def clean_content(self): def clean_content(self):
"""Cleans-up the content data, make sure it is really new""" """Cleans-up the content data, make sure it is really new"""
try: try:
data = json.loads(self.cleaned_data['content']) data = json.loads(self.cleaned_data["content"])
return json.dumps(data, indent=4) return json.dumps(data, indent=4)
except Exception as e: except Exception as e:
raise forms.ValidationError(str(e)) raise forms.ValidationError(str(e))
class ReportAdmin(admin.ModelAdmin): class ReportAdmin(admin.ModelAdmin):
form = ReportModelForm form = ReportModelForm
readonly_fields = ('referenced_plotters', 'referenced_plotterparameters') readonly_fields = ("referenced_plotters", "referenced_plotterparameters")
filter_horizontal = [ filter_horizontal = [
'experiments', "experiments",
'referenced_plotters', "referenced_plotters",
'referenced_plotterparameters' "referenced_plotterparameters",
] ]
fieldsets = ( fieldsets = (
(None, (None, dict(fields=("status", "name", "number", "author",),),),
dict( (
fields=('status', 'name', 'number', 'author',), "Dates",
), dict(
), classes=("collapse",),
('Dates', fields=("creation_date", "expiration_date", "publication_date",),
dict( ),
classes=('collapse',), ),
fields=('creation_date', 'expiration_date', 'publication_date',), (
), "Documentation",
), dict(classes=("collapse",), fields=("short_description", "description",),),
('Documentation', ),
dict( (
classes=('collapse',), None,
fields=('short_description', 'description',), dict(
), fields=(
), "analyzer",
(None, "experiments",
dict( "referenced_plotters",
fields=('analyzer', 'experiments', 'referenced_plotters', 'referenced_plotterparameters', 'content',), "referenced_plotterparameters",
), "content",
), ),
),
),
) )
list_display = ('id', 'name', 'number', 'author', 'creation_date', 'expiration_date', 'publication_date') list_display = (
search_fields = [ "id",
'author__username', "name",
'name', "number",
'short_description', "author",
'description', "creation_date",
'number', "expiration_date",
"publication_date",
)
search_fields = [
"author__username",
"name",
"short_description",
"description",
"number",
] ]
list_display_links = ('id', 'name') list_display_links = ("id", "name")
list_filter = ("author", "name")
list_filter = ('author', 'name')
admin.site.register(Report, ReportAdmin) admin.site.register(Report, ReportAdmin)
...@@ -26,44 +26,38 @@ ...@@ -26,44 +26,38 @@
############################################################################### ###############################################################################
import json import json
from datetime import datetime
from datetime import datetime, timedelta from datetime import timedelta
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from django.db.models import Q from django.db.models import Q
from django.shortcuts import get_object_or_404
from django.urls import reverse from django.urls import reverse
from rest_framework import generics from rest_framework import generics
from rest_framework import views
from rest_framework import permissions from rest_framework import permissions
from rest_framework.response import Response
from rest_framework import status from rest_framework import status
from rest_framework import views
from rest_framework.response import Response
from ..common.models import Shareable
from ..common.exceptions import ShareError from ..common.exceptions import ShareError
from ..common.mixins import CommonContextMixin from ..common.mixins import CommonContextMixin
from ..common.responses import BadRequestResponse, ForbiddenResponse from ..common.models import Shareable
from ..common.responses import BadRequestResponse
from ..common.responses import ForbiddenResponse
from ..common.utils import ensure_html from ..common.utils import ensure_html
from ..experiments.serializers import ExperimentResultsSerializer from ..experiments.serializers import ExperimentResultsSerializer
from .models import Report
from .serializers import SimpleReportSerializer from .permissions import IsAccessibleOutside
from .permissions import IsAuthor
from .permissions import IsAuthorOrPublished
from .permissions import IsEditable
from .permissions import IsLocked
from .serializers import FullReportSerializer from .serializers import FullReportSerializer
from .serializers import ReportCreationFailedException
from .serializers import ReportCreationSerializer from .serializers import ReportCreationSerializer
from .serializers import ReportUpdateSerializer from .serializers import ReportUpdateSerializer
from .serializers import ReportCreationFailedException from .serializers import SimpleReportSerializer
from .models import Report
from .permissions import (
IsAuthor,
IsAuthorOrPublished,
IsAccessibleOutside,
IsEditable,
IsLocked,
)
# ---------------------------------------------------------- # ----------------------------------------------------------
......
...@@ -27,49 +27,66 @@ ...@@ -27,49 +27,66 @@
############################################################################### ###############################################################################
from django.core.management import call_command from datetime import date
from django.core.management.base import BaseCommand, CommandError from datetime import datetime
from django.core.mail import send_mail from datetime import time
from django.template.loader import render_to_string from datetime import timedelta
from django.conf import settings from django.conf import settings
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core.mail import send_mail
from django.core.management import call_command
from django.core.management.base import BaseCommand
from django.template.loader import render_to_string
from datetime import datetime, time, date, timedelta
from ...models import Report
from .... import __version__ from .... import __version__
from ...models import Report
import sys
class Command(BaseCommand): class Command(BaseCommand):
help = 'Send email warning for reports about to expire and cleanup old reports' help = "Send email warning for reports about to expire and cleanup old reports"
def handle(self, *args, **options): def handle(self, *args, **options):
for expiration_reminder in settings.EXPIRATION_REMINDERS: for expiration_reminder in settings.EXPIRATION_REMINDERS:
expiration_date = date.today() + timedelta(days=expiration_reminder) expiration_date = date.today() + timedelta(days=expiration_reminder)
reports_about_to_expire = Report.objects.filter(status=Report.LOCKED, expiration_date__range=(datetime.combine(expiration_date, time.min), reports_about_to_expire = Report.objects.filter(
datetime.combine(expiration_date, time.max))) status=Report.LOCKED,
expiration_date__range=(
datetime.combine(expiration_date, time.min),
datetime.combine(expiration_date, time.max),
),
)
if reports_about_to_expire: if reports_about_to_expire:
current_site = Site.objects.get_current() current_site = Site.objects.get_current()
template_path = 'reports/report_about_to_expire_email.txt' template_path = "reports/report_about_to_expire_email.txt"
for report in reports_about_to_expire: for report in reports_about_to_expire:
subject = "Report %s is about to expire" % \ subject = "Report %s is about to expire" % report.name
report.name
send_mail(subject, send_mail(
render_to_string(template_path, subject,
{ render_to_string(
'report': report, template_path,
'beat_version': __version__, {
'site': current_site, "report": report,
} "beat_version": __version__,
), "site": current_site,
settings.DEFAULT_FROM_EMAIL, },
[report.author.email]) ),
self.stdout.write('{} report(s) about to expire'.format(reports_about_to_expire.count())) settings.DEFAULT_FROM_EMAIL,
[report.author.email],
)
self.stdout.write(
"{} report(s) about to expire".format(
reports_about_to_expire.count()
)
)
else: else:
self.stdout.write('No report(s) about to expire in {} day(s)'.format(expiration_reminder)) self.stdout.write(
"No report(s) about to expire in {} day(s)".format(
expiration_reminder
)
)
call_command('clean_report', '--noinput') call_command("clean_report", "--noinput")
...@@ -27,37 +27,104 @@ ...@@ -27,37 +27,104 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings from django.conf import settings
from django.db import migrations
from django.db import models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('experiments', '0001_initial'), ("experiments", "0001_initial"),
('algorithms', '0001_initial'), ("algorithms", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('plotters', '0001_initial'), ("plotters", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Report', name="Report",
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), (
('status', models.CharField(default=b'E', max_length=1, choices=[(b'E', b'Editable'), (b'L', b'Locked'), (b'P', b'Published')])), "id",
('name', models.CharField(help_text=b'The name for this object (space-like characters will be automatically replaced by dashes)', max_length=200)), models.AutoField(
('number', models.IntegerField(blank=True)), verbose_name="ID",
('creation_date', models.DateTimeField()), serialize=False,
('publication_date', models.DateTimeField(null=True, blank=True)), auto_created=True,
('short_description', models.CharField(default=b'', help_text=b'Describe the object succinctly (try to keep it under 80 characters)', max_length=100, blank=True)), primary_key=True,
('description', models.TextField(default=b'', blank=True)), ),
('content', models.TextField(default=b'{}', blank=True)), ),
('analyzer', models.ForeignKey(related_name='reports', blank=True, to='algorithms.Algorithm', null=True, on_delete=models.SET_NULL)), (
('author', models.ForeignKey(related_name='reports', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), "status",
('experiments', models.ManyToManyField(related_name='reports', to='experiments.Experiment', blank=True)), models.CharField(
('referenced_plotterparameters', models.ManyToManyField(related_name='reports', to='plotters.PlotterParameter', blank=True)), default=b"E",
('referenced_plotters', models.ManyToManyField(related_name='reports', to='plotters.Plotter', blank=True)), max_length=1,
choices=[
(b"E", b"Editable"),
(b"L", b"Locked"),
(b"P", b"Published"),
],
),
),
(
"name",
models.CharField(
help_text=b"The name for this object (space-like characters will be automatically replaced by dashes)",
max_length=200,
),
),
("number", models.IntegerField(blank=True)),
("creation_date", models.DateTimeField()),
("publication_date", models.DateTimeField(null=True, blank=True)),
(
"short_description",
models.CharField(
default=b"",
help_text=b"Describe the object succinctly (try to keep it under 80 characters)",
max_length=100,
blank=True,
),
),
("description", models.TextField(default=b"", blank=True)),
("content", models.TextField(default=b"{}", blank=True)),
(
"analyzer",
models.ForeignKey(
related_name="reports",
blank=True,
to="algorithms.Algorithm",
null=True,
on_delete=models.SET_NULL,
),
),
(
"author",
models.ForeignKey(
related_name="reports",
to=settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
),
),
(
"experiments",
models.ManyToManyField(
related_name="reports", to="experiments.Experiment", blank=True
),
),
(
"referenced_plotterparameters",
models.ManyToManyField(
related_name="reports",
to="plotters.PlotterParameter",
blank=True,
),
),
(
"referenced_plotters",
models.ManyToManyField(
related_name="reports", to="plotters.Plotter", blank=True
),
),
], ],
), ),
] ]
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from datetime import datetime
from datetime import timedelta
from datetime import datetime, timedelta
from django.conf import settings from django.conf import settings
from django.db import migrations
from django.db import models
def add_timeout_to_existing_locked_report(apps, schema_editor): def add_timeout_to_existing_locked_report(apps, schema_editor):
report_model = apps.get_model("reports", "report") report_model = apps.get_model("reports", "report")
for single_report in report_model.objects.all(): for single_report in report_model.objects.all():
if single_report.status == 'L': if single_report.status == "L":
single_report.expiration_date = datetime.now() + timedelta(days=settings.EXPIRATION_DELTA) single_report.expiration_date = datetime.now() + timedelta(
days=settings.EXPIRATION_DELTA
)
single_report.save() single_report.save()
def backward_dummy(apps, schema_editor): def backward_dummy(apps, schema_editor):
pass pass
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('reports', '0001_initial'), ("reports", "0001_initial"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='report', model_name="report",
name='expiration_date', name="expiration_date",
field=models.DateTimeField(null=True, blank=True), field=models.DateTimeField(null=True, blank=True),
), ),
migrations.RunPython(add_timeout_to_existing_locked_report, backward_dummy),
migrations.RunPython(add_timeout_to_existing_locked_report,
backward_dummy)
] ]
...@@ -2,19 +2,20 @@ ...@@ -2,19 +2,20 @@
# Generated by Django 1.9.5 on 2017-03-13 15:11 # Generated by Django 1.9.5 on 2017-03-13 15:11
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations
from django.db import models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('reports', '0002_report_expiration_date'), ("reports", "0002_report_expiration_date"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='report', model_name="report",
name='last_edited_date', name="last_edited_date",
field=models.DateTimeField(null=True),