From 3dbda6a041c1d5f50b76c384f0d97452b7079431 Mon Sep 17 00:00:00 2001 From: haribo Date: Fri, 17 Jun 2016 17:14:55 +0200 Subject: [PATCH] Date: 17/06/2016 By: Paul Carensac Version: 0.7.4 Import XML + Changed deprecated reverse by dotting path in templates (links) Warning : DB updated Issues (closed): https://projects.irap.omp.eu/issues/3811 Major current version (0.7): https://projects.irap.omp.eu/versions/117 --- README.md | 9 +++++---- src/alert_manager/templates/alert_manager/alert_simulation.html | 2 +- src/alert_manager/templates/alert_manager/alerts.html | 2 +- src/alert_manager/templates/alert_manager/strategy_change.html | 4 ++-- src/alert_manager/urls.py | 10 +++++----- src/routine_manager/RequestSerializer.py | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/routine_manager/templates/routine_manager/edit_base.html | 22 +++++++++++----------- src/routine_manager/templates/routine_manager/requests_list.html | 39 +++++++++++++++++++++++++++------------ src/routine_manager/templates/routine_manager/view_album.html | 8 ++++---- src/routine_manager/templates/routine_manager/view_plan.html | 2 +- src/routine_manager/templates/routine_manager/view_request.html | 8 ++++---- src/routine_manager/templates/routine_manager/view_sequence.html | 8 ++++---- src/routine_manager/urls.py | 43 ++++++++++++++++++++++--------------------- src/routine_manager/validators.py | 15 +++++++++++++++ src/routine_manager/views.py | 33 ++++++++++++++++++++++++++++++--- src/saved_requests/empty | 0 src/saved_requests/request50.xml | 16 ++++++++++++++++ src/scheduler/urls.py | 4 ++-- src/templates/base.html | 20 ++++++++++---------- src/user_manager/templates/user_manager/home_login.html | 4 ++-- src/user_manager/templates/user_manager/home_user_creation.html | 2 +- src/user_manager/urls.py | 10 +++++----- 22 files changed, 318 insertions(+), 95 deletions(-) create mode 100644 src/saved_requests/empty create mode 100644 src/saved_requests/request50.xml diff --git a/README.md b/README.md index 7764862..be2fe1d 100644 --- a/README.md +++ b/README.md @@ -60,11 +60,12 @@ PROJECT STRUCTURE: -------------------------------------------------------------------------------------------- CURRENT VERSION -Date: 16/06/2016 +Date: 17/06/2016 By: Paul Carensac -Version: 0.7.3 -Export XML + download -Issues (closed): https://projects.irap.omp.eu/issues/3827 +Version: 0.7.4 +Import XML + Changed deprecated reverse by dotting path in templates (links) +Warning : DB updated +Issues (closed): https://projects.irap.omp.eu/issues/3811 Major current version (0.7): https://projects.irap.omp.eu/versions/117 ROADMAP: https://projects.irap.omp.eu/projects/pyros/roadmap diff --git a/src/alert_manager/templates/alert_manager/alert_simulation.html b/src/alert_manager/templates/alert_manager/alert_simulation.html index ec8b167..2fdc7d3 100644 --- a/src/alert_manager/templates/alert_manager/alert_simulation.html +++ b/src/alert_manager/templates/alert_manager/alert_simulation.html @@ -15,7 +15,7 @@
diff --git a/src/alert_manager/templates/alert_manager/alerts.html b/src/alert_manager/templates/alert_manager/alerts.html index 442cda2..618fc33 100644 --- a/src/alert_manager/templates/alert_manager/alerts.html +++ b/src/alert_manager/templates/alert_manager/alerts.html @@ -29,7 +29,7 @@ {{ alert.strategyobs.name }}     - Change diff --git a/src/alert_manager/templates/alert_manager/strategy_change.html b/src/alert_manager/templates/alert_manager/strategy_change.html index ebfae0c..1f3ab1e 100644 --- a/src/alert_manager/templates/alert_manager/strategy_change.html +++ b/src/alert_manager/templates/alert_manager/strategy_change.html @@ -11,7 +11,7 @@

Select a new observation strategy for alert {{ alert.request.name }}:

-
+ {% csrf_token %} {% for strategy in strategies %}
@@ -33,7 +33,7 @@
{% endblock %} diff --git a/src/alert_manager/urls.py b/src/alert_manager/urls.py index dd270c5..45b06d6 100644 --- a/src/alert_manager/urls.py +++ b/src/alert_manager/urls.py @@ -2,9 +2,9 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^simulation$', views.alert_simulation), - url(r'^simulation/start$', views.alert_simulation_start), - url(r'^change_obs_strategy/(?P\d+)$', views.change_obs_strategy), - url(r'^change_obs_strategy_validate/(?P\d+)$', views.change_obs_strategy_validate), - url(r'^alerts$', views.alerts_list), + url(r'^simulation$', views.alert_simulation, name="alert_simulation"), + url(r'^simulation/start$', views.alert_simulation_start, name="alert_simulation_start"), + url(r'^change_obs_strategy/(?P\d+)$', views.change_obs_strategy, name="change_obs_strategy"), + url(r'^change_obs_strategy_validate/(?P\d+)$', views.change_obs_strategy_validate, name="change_obs_strategy_validate"), + url(r'^alerts$', views.alerts_list, name='alerts_list'), ] diff --git a/src/routine_manager/RequestSerializer.py b/src/routine_manager/RequestSerializer.py index 0315569..fffeab7 100644 --- a/src/routine_manager/RequestSerializer.py +++ b/src/routine_manager/RequestSerializer.py @@ -1,7 +1,11 @@ from pyrosapp.models import * +import pyrosapp import xml.etree.ElementTree as ET import sys from xml.dom import minidom +from .validators import check_plan_validity +import re +from decimal import Decimal def prettify(elem): """ @@ -38,12 +42,156 @@ class RequestSerializer(): with open(file_name, "w") as file: file.write(prettify(request)) - def unserialize(self, file_name): + def unserialize(self, xml_data, pyros_user): """ Unserializes the request read into file_name Throws exceptions in case of invalid file or values Directly saves the objects in DB The request still need to be submitted afterward ! + + :returns : "" (empty string) in case of success, error message (string) instead """ - pass + + try: + root = ET.fromstring(xml_data) + except ET.ParseError as E: + return "Invalid file : " + str(E) + + self.pyros_user = pyros_user + self.request = None + + """ self.sequences will be a [(seq, album_list), ...], and same thing for album """ + self.sequences = [] + ret = self.unserialize_request(root) + if ret != "": + return ret + + self.request.save() + for sequence, albums in self.sequences: + sequence.request = self.request + sequence.save() + for album, plans in albums: + album.sequence = sequence + album.save() + for plan in plans: + plan.album = album + plan.save() + check_plan_validity(plan) + + return "" + + def unserialize_request(self, request): + if request.tag != "request": + return "Main object should be a request (found %s instead)" % (request.tag,) + possible_attribs = ["name", "scientific_program", "target_type"] + + self.request = Request(pyros_user=self.pyros_user, is_alert=False, complete=False, submitted=False) + + for name, value in request.attrib.items(): + if name not in possible_attribs: + return "Unknown attribute %s in request" % (name,) + if name == "scientific_program": + try: + sp = ScientificProgram.objects.get(name=value) + self.request.scientific_program = sp + except Exception as E: + print(str(E)) + return "Invalid scientific program %s" % (value,) + else: + self.request.__dict__[name] = value + + for sequence in request: + ret = self.unserialize_sequence(sequence) + if ret != "": + return ret + return "" + + def unserialize_sequence(self, sequence): + if sequence.tag != "sequence": + return "A request can only have 'sequence' children (found %s instead)" % (sequence.tag,) + possible_attribs = ["name", "target_coords", "jd1", "jd2", "duration"] + + seq = Sequence(request=self.request, status=Sequence.INCOMPLETE) + + for name, value in sequence.attrib.items(): + if name not in possible_attribs: + return "Unknown attribute %s in sequence" % (name,) + if name == "name": + seq.name = value + elif name == "target_coords": + seq.target_coords = value + elif name == "jd1": + seq.jd1 = Decimal(value) + elif name == "jd2": + seq.jd2 = Decimal(value) + elif name == "duration": + seq.duration = Decimal(value) + + # faire des checks ?? j'imagine + album_list = [] + self.sequences.append((seq, album_list)) + + for album in sequence: + ret = self.unserialize_album(album, seq, album_list) + if ret != "": + return ret + return "" + + def unserialize_album(self, album, sequence, album_list): + if album.tag != "album": + return "A sequence can only have 'album' children (found %s instead)" % (album.tag,) + possible_attribs = ["name", "detector"] + + alb = Album(sequence=sequence) + + for name, value in album.attrib.items(): + if name not in possible_attribs: + return "Unknown attribute %s in album" % (name,) + if name == "detector": + try: + detector = Detector.objects.get(device__name=value) + alb.detector = detector + except Exception as E: + print(str(E)) + return "Invalid detector %s" % (value,) + elif name == "name": + alb.name = value + plan_list = [] + album_list.append((alb, plan_list)) + + for plan in album: + ret = self.unserialize_plan(plan, alb, plan_list) + if ret != "": + return ret + return "" + + + def unserialize_plan(self, plan, album, plan_list): + if plan.tag != "plan": + return "An album can only have 'plan' children (found %s instead)" % (plan.tag,) + possible_attribs = ["name", "filter", "duration", "nb_images"] + + pl = Plan(album=album) + + for name, value in plan.attrib.items(): + if name not in possible_attribs: + return "Unknown attribute %s in plan" % (name,) + if name == "filter": + try: + filter = Filter.objects.get(device__name=value) + pl.filter = filter + except Exception as E: + return "Invalid filter %s" % (value,) + elif name == "name": + pl.name = value + elif name == "duration": + pl.duration = Decimal(value) + elif name == "nb_images": + pl.nb_images = int(value) + + # quelques checks ... + + plan_list.append(pl) + return "" + diff --git a/src/routine_manager/templates/routine_manager/edit_base.html b/src/routine_manager/templates/routine_manager/edit_base.html index e01b386..8a549ba 100644 --- a/src/routine_manager/templates/routine_manager/edit_base.html +++ b/src/routine_manager/templates/routine_manager/edit_base.html @@ -13,19 +13,19 @@ @@ -34,20 +34,20 @@
{% if req.submitted == False %} {% if req.complete == True %} - Submit request for scheduling {% else %} Submit request for scheduling {% endif %} {% else %} - Unsubmit request {% endif %}
@@ -80,25 +80,25 @@

Summary

- Request: {{ req.name }} + Request: {{ req.name }} {% if depth_level == 1 %}{{action}}ing ...{% endif %}
{% for seq in req.sequences.all %}
- Sequence: {{ seq.name }} + Sequence: {{ seq.name }} {% if depth_level == 2 and seq_id == seq.id %}{{action}}ing ...{% endif %}
{% for album in seq.albums.all %}
- Album: {{ album.name }} + Album: {{ album.name }} {% if depth_level == 3 and alb_id == album.id %}{{action}}ing ...{% endif %}
{% for plan in album.plans.all %}
- Plan: {{ plan.name }} + Plan: {{ plan.name }} {% if depth_level == 4 and plan_id == plan.id %}{{action}}ing ...{% endif %}
diff --git a/src/routine_manager/templates/routine_manager/requests_list.html b/src/routine_manager/templates/routine_manager/requests_list.html index 21a29ed..c5922eb 100644 --- a/src/routine_manager/templates/routine_manager/requests_list.html +++ b/src/routine_manager/templates/routine_manager/requests_list.html @@ -10,10 +10,32 @@
-

List of Routine Requests in the database

+

Actions

+
+
+
+ + {% csrf_token %} + + +
+
+ + +
+
+

List of Routine Requests in the database

+
@@ -40,7 +62,7 @@ {% for row in requests %} - {{ row.req.name }} + {{ row.req.name }} {{ row.req.created }} {{ row.req.updated }} {{ row.req.type }} @@ -50,10 +72,10 @@
{% if row.req.submitted == False %} - Edit + Edit {% endif %} - View - View + Delete
@@ -71,13 +93,6 @@
- - diff --git a/src/routine_manager/templates/routine_manager/view_album.html b/src/routine_manager/templates/routine_manager/view_album.html index 302404e..5e759d9 100644 --- a/src/routine_manager/templates/routine_manager/view_album.html +++ b/src/routine_manager/templates/routine_manager/view_album.html @@ -5,7 +5,7 @@ {% endblock %} {% block fields %} -
+ {% csrf_token %}
@@ -69,11 +69,11 @@
{% if action == 'edit' %} - Edit - Edit + Delete {% else %} - + {% endif %}
diff --git a/src/routine_manager/templates/routine_manager/view_plan.html b/src/routine_manager/templates/routine_manager/view_plan.html index 3727c73..0edbc12 100644 --- a/src/routine_manager/templates/routine_manager/view_plan.html +++ b/src/routine_manager/templates/routine_manager/view_plan.html @@ -5,7 +5,7 @@ {% endblock %} {% block fields %} - + {% csrf_token %}
diff --git a/src/routine_manager/templates/routine_manager/view_request.html b/src/routine_manager/templates/routine_manager/view_request.html index b86608b..d3ac024 100644 --- a/src/routine_manager/templates/routine_manager/view_request.html +++ b/src/routine_manager/templates/routine_manager/view_request.html @@ -6,7 +6,7 @@ {% block fields %} - + {% csrf_token %}
@@ -67,11 +67,11 @@
{% if action == 'edit' %} - Edit - Edit + Delete {% else %} - View + View {% endif %}
diff --git a/src/routine_manager/templates/routine_manager/view_sequence.html b/src/routine_manager/templates/routine_manager/view_sequence.html index b538e9f..e61d027 100644 --- a/src/routine_manager/templates/routine_manager/view_sequence.html +++ b/src/routine_manager/templates/routine_manager/view_sequence.html @@ -5,7 +5,7 @@ {% endblock %} {% block fields %} - + {% csrf_token %}
@@ -65,11 +65,11 @@
{% if action == 'edit' %} - Edit - Edit + Delete {% else %} - View + View {% endif %}
diff --git a/src/routine_manager/urls.py b/src/routine_manager/urls.py index 8893f6c..b9a4cf2 100644 --- a/src/routine_manager/urls.py +++ b/src/routine_manager/urls.py @@ -2,35 +2,36 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^$', views.requests_list), - url(r'^(?P[-1,0,1])/(?P[a-zA-Z0-9_ ]{1,100})$', views.requests_list), + url(r'^$', views.requests_list, name="requests_list"), + url(r'^(?P-?\d)/(?P.+)$', views.requests_list, name="requests_list"), - url(r'^action_request/(?P\d+)/(?P[a-z_]{1,20})$', views.action_request), - url(r'^action_request/(?P\d+)/(?P[a-z_]{1,20})/(?P[-1,0,1])/(?P[a-zA-Z0-9_ ]{1,100})$', views.action_request), + url(r'^action_request/(?P\d+)/(?P[a-z_]{1,20})$', views.action_request, name="action_request"), + url(r'^action_request/(?P\d+)/(?P[a-z_]{1,20})/(?P-?\d)/(?P.+)$', views.action_request, name="action_request_message"), - url(r'^action_sequence/(?P\d+)/(?P[a-z_]{1,20})$', views.action_sequence), - url(r'^action_sequence/(?P\d+)/(?P[a-z_]{1,20})/(?P[-1,0,1])/(?P[a-zA-Z0-9_ ]{1,100})$', views.action_sequence), + url(r'^action_sequence/(?P\d+)/(?P[a-z_]{1,20})$', views.action_sequence, name="action_sequence"), + url(r'^action_sequence/(?P\d+)/(?P[a-z_]{1,20})/(?P-?\d)/(?P.+)$', views.action_sequence, name="action_sequence_message"), - url(r'^action_album/(?P\d+)/(?P[a-z_]{1,20})$', views.action_album), - url(r'^action_album/(?P\d+)/(?P[a-z_]{1,20})/(?P[-1,0,1])/(?P[a-zA-Z0-9_ ]{1,100})$', views.action_album), + url(r'^action_album/(?P\d+)/(?P[a-z_]{1,20})$', views.action_album, name="action_album"), + url(r'^action_album/(?P\d+)/(?P[a-z_]{1,20})/(?P-?\d)/(?P.+)$', views.action_album, name="action_album_message"), - url(r'^action_plan/(?P\d+)/(?P[a-z_]{1,20})$', views.action_plan), - url(r'^action_plan/(?P\d+)/(?P[a-z_]{1,20})/(?P[-1,0,1])/(?P[a-zA-Z0-9_ ]{1,100})$', views.action_plan), + url(r'^action_plan/(?P\d+)/(?P[a-z_]{1,20})$', views.action_plan, name="action_plan"), + url(r'^action_plan/(?P\d+)/(?P[a-z_]{1,20})/(?P-?\d)/(?P.+)$', views.action_plan, name="action_plan_message"), - url(r'^request_validate/(?P\d+)$', views.request_validate), - url(r'^sequence_validate/(?P\d+)$', views.sequence_validate), - url(r'^album_validate/(?P\d+)$', views.album_validate), - url(r'^plan_validate/(?P\d+)$', views.plan_validate), + url(r'^request_validate/(?P\d+)$', views.request_validate, name="request_validate"), + url(r'^sequence_validate/(?P\d+)$', views.sequence_validate, name="sequence_validate"), + url(r'^album_validate/(?P\d+)$', views.album_validate, name="album_validate"), + url(r'^plan_validate/(?P\d+)$', views.plan_validate, name="plan_validate"), - url(r'^create_request$', views.create_request), - url(r'^create_sequence/(?P\d+)$', views.create_sequence), - url(r'^create_album/(?P\d+)$', views.create_album), - url(r'^create_plan/(?P\d+)$', views.create_plan), + url(r'^create_request$', views.create_request, name="create_request"), + url(r'^create_sequence/(?P\d+)$', views.create_sequence, name="create_sequence"), + url(r'^create_album/(?P\d+)$', views.create_album, name="create_album"), + url(r'^create_plan/(?P\d+)$', views.create_plan, name="create_plan"), - url(r'^submit_request/(?P\d+)$', views.submit_request), - url(r'^unsubmit_request/(?P\d+)$', views.unsubmit_request), + url(r'^submit_request/(?P\d+)$', views.submit_request, name="submit_request"), + url(r'^unsubmit_request/(?P\d+)$', views.unsubmit_request, name="unsubmit_request"), - url(r'^export_request/(?P\d+)$', views.export_request), + url(r'^export_request/(?P\d+)$', views.export_request, name="export_request"), + url(r'^import_request$', views.import_request, name="import_request"), ] diff --git a/src/routine_manager/validators.py b/src/routine_manager/validators.py index cc1b3be..e1d968f 100644 --- a/src/routine_manager/validators.py +++ b/src/routine_manager/validators.py @@ -1,5 +1,19 @@ from pyrosapp.models import Sequence +def check_plan_validity(plan): + """ + Checks if a plan is complete, and save its status in DB + + A plan is complete if His name, Filter, Duration and Nb_images are set + :returns : a bool equal to True if the request was submitted but incomplete + """ + + if plan.name == None or plan.filter == None or plan.duration <= 0 or plan.nb_images <= 0: + plan.complete = False + else: + plan.complete = True + plan.save() + return check_album_validity(plan.album) def check_album_validity(alb): """ @@ -16,6 +30,7 @@ def check_album_validity(alb): alb.save() return check_sequence_validity(alb.sequence) + def check_sequence_validity(seq): """ Computes the sequence duration diff --git a/src/routine_manager/views.py b/src/routine_manager/views.py index 44a8e59..cd94546 100644 --- a/src/routine_manager/views.py +++ b/src/routine_manager/views.py @@ -3,10 +3,11 @@ from pyrosapp.models import * from django.db.models import Q from django.contrib.auth.decorators import login_required from .forms import RequestForm, SequenceForm, AlbumForm, PlanForm -from .validators import check_album_validity, check_sequence_validity, check_request_validity +from .validators import check_plan_validity, check_album_validity, check_sequence_validity, check_request_validity from .RequestSerializer import RequestSerializer import scheduler +""" XML Export / Import utils """ from wsgiref.util import FileWrapper from django.utils.encoding import smart_str from django.http import HttpResponse @@ -275,7 +276,7 @@ def action_plan(request, plan_id, action, status=0, message=""): message = "You can't edit a submitted request" action = "view" - if check_album_validity(plan.album) == True: + if check_plan_validity(plan) == True: return redirect(unsubmit_request, req_id) if action == "edit": form = PlanForm(instance=plan) @@ -422,7 +423,7 @@ def export_request(request, req_id): req = Request.objects.get(id=req_id) if req.complete == False: message = "Request must be completely valid to be serialized" - return redirect(action_request, req_id=req_id, action="view", status=1, message=message) + return redirect(action_request, req_id=req_id, action="view", status=-1, message=message) file_name = "saved_requests/request" + str(req.id) + ".xml" rs = RequestSerializer() @@ -436,3 +437,29 @@ def export_request(request, req_id): response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(os.path.basename(file_name)) # same here return response + +@login_required +def import_request(request): + """ + Ask for a XML file, parse it and create a request in DB + Don't do anything if there is a single error into the file + """ + + if request.method == "POST": + file = request.FILES.get("request_file") + if file.size > 1000000: + status = -1 + message = "File is too big (more than 1 000 000 bytes)" + else: + rs = RequestSerializer() + message = rs.unserialize(file.read(), request.user.pyros_user) + if message != "": + status = -1 + else: + status = 1 + message = "Request imported successfully. Please check it before submitting for scheduling." + else: + status = -1 + message = "Internal error" + + return redirect(requests_list, status=status, message=message) diff --git a/src/saved_requests/empty b/src/saved_requests/empty new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/saved_requests/empty diff --git a/src/saved_requests/request50.xml b/src/saved_requests/request50.xml new file mode 100644 index 0000000..844c064 --- /dev/null +++ b/src/saved_requests/request50.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/scheduler/urls.py b/src/scheduler/urls.py index d04c6e1..3749146 100644 --- a/src/scheduler/urls.py +++ b/src/scheduler/urls.py @@ -5,6 +5,6 @@ from django.conf import settings from django.conf.urls.static import static urlpatterns = [ - url(r'^$', views.current_schedule), - url(r'^simulation$', views.schedule_simulation), + url(r'^$', views.current_schedule, name="current_schedule"), + url(r'^simulation$', views.schedule_simulation, name="schedule_simulation"), ] \ No newline at end of file diff --git a/src/templates/base.html b/src/templates/base.html index 745b417..3862306 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -47,23 +47,23 @@
diff --git a/src/user_manager/templates/user_manager/home_user_creation.html b/src/user_manager/templates/user_manager/home_user_creation.html index 1a07271..0adf187 100644 --- a/src/user_manager/templates/user_manager/home_user_creation.html +++ b/src/user_manager/templates/user_manager/home_user_creation.html @@ -7,7 +7,7 @@
- + {% csrf_token %}

diff --git a/src/user_manager/urls.py b/src/user_manager/urls.py index 5dcccfd..a5e0206 100644 --- a/src/user_manager/urls.py +++ b/src/user_manager/urls.py @@ -2,9 +2,9 @@ from django.conf.urls import url from . import views urlpatterns = [ - url(r'^create$', views.create_user), - url(r'^creation_validate$', views.user_signup_validation), - url(r'^login$', views.login_validation), - url(r'^profile$', views.profile), - url(r'^logout$', views.user_logout), + url(r'^create$', views.create_user, name="create_user"), + url(r'^creation_validate$', views.user_signup_validation, name="user_signup_validation"), + url(r'^login$', views.login_validation, name="login_validation"), + url(r'^profile$', views.profile, name="profile"), + url(r'^logout$', views.user_logout, name="user_logout"), ] -- libgit2 0.21.2