Commit 3dbda6a041c1d5f50b76c384f0d97452b7079431

Authored by haribo
1 parent eea995c9
Exists in master and in 1 other branch dev

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
... ... @@ -60,11 +60,12 @@ PROJECT STRUCTURE:
60 60 --------------------------------------------------------------------------------------------
61 61 CURRENT VERSION
62 62  
63   -Date: 16/06/2016
  63 +Date: 17/06/2016
64 64 By: Paul Carensac
65   -Version: 0.7.3
66   -Export XML + download
67   -Issues (closed): https://projects.irap.omp.eu/issues/3827
  65 +Version: 0.7.4
  66 +Import XML + Changed deprecated reverse by dotting path in templates (links)
  67 +Warning : DB updated
  68 +Issues (closed): https://projects.irap.omp.eu/issues/3811
68 69 Major current version (0.7): https://projects.irap.omp.eu/versions/117
69 70  
70 71 ROADMAP: https://projects.irap.omp.eu/projects/pyros/roadmap
... ...
src/alert_manager/templates/alert_manager/alert_simulation.html
... ... @@ -15,7 +15,7 @@
15 15 <br>
16 16 <center>
17 17 <div class="row">
18   - <a href="{% url "alert_manager.views.alert_simulation_start" %}" class="btn btn-lg btn-info">
  18 + <a href="{% url "alert_simulation_start" %}" class="btn btn-lg btn-info">
19 19 Simulate an alert !
20 20 </a>
21 21 </div>
... ...
src/alert_manager/templates/alert_manager/alerts.html
... ... @@ -29,7 +29,7 @@
29 29 <td align="center">
30 30 {{ alert.strategyobs.name }}
31 31 &nbsp &nbsp
32   - <a href="{% url "alert_manager.views.change_obs_strategy" alert.id %}"
  32 + <a href="{% url "change_obs_strategy" alert.id %}"
33 33 class="btn btn-primary" type="a">
34 34 Change
35 35 </a>
... ...
src/alert_manager/templates/alert_manager/strategy_change.html
... ... @@ -11,7 +11,7 @@
11 11  
12 12 <div class="row">
13 13 <h3>Select a new observation strategy for alert {{ alert.request.name }}:</h3>
14   - <form action="{% url 'alert_manager.views.change_obs_strategy_validate' alert.id %}" method="post">
  14 + <form action="{% url 'change_obs_strategy_validate' alert.id %}" method="post">
15 15 {% csrf_token %}
16 16 {% for strategy in strategies %}
17 17 <div class="row">
... ... @@ -33,7 +33,7 @@
33 33 </div>
34 34  
35 35 <div class="row">
36   - <a href="{% url "alert_manager.views.alerts_list" %}" class="btn btn-sm btn-primary" type="a">Back to alerts list</a>
  36 + <a href="{% url "alerts_list" %}" class="btn btn-sm btn-primary" type="a">Back to alerts list</a>
37 37 </div>
38 38 </div><!-- /#page-wrapper -->
39 39 {% endblock %}
... ...
src/alert_manager/urls.py
... ... @@ -2,9 +2,9 @@ from django.conf.urls import url
2 2 from . import views
3 3  
4 4 urlpatterns = [
5   - url(r'^simulation$', views.alert_simulation),
6   - url(r'^simulation/start$', views.alert_simulation_start),
7   - url(r'^change_obs_strategy/(?P<alert_id>\d+)$', views.change_obs_strategy),
8   - url(r'^change_obs_strategy_validate/(?P<alert_id>\d+)$', views.change_obs_strategy_validate),
9   - url(r'^alerts$', views.alerts_list),
  5 + url(r'^simulation$', views.alert_simulation, name="alert_simulation"),
  6 + url(r'^simulation/start$', views.alert_simulation_start, name="alert_simulation_start"),
  7 + url(r'^change_obs_strategy/(?P<alert_id>\d+)$', views.change_obs_strategy, name="change_obs_strategy"),
  8 + url(r'^change_obs_strategy_validate/(?P<alert_id>\d+)$', views.change_obs_strategy_validate, name="change_obs_strategy_validate"),
  9 + url(r'^alerts$', views.alerts_list, name='alerts_list'),
10 10 ]
... ...
src/routine_manager/RequestSerializer.py
1 1 from pyrosapp.models import *
  2 +import pyrosapp
2 3 import xml.etree.ElementTree as ET
3 4 import sys
4 5 from xml.dom import minidom
  6 +from .validators import check_plan_validity
  7 +import re
  8 +from decimal import Decimal
5 9  
6 10 def prettify(elem):
7 11 """
... ... @@ -38,12 +42,156 @@ class RequestSerializer():
38 42 with open(file_name, "w") as file:
39 43 file.write(prettify(request))
40 44  
41   - def unserialize(self, file_name):
  45 + def unserialize(self, xml_data, pyros_user):
42 46 """
43 47 Unserializes the request read into file_name
44 48 Throws exceptions in case of invalid file or values
45 49  
46 50 Directly saves the objects in DB
47 51 The request still need to be submitted afterward !
  52 +
  53 + :returns : "" (empty string) in case of success, error message (string) instead
48 54 """
49   - pass
  55 +
  56 + try:
  57 + root = ET.fromstring(xml_data)
  58 + except ET.ParseError as E:
  59 + return "Invalid file : " + str(E)
  60 +
  61 + self.pyros_user = pyros_user
  62 + self.request = None
  63 +
  64 + """ self.sequences will be a [(seq, album_list), ...], and same thing for album """
  65 + self.sequences = []
  66 + ret = self.unserialize_request(root)
  67 + if ret != "":
  68 + return ret
  69 +
  70 + self.request.save()
  71 + for sequence, albums in self.sequences:
  72 + sequence.request = self.request
  73 + sequence.save()
  74 + for album, plans in albums:
  75 + album.sequence = sequence
  76 + album.save()
  77 + for plan in plans:
  78 + plan.album = album
  79 + plan.save()
  80 + check_plan_validity(plan)
  81 +
  82 + return ""
  83 +
  84 + def unserialize_request(self, request):
  85 + if request.tag != "request":
  86 + return "Main object should be a request (found %s instead)" % (request.tag,)
  87 + possible_attribs = ["name", "scientific_program", "target_type"]
  88 +
  89 + self.request = Request(pyros_user=self.pyros_user, is_alert=False, complete=False, submitted=False)
  90 +
  91 + for name, value in request.attrib.items():
  92 + if name not in possible_attribs:
  93 + return "Unknown attribute %s in request" % (name,)
  94 + if name == "scientific_program":
  95 + try:
  96 + sp = ScientificProgram.objects.get(name=value)
  97 + self.request.scientific_program = sp
  98 + except Exception as E:
  99 + print(str(E))
  100 + return "Invalid scientific program %s" % (value,)
  101 + else:
  102 + self.request.__dict__[name] = value
  103 +
  104 + for sequence in request:
  105 + ret = self.unserialize_sequence(sequence)
  106 + if ret != "":
  107 + return ret
  108 + return ""
  109 +
  110 + def unserialize_sequence(self, sequence):
  111 + if sequence.tag != "sequence":
  112 + return "A request can only have 'sequence' children (found %s instead)" % (sequence.tag,)
  113 + possible_attribs = ["name", "target_coords", "jd1", "jd2", "duration"]
  114 +
  115 + seq = Sequence(request=self.request, status=Sequence.INCOMPLETE)
  116 +
  117 + for name, value in sequence.attrib.items():
  118 + if name not in possible_attribs:
  119 + return "Unknown attribute %s in sequence" % (name,)
  120 + if name == "name":
  121 + seq.name = value
  122 + elif name == "target_coords":
  123 + seq.target_coords = value
  124 + elif name == "jd1":
  125 + seq.jd1 = Decimal(value)
  126 + elif name == "jd2":
  127 + seq.jd2 = Decimal(value)
  128 + elif name == "duration":
  129 + seq.duration = Decimal(value)
  130 +
  131 + # faire des checks ?? j'imagine
  132 + album_list = []
  133 + self.sequences.append((seq, album_list))
  134 +
  135 + for album in sequence:
  136 + ret = self.unserialize_album(album, seq, album_list)
  137 + if ret != "":
  138 + return ret
  139 + return ""
  140 +
  141 + def unserialize_album(self, album, sequence, album_list):
  142 + if album.tag != "album":
  143 + return "A sequence can only have 'album' children (found %s instead)" % (album.tag,)
  144 + possible_attribs = ["name", "detector"]
  145 +
  146 + alb = Album(sequence=sequence)
  147 +
  148 + for name, value in album.attrib.items():
  149 + if name not in possible_attribs:
  150 + return "Unknown attribute %s in album" % (name,)
  151 + if name == "detector":
  152 + try:
  153 + detector = Detector.objects.get(device__name=value)
  154 + alb.detector = detector
  155 + except Exception as E:
  156 + print(str(E))
  157 + return "Invalid detector %s" % (value,)
  158 + elif name == "name":
  159 + alb.name = value
  160 + plan_list = []
  161 + album_list.append((alb, plan_list))
  162 +
  163 + for plan in album:
  164 + ret = self.unserialize_plan(plan, alb, plan_list)
  165 + if ret != "":
  166 + return ret
  167 + return ""
  168 +
  169 +
  170 + def unserialize_plan(self, plan, album, plan_list):
  171 + if plan.tag != "plan":
  172 + return "An album can only have 'plan' children (found %s instead)" % (plan.tag,)
  173 + possible_attribs = ["name", "filter", "duration", "nb_images"]
  174 +
  175 + pl = Plan(album=album)
  176 +
  177 + for name, value in plan.attrib.items():
  178 + if name not in possible_attribs:
  179 + return "Unknown attribute %s in plan" % (name,)
  180 + if name == "filter":
  181 + try:
  182 + filter = Filter.objects.get(device__name=value)
  183 + pl.filter = filter
  184 + except Exception as E:
  185 + return "Invalid filter %s" % (value,)
  186 + elif name == "name":
  187 + pl.name = value
  188 + elif name == "duration":
  189 + pl.duration = Decimal(value)
  190 + elif name == "nb_images":
  191 + pl.nb_images = int(value)
  192 +
  193 + # quelques checks ...
  194 +
  195 + plan_list.append(pl)
  196 + return ""
  197 +
... ...
src/routine_manager/templates/routine_manager/edit_base.html
... ... @@ -13,19 +13,19 @@
13 13 <ul class="nav nav-tabs col-lg-4" style="margin-bottom: 15px;">
14 14  
15 15 {% if depth_level > 0 %}
16   - <li {% if depth_level == 1 %}class="active"{% endif %}><a href="{% url "routine_manager.views.action_request" req_id action%}" >Request Info</a></li>
  16 + <li {% if depth_level == 1 %}class="active"{% endif %}><a href="{% url "action_request" req_id action%}" >Request Info</a></li>
17 17 {% endif %}
18 18  
19 19 {% if depth_level > 1 %}
20   - <li {% if depth_level == 2 %}class="active"{% endif %}><a href="{% url "routine_manager.views.action_sequence" seq_id action%}" >Sequence Info</a></li>
  20 + <li {% if depth_level == 2 %}class="active"{% endif %}><a href="{% url "action_sequence" seq_id action%}" >Sequence Info</a></li>
21 21 {% endif %}
22 22  
23 23 {% if depth_level > 2 %}
24   - <li {% if depth_level == 3 %}class="active"{% endif %}><a href="{% url "routine_manager.views.action_album" alb_id action%}" >Album Info</a></li>
  24 + <li {% if depth_level == 3 %}class="active"{% endif %}><a href="{% url "action_album" alb_id action%}" >Album Info</a></li>
25 25 {% endif %}
26 26  
27 27 {% if depth_level > 3 %}
28   - <li {% if depth_level == 4 %}class="active"{% endif %}><a href="{% url "routine_manager.views.action_plan" plan_id action%}" >Plan Info</a></li>
  28 + <li {% if depth_level == 4 %}class="active"{% endif %}><a href="{% url "action_plan" plan_id action%}" >Plan Info</a></li>
29 29 {% endif %}
30 30 </ul>
31 31  
... ... @@ -34,20 +34,20 @@
34 34 <div class="row col-lg-4">
35 35 {% if req.submitted == False %}
36 36 {% if req.complete == True %}
37   - <a href="{% url "routine_manager.views.submit_request" req.id %}" class="btn btn-info" onclick="return confirm('The request will be validated, and the sequences scheduled')"
  37 + <a href="{% url "submit_request" req.id %}" class="btn btn-info" onclick="return confirm('The request will be validated, and the sequences scheduled')"
38 38 title="The request will be validated, and the sequences scheduled">Submit request for scheduling</a>
39 39 {% else %}
40 40 <a class="btn btn-info" onclick="return confirm('The request must be complete to be submitted')"
41 41 title="The request must be complete to be submitted">Submit request for scheduling</a>
42 42 {% endif %}
43 43 {% else %}
44   - <a href="{% url "routine_manager.views.unsubmit_request" req.id %}" class="btn btn-warning" onclick="return confirm('The request will be unvalidated, and the unexecuted sequences, unscheduled')"
  44 + <a href="{% url "unsubmit_request" req.id %}" class="btn btn-warning" onclick="return confirm('The request will be unvalidated, and the unexecuted sequences, unscheduled')"
45 45 title="The request will be unvalidated, and the unexecuted sequences, unscheduled">Unsubmit request</a>
46 46 {% endif %}
47 47 </div>
48 48  
49 49 <div class="row col-lg-4">
50   - <a href="{% url "routine_manager.views.export_request" req.id %}" class="btn btn-info">Export request as XML file</a>
  50 + <a href="{% url "export_request" req.id %}" class="btn btn-info">Export request as XML file</a>
51 51 </div>
52 52  
53 53 <div class="row col-lg-4">
... ... @@ -80,25 +80,25 @@
80 80 <div class="panel-heading"><h3>Summary</h3></div>
81 81 <div class="well" style="overflow:hidden; height:350px;">
82 82 <div>
83   - <a class="btn btn-sm {% if req.complete %}btn-success{% else %}btn-danger{% endif %}" href="{% url "routine_manager.views.action_request" req_id action%}" >Request: {{ req.name }}</a>
  83 + <a class="btn btn-sm {% if req.complete %}btn-success{% else %}btn-danger{% endif %}" href="{% url "action_request" req_id action%}" >Request: {{ req.name }}</a>
84 84 {% if depth_level == 1 %}<span class="label label-info">{{action}}ing ...</span>{% endif %}
85 85 </div>
86 86 {% for seq in req.sequences.all %}
87 87  
88 88 <div>
89   - <a class="btn btn-sm {% if seq.status != "INCPL" %}btn-success{% else %}btn-danger{% endif %}" href="{% url "routine_manager.views.action_sequence" seq.id action%}" style="margin-left: 60px" >Sequence: {{ seq.name }}</a>
  89 + <a class="btn btn-sm {% if seq.status != "INCPL" %}btn-success{% else %}btn-danger{% endif %}" href="{% url "action_sequence" seq.id action%}" style="margin-left: 60px" >Sequence: {{ seq.name }}</a>
90 90 {% if depth_level == 2 and seq_id == seq.id %}<span class="label label-info">{{action}}ing ...</span>{% endif %}
91 91 </div>
92 92 {% for album in seq.albums.all %}
93 93  
94 94 <div>
95   - <a class="btn btn-sm {% if album.complete %}btn-success{% else %}btn-danger{% endif %}" href="{% url "routine_manager.views.action_album" album.id action%}" style="margin-left: 120px" >Album: {{ album.name }}</a>
  95 + <a class="btn btn-sm {% if album.complete %}btn-success{% else %}btn-danger{% endif %}" href="{% url "action_album" album.id action%}" style="margin-left: 120px" >Album: {{ album.name }}</a>
96 96 {% if depth_level == 3 and alb_id == album.id %}<span class="label label-info">{{action}}ing ...</span>{% endif %}
97 97 </div>
98 98 {% for plan in album.plans.all %}
99 99  
100 100 <div>
101   - <a class="btn btn-sm {% if plan.complete %}btn-success{% else %}btn-danger{% endif %}" href="{% url "routine_manager.views.action_plan" plan.id action%}" style="margin-left: 180px" >Plan: {{ plan.name }}</a>
  101 + <a class="btn btn-sm {% if plan.complete %}btn-success{% else %}btn-danger{% endif %}" href="{% url "action_plan" plan.id action%}" style="margin-left: 180px" >Plan: {{ plan.name }}</a>
102 102 {% if depth_level == 4 and plan_id == plan.id %}<span class="label label-info">{{action}}ing ...</span>{% endif %}
103 103 </div>
104 104  
... ...
src/routine_manager/templates/routine_manager/requests_list.html
... ... @@ -10,10 +10,32 @@
10 10  
11 11 <div class="row">
12 12 <div class="col-lg-5">
13   - <h3>List of Routine Requests in the database</h3>
  13 + <h3>Actions</h3>
14 14 </div>
  15 +</div>
15 16  
  17 +<div class="row">
  18 + <div class="col-lg-5">
  19 + <form action="{% url "import_request" %}" method="post" enctype="multipart/form-data">
  20 + {% csrf_token %}
  21 + <label class="btn btn-primary btn-file">
  22 + Import an XML file as a request <input type="file" onchange="this.form.submit()" name="request_file" style="display:none;"/>
  23 + </label>
  24 + </form>
  25 + </div>
  26 +</div>
16 27  
  28 +<div class="row" style="margin-top:10px;">
  29 + <div class="col-lg-12 text-left">
  30 + <a href="{% url "create_request" %}"><button class="btn btn-primary">Create manually a new
  31 + observation request</button></a>
  32 + </div>
  33 +</div>
  34 +
  35 +<div class="row">
  36 + <div class="col-lg-5">
  37 + <h3>List of Routine Requests in the database</h3>
  38 + </div>
17 39 </div>
18 40  
19 41 <div class="row">
... ... @@ -40,7 +62,7 @@
40 62 <tbody>
41 63 {% for row in requests %}
42 64 <tr>
43   - <td><a href="{% url "routine_manager.views.action_request" row.req.id 'view' %}">{{ row.req.name }}</a></td>
  65 + <td><a href="{% url "action_request" row.req.id 'view' %}">{{ row.req.name }}</a></td>
44 66 <td>{{ row.req.created }}</td>
45 67 <td>{{ row.req.updated }}</td>
46 68 <td>{{ row.req.type }}</td>
... ... @@ -50,10 +72,10 @@
50 72 <td>
51 73 <center>
52 74 {% if row.req.submitted == False %}
53   - <a href="{% url "routine_manager.views.action_request" row.req.id 'edit' %}" class="btn btn-primary">Edit</a>
  75 + <a href="{% url "action_request" row.req.id 'edit' %}" class="btn btn-primary">Edit</a>
54 76 {% endif %}
55   - <a href="{% url "routine_manager.views.action_request" row.req.id 'view' %}" class="btn btn-primary">View</a>
56   - <a href="{% url "routine_manager.views.action_request" row.req.id 'delete' %}" class="btn btn-danger"
  77 + <a href="{% url "action_request" row.req.id 'view' %}" class="btn btn-primary">View</a>
  78 + <a href="{% url "action_request" row.req.id 'delete' %}" class="btn btn-danger"
57 79 onclick="return confirm('Are you sure you want to delete this request ?')">Delete</a>
58 80 </center>
59 81 </td>
... ... @@ -71,13 +93,6 @@
71 93  
72 94 </div>
73 95  
74   -<div class="row">
75   - <div class="col-lg-12 text-left">
76   - <a href="{% url "routine_manager.views.create_request" %}"><button class="btn btn-primary">Create a new
77   - observation request</button></a>
78   - </div>
79   -</div>
80   -
81 96  
82 97  
83 98  
... ...
src/routine_manager/templates/routine_manager/view_album.html
... ... @@ -5,7 +5,7 @@
5 5 {% endblock %}
6 6  
7 7 {% block fields %}
8   - <form action="{% url "routine_manager.views.album_validate" alb.id %}" method="post" enctype="multipart/form-data">
  8 + <form action="{% url "album_validate" alb.id %}" method="post" enctype="multipart/form-data">
9 9 {% csrf_token %}
10 10 <br>
11 11  
... ... @@ -69,11 +69,11 @@
69 69 <td>
70 70 <center>
71 71 {% if action == 'edit' %}
72   - <a href="{% url "routine_manager.views.action_plan" plan.id 'edit' %}" class="btn btn-primary">Edit</a>
73   - <a href="{% url "routine_manager.views.action_plan" plan.id 'delete' %}" class="btn btn-danger"
  72 + <a href="{% url "action_plan" plan.id 'edit' %}" class="btn btn-primary">Edit</a>
  73 + <a href="{% url "action_plan" plan.id 'delete' %}" class="btn btn-danger"
74 74 onclick="return confirm('Are you sure you want to delete this plan ?')">Delete</a>
75 75 {% else %}
76   - <a href="{% url "routine_manager.views.action_plan" plan.id 'view' %}" class="btn btn-primary"><span class="glyphicon glyphicon-e"></span></a>
  76 + <a href="{% url "action_plan" plan.id 'view' %}" class="btn btn-primary"><span class="glyphicon glyphicon-e"></span></a>
77 77 {% endif %}
78 78 </center>
79 79 </td>
... ...
src/routine_manager/templates/routine_manager/view_plan.html
... ... @@ -5,7 +5,7 @@
5 5 {% endblock %}
6 6  
7 7 {% block fields %}
8   - <form action="{% url "routine_manager.views.plan_validate" plan.id %}" method="post" enctype="multipart/form-data">
  8 + <form action="{% url "plan_validate" plan.id %}" method="post" enctype="multipart/form-data">
9 9 {% csrf_token %}
10 10 <br>
11 11  
... ...
src/routine_manager/templates/routine_manager/view_request.html
... ... @@ -6,7 +6,7 @@
6 6  
7 7  
8 8 {% block fields %}
9   - <form action="{% url "routine_manager.views.request_validate" req.id %}" method="post" enctype="multipart/form-data">
  9 + <form action="{% url "request_validate" req.id %}" method="post" enctype="multipart/form-data">
10 10 {% csrf_token %}
11 11 <br>
12 12  
... ... @@ -67,11 +67,11 @@
67 67 <td>
68 68 <center>
69 69 {% if action == 'edit' %}
70   - <a href="{% url "routine_manager.views.action_sequence" seq.id 'edit' %}" class="btn btn-primary">Edit</a>
71   - <a href="{% url "routine_manager.views.action_sequence" seq.id 'delete' %}" class="btn btn-danger"
  70 + <a href="{% url "action_sequence" seq.id 'edit' %}" class="btn btn-primary">Edit</a>
  71 + <a href="{% url "action_sequence" seq.id 'delete' %}" class="btn btn-danger"
72 72 onclick="return confirm('Are you sure you want to delete this sequence ?')">Delete</a>
73 73 {% else %}
74   - <a href="{% url "routine_manager.views.action_sequence" seq.id 'view' %}" class="btn btn-primary">View</a>
  74 + <a href="{% url "action_sequence" seq.id 'view' %}" class="btn btn-primary">View</a>
75 75 {% endif %}
76 76 </center>
77 77 </td>
... ...
src/routine_manager/templates/routine_manager/view_sequence.html
... ... @@ -5,7 +5,7 @@
5 5 {% endblock %}
6 6  
7 7 {% block fields %}
8   - <form action="{% url "routine_manager.views.sequence_validate" seq.id %}" method="post" enctype="multipart/form-data">
  8 + <form action="{% url "sequence_validate" seq.id %}" method="post" enctype="multipart/form-data">
9 9 {% csrf_token %}
10 10 <br>
11 11  
... ... @@ -65,11 +65,11 @@
65 65 <td>
66 66 <center>
67 67 {% if action == 'edit' %}
68   - <a href="{% url "routine_manager.views.action_album" alb.id 'edit' %}" class="btn btn-primary">Edit</a>
69   - <a href="{% url "routine_manager.views.action_album" alb.id 'delete' %}" class="btn btn-danger"
  68 + <a href="{% url "action_album" alb.id 'edit' %}" class="btn btn-primary">Edit</a>
  69 + <a href="{% url "action_album" alb.id 'delete' %}" class="btn btn-danger"
70 70 onclick="return confirm('Are you sure you want to delete this album ?')">Delete</a>
71 71 {% else %}
72   - <a href="{% url "routine_manager.views.action_album" alb.id 'view' %}" class="btn btn-primary">View</a>
  72 + <a href="{% url "action_album" alb.id 'view' %}" class="btn btn-primary">View</a>
73 73 {% endif %}
74 74 </center>
75 75 </td>
... ...
src/routine_manager/urls.py
... ... @@ -2,35 +2,36 @@ from django.conf.urls import url
2 2 from . import views
3 3  
4 4 urlpatterns = [
5   - url(r'^$', views.requests_list),
6   - url(r'^(?P<status>[-1,0,1])/(?P<message>[a-zA-Z0-9_ ]{1,100})$', views.requests_list),
  5 + url(r'^$', views.requests_list, name="requests_list"),
  6 + url(r'^(?P<status>-?\d)/(?P<message>.+)$', views.requests_list, name="requests_list"),
7 7  
8   - url(r'^action_request/(?P<req_id>\d+)/(?P<action>[a-z_]{1,20})$', views.action_request),
9   - url(r'^action_request/(?P<req_id>\d+)/(?P<action>[a-z_]{1,20})/(?P<status>[-1,0,1])/(?P<message>[a-zA-Z0-9_ ]{1,100})$', views.action_request),
  8 + url(r'^action_request/(?P<req_id>\d+)/(?P<action>[a-z_]{1,20})$', views.action_request, name="action_request"),
  9 + url(r'^action_request/(?P<req_id>\d+)/(?P<action>[a-z_]{1,20})/(?P<status>-?\d)/(?P<message>.+)$', views.action_request, name="action_request_message"),
10 10  
11   - url(r'^action_sequence/(?P<seq_id>\d+)/(?P<action>[a-z_]{1,20})$', views.action_sequence),
12   - url(r'^action_sequence/(?P<seq_id>\d+)/(?P<action>[a-z_]{1,20})/(?P<status>[-1,0,1])/(?P<message>[a-zA-Z0-9_ ]{1,100})$', views.action_sequence),
  11 + url(r'^action_sequence/(?P<seq_id>\d+)/(?P<action>[a-z_]{1,20})$', views.action_sequence, name="action_sequence"),
  12 + url(r'^action_sequence/(?P<seq_id>\d+)/(?P<action>[a-z_]{1,20})/(?P<status>-?\d)/(?P<message>.+)$', views.action_sequence, name="action_sequence_message"),
13 13  
14   - url(r'^action_album/(?P<alb_id>\d+)/(?P<action>[a-z_]{1,20})$', views.action_album),
15   - url(r'^action_album/(?P<alb_id>\d+)/(?P<action>[a-z_]{1,20})/(?P<status>[-1,0,1])/(?P<message>[a-zA-Z0-9_ ]{1,100})$', views.action_album),
  14 + url(r'^action_album/(?P<alb_id>\d+)/(?P<action>[a-z_]{1,20})$', views.action_album, name="action_album"),
  15 + url(r'^action_album/(?P<alb_id>\d+)/(?P<action>[a-z_]{1,20})/(?P<status>-?\d)/(?P<message>.+)$', views.action_album, name="action_album_message"),
16 16  
17   - url(r'^action_plan/(?P<plan_id>\d+)/(?P<action>[a-z_]{1,20})$', views.action_plan),
18   - url(r'^action_plan/(?P<plan_id>\d+)/(?P<action>[a-z_]{1,20})/(?P<status>[-1,0,1])/(?P<message>[a-zA-Z0-9_ ]{1,100})$', views.action_plan),
  17 + url(r'^action_plan/(?P<plan_id>\d+)/(?P<action>[a-z_]{1,20})$', views.action_plan, name="action_plan"),
  18 + url(r'^action_plan/(?P<plan_id>\d+)/(?P<action>[a-z_]{1,20})/(?P<status>-?\d)/(?P<message>.+)$', views.action_plan, name="action_plan_message"),
19 19  
20   - url(r'^request_validate/(?P<req_id>\d+)$', views.request_validate),
21   - url(r'^sequence_validate/(?P<seq_id>\d+)$', views.sequence_validate),
22   - url(r'^album_validate/(?P<alb_id>\d+)$', views.album_validate),
23   - url(r'^plan_validate/(?P<plan_id>\d+)$', views.plan_validate),
  20 + url(r'^request_validate/(?P<req_id>\d+)$', views.request_validate, name="request_validate"),
  21 + url(r'^sequence_validate/(?P<seq_id>\d+)$', views.sequence_validate, name="sequence_validate"),
  22 + url(r'^album_validate/(?P<alb_id>\d+)$', views.album_validate, name="album_validate"),
  23 + url(r'^plan_validate/(?P<plan_id>\d+)$', views.plan_validate, name="plan_validate"),
24 24  
25   - url(r'^create_request$', views.create_request),
26   - url(r'^create_sequence/(?P<req_id>\d+)$', views.create_sequence),
27   - url(r'^create_album/(?P<seq_id>\d+)$', views.create_album),
28   - url(r'^create_plan/(?P<alb_id>\d+)$', views.create_plan),
  25 + url(r'^create_request$', views.create_request, name="create_request"),
  26 + url(r'^create_sequence/(?P<req_id>\d+)$', views.create_sequence, name="create_sequence"),
  27 + url(r'^create_album/(?P<seq_id>\d+)$', views.create_album, name="create_album"),
  28 + url(r'^create_plan/(?P<alb_id>\d+)$', views.create_plan, name="create_plan"),
29 29  
30   - url(r'^submit_request/(?P<req_id>\d+)$', views.submit_request),
31   - url(r'^unsubmit_request/(?P<req_id>\d+)$', views.unsubmit_request),
  30 + url(r'^submit_request/(?P<req_id>\d+)$', views.submit_request, name="submit_request"),
  31 + url(r'^unsubmit_request/(?P<req_id>\d+)$', views.unsubmit_request, name="unsubmit_request"),
32 32  
33   - url(r'^export_request/(?P<req_id>\d+)$', views.export_request),
  33 + url(r'^export_request/(?P<req_id>\d+)$', views.export_request, name="export_request"),
  34 + url(r'^import_request$', views.import_request, name="import_request"),
34 35  
35 36 ]
36 37  
... ...
src/routine_manager/validators.py
1 1 from pyrosapp.models import Sequence
2 2  
  3 +def check_plan_validity(plan):
  4 + """
  5 + Checks if a plan is complete, and save its status in DB
  6 +
  7 + A plan is complete if His name, Filter, Duration and Nb_images are set
  8 + :returns : a bool equal to True if the request was submitted but incomplete
  9 + """
  10 +
  11 + if plan.name == None or plan.filter == None or plan.duration <= 0 or plan.nb_images <= 0:
  12 + plan.complete = False
  13 + else:
  14 + plan.complete = True
  15 + plan.save()
  16 + return check_album_validity(plan.album)
3 17  
4 18 def check_album_validity(alb):
5 19 """
... ... @@ -16,6 +30,7 @@ def check_album_validity(alb):
16 30 alb.save()
17 31 return check_sequence_validity(alb.sequence)
18 32  
  33 +
19 34 def check_sequence_validity(seq):
20 35 """
21 36 Computes the sequence duration
... ...
src/routine_manager/views.py
... ... @@ -3,10 +3,11 @@ from pyrosapp.models import *
3 3 from django.db.models import Q
4 4 from django.contrib.auth.decorators import login_required
5 5 from .forms import RequestForm, SequenceForm, AlbumForm, PlanForm
6   -from .validators import check_album_validity, check_sequence_validity, check_request_validity
  6 +from .validators import check_plan_validity, check_album_validity, check_sequence_validity, check_request_validity
7 7 from .RequestSerializer import RequestSerializer
8 8 import scheduler
9 9  
  10 +""" XML Export / Import utils """
10 11 from wsgiref.util import FileWrapper
11 12 from django.utils.encoding import smart_str
12 13 from django.http import HttpResponse
... ... @@ -275,7 +276,7 @@ def action_plan(request, plan_id, action, status=0, message=&quot;&quot;):
275 276 message = "You can't edit a submitted request"
276 277 action = "view"
277 278  
278   - if check_album_validity(plan.album) == True:
  279 + if check_plan_validity(plan) == True:
279 280 return redirect(unsubmit_request, req_id)
280 281 if action == "edit":
281 282 form = PlanForm(instance=plan)
... ... @@ -422,7 +423,7 @@ def export_request(request, req_id):
422 423 req = Request.objects.get(id=req_id)
423 424 if req.complete == False:
424 425 message = "Request must be completely valid to be serialized"
425   - return redirect(action_request, req_id=req_id, action="view", status=1, message=message)
  426 + return redirect(action_request, req_id=req_id, action="view", status=-1, message=message)
426 427  
427 428 file_name = "saved_requests/request" + str(req.id) + ".xml"
428 429 rs = RequestSerializer()
... ... @@ -436,3 +437,29 @@ def export_request(request, req_id):
436 437 response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(os.path.basename(file_name)) # same here
437 438  
438 439 return response
  440 +
  441 +@login_required
  442 +def import_request(request):
  443 + """
  444 + Ask for a XML file, parse it and create a request in DB
  445 + Don't do anything if there is a single error into the file
  446 + """
  447 +
  448 + if request.method == "POST":
  449 + file = request.FILES.get("request_file")
  450 + if file.size > 1000000:
  451 + status = -1
  452 + message = "File is too big (more than 1 000 000 bytes)"
  453 + else:
  454 + rs = RequestSerializer()
  455 + message = rs.unserialize(file.read(), request.user.pyros_user)
  456 + if message != "":
  457 + status = -1
  458 + else:
  459 + status = 1
  460 + message = "Request imported successfully. Please check it before submitting for scheduling."
  461 + else:
  462 + status = -1
  463 + message = "Internal error"
  464 +
  465 + return redirect(requests_list, status=status, message=message)
... ...
src/saved_requests/empty 0 โ†’ 100644
src/saved_requests/request50.xml 0 โ†’ 100644
... ... @@ -0,0 +1,16 @@
  1 +<?xml version="1.0" ?>
  2 +<request name="532871" scientific_program="GRB" target_type="aze">
  3 + <sequence duration="1.00000000" jd1="0E-8" jd2="10.00000000" name="532871_1" target_coords="azer">
  4 + <album detector="Cagire" name="532871_11">
  5 + <plan duration="1.0" filter="First infrared filter" name="532871_111" nb_images="5"/>
  6 + </album>
  7 + <album detector="Visible camera" name="532871_12">
  8 + <plan duration="1.0" filter="First visible filter" name="532871_121" nb_images="1"/>
  9 + </album>
  10 + </sequence>
  11 + <sequence duration="1.00000000" jd1="0E-8" jd2="10.00000000" name="532871_2" target_coords="azerty">
  12 + <album detector="Cagire" name="532871_21">
  13 + <plan duration="1.0" filter="Second infrared filter" name="532871_211" nb_images="3"/>
  14 + </album>
  15 + </sequence>
  16 +</request>
... ...
src/scheduler/urls.py
... ... @@ -5,6 +5,6 @@ from django.conf import settings
5 5 from django.conf.urls.static import static
6 6  
7 7 urlpatterns = [
8   - url(r'^$', views.current_schedule),
9   - url(r'^simulation$', views.schedule_simulation),
  8 + url(r'^$', views.current_schedule, name="current_schedule"),
  9 + url(r'^simulation$', views.schedule_simulation, name="schedule_simulation"),
10 10 ]
11 11 \ No newline at end of file
... ...
src/templates/base.html
... ... @@ -47,23 +47,23 @@
47 47 <div class="collapse navbar-collapse navbar-ex1-collapse">
48 48  
49 49 <ul class="nav navbar-nav side-nav">
50   - <li><a href="{% url "scheduler.views.schedule_simulation" %}">Schedule</a></li>
51   - <li><a href="{% url "dashboard.views.system" %}">System</a></li>
52   - <li><a href="{% url "alert_manager.views.alerts_list" %}">Alerts</a></li>
53   - <li><a href="{% url "routine_manager.views.requests_list" %}">Routines</a></li>
54   - <li><a href="{% url "dashboard.views.weather" %}">Weather</a></li>
55   - <li><a href="{% url "dashboard.views.site" %}">Site</a></li>
56   - <li><a href="{% url "dashboard.views.devices" %}">Devices</a></li>
57   - <li><a href="{% url "dashboard.views.users" %}">Users</a></li>
  50 + <li><a href="{% url "schedule_simulation" %}">Schedule</a></li>
  51 + <li><a href="{% url "system" %}">System</a></li>
  52 + <li><a href="{% url "alerts_list" %}">Alerts</a></li>
  53 + <li><a href="{% url "requests_list" %}">Routines</a></li>
  54 + <li><a href="{% url "weather" %}">Weather</a></li>
  55 + <li><a href="{% url "site" %}">Site</a></li>
  56 + <li><a href="{% url "devices" %}">Devices</a></li>
  57 + <li><a href="{% url "users" %}">Users</a></li>
58 58 </ul>
59 59  
60 60 <ul class="nav navbar-nav navbar-right navbar-user">
61 61  
62 62 <li class="dropdown alerts-dropdown">
63   - <a href="{% url "user_manager.views.profile" %}"><i class="fa fa-user"></i> {{ user.first_name }} <b class="caret"></b></a>
  63 + <a href="{% url "profile" %}"><i class="fa fa-user"></i> {{ user.first_name }} <b class="caret"></b></a>
64 64 </li>
65 65 <li class="dropdown user-dropdown">
66   - <a href="{% url "user_manager.views.user_logout" %}"><i class="fa fa-power-off"></i> Log Out</a>
  66 + <a href="{% url "user_logout" %}"><i class="fa fa-power-off"></i> Log Out</a>
67 67 </li>
68 68 </ul>
69 69  
... ...
src/user_manager/templates/user_manager/home_login.html
... ... @@ -5,7 +5,7 @@
5 5  
6 6  
7 7 <div class="form-group">
8   - <form action=" {% url "user_manager.views.login_validation" %}" method="post" enctype="multipart/form-data">
  8 + <form action=" {% url "login_validation" %}" method="post" enctype="multipart/form-data">
9 9 {% csrf_token %}
10 10 {% if next %}
11 11 <input class="form-control" type="hidden" name="next" value="{{ next }}" />
... ... @@ -29,7 +29,7 @@
29 29 </div>
30 30 <div class="row">
31 31 <input class="btn btn-primary" type="submit" value="Log In" />
32   - <a href="{% url "user_manager.views.create_user" %}" class="btn btn-primary">Subscription form</a>
  32 + <a href="{% url "create_user" %}" class="btn btn-primary">Subscription form</a>
33 33 </div>
34 34 </div>
35 35 <div class="row">
... ...
src/user_manager/templates/user_manager/home_user_creation.html
... ... @@ -7,7 +7,7 @@
7 7 <div class="form-group">
8 8  
9 9  
10   - <form action="{% url "user_manager.views.user_signup_validation" %}" method="post" enctype="multipart/form-data">
  10 + <form action="{% url "user_signup_validation" %}" method="post" enctype="multipart/form-data">
11 11 {% csrf_token %}
12 12 <div class="col-lg-3 text-left" >
13 13 <p></p>
... ...
src/user_manager/urls.py
... ... @@ -2,9 +2,9 @@ from django.conf.urls import url
2 2 from . import views
3 3  
4 4 urlpatterns = [
5   - url(r'^create$', views.create_user),
6   - url(r'^creation_validate$', views.user_signup_validation),
7   - url(r'^login$', views.login_validation),
8   - url(r'^profile$', views.profile),
9   - url(r'^logout$', views.user_logout),
  5 + url(r'^create$', views.create_user, name="create_user"),
  6 + url(r'^creation_validate$', views.user_signup_validation, name="user_signup_validation"),
  7 + url(r'^login$', views.login_validation, name="login_validation"),
  8 + url(r'^profile$', views.profile, name="profile"),
  9 + url(r'^logout$', views.user_logout, name="user_logout"),
10 10 ]
... ...