initial work on submitting job logic
[qcg-portal.git] / qcg / views.py
1 # coding=utf-8
2 from datetime import datetime, timedelta
3 from django.conf import settings
4 from django.contrib.auth import REDIRECT_FIELD_NAME
5 from django.contrib.auth.decorators import login_required
6 from django.core.urlresolvers import reverse
7 from django.db.models import Q
8 from django.http import HttpResponse, QueryDict
9 from django.shortcuts import render, get_object_or_404
10 from django.utils.http import urlencode
11 from django.utils.timezone import UTC
12 from django_openid_auth.views import make_consumer
13 from openid.extensions import ax
14 from pyqcg import QCG
15 from pyqcg.description import JobDescription
16 from pyqcg.utils import Credential
17
18 from qcg.forms import FiltersForm, ColumnsForm, JobDescriptionForm, EnvFormSet
19 from qcg.utils import update_user_data, paginator_context
20
21
22 def index(request):
23     return render(request, 'qcg/base.html')
24
25
26 def openid_begin(request):
27     openid_request = make_consumer(request).begin(settings.OPENID_SSO_SERVER_URL)
28
29     fetch_request = ax.FetchRequest()
30     for (attr, alias) in [('http://axschema.org/namePerson/friendly', 'nickname'),
31                           ('http://axschema.org/contact/email', 'email'),
32                           ('http://axschema.org/namePerson', 'fullname'),
33                           ('http://openid.plgrid.pl/certificate/proxy', 'proxy'),
34                           ('http://openid.plgrid.pl/certificate/userCert', 'userCert'),
35                           ('http://openid.plgrid.pl/certificate/proxyPrivKey', 'proxyPrivKey'),
36                           ('http://openid.plgrid.pl/POSTresponse', 'POSTresponse')]:
37         fetch_request.add(ax.AttrInfo(attr, alias=alias, required=True))
38     openid_request.addExtension(fetch_request)
39
40     return_to = request.build_absolute_uri(reverse('openid-complete'))
41
42     redirect_to = request.GET.get(REDIRECT_FIELD_NAME)
43     if redirect_to:
44         return_to += '?' + urlencode({REDIRECT_FIELD_NAME: redirect_to})
45
46     return HttpResponse(openid_request.htmlMarkup(request.build_absolute_uri('/'), return_to))
47
48
49 search_fields = ('status_description', 'type', 'note', 'task_id', 'job__note', 'job__project', 'job__job_id',
50                  'allocations__status_description', 'allocations__processes_group_id', 'allocations__comment')
51
52
53 def parse_date(string):
54     return datetime.strptime(string.strip(), "%d.%m.%Y").replace(tzinfo=UTC())
55
56
57 @login_required
58 def jobs_list(request):
59     # QCG.start()
60     # update_user_data(request.user, request.session['proxy'])
61
62     tasks = request.user.tasks.order_by('-job__submission_time', '-submission_time') \
63         .select_related('job').prefetch_related('allocations__nodes')
64
65     filters = FiltersForm(request.GET)
66     selected_filters = []
67     if filters.is_valid():
68         keywords = filters.cleaned_data['keywords']
69         status = filters.cleaned_data['status']
70         host = filters.cleaned_data['host']
71         submission = filters.cleaned_data['submission']
72         finish = filters.cleaned_data['finish']
73
74         if keywords:
75             and_query = Q()
76
77             for q in keywords.split():
78                 or_query = Q()
79                 for field in search_fields:
80                     or_query |= Q(**{field + '__icontains': q})
81                 and_query &= or_query
82
83             tasks = tasks.filter(and_query)
84             selected_filters.append((keywords, 'keywords', keywords))
85
86         if status:
87             statuses = []
88             for s in status:
89                 si = int(s)
90                 statuses.extend(FiltersForm.STATUS_MAP[si])
91                 selected_filters.append((FiltersForm.STATUS_CHOICES_DICT[si], 'status', s))
92
93             tasks = tasks.filter(status__in=statuses)
94
95         if host:
96             tasks = tasks.filter(allocations__host_name__in=host)
97
98             host_dict = dict(filters.fields['host'].choices)
99             for h in host:
100                 selected_filters.append((host_dict[h], 'host', h))
101
102         if submission:
103             start, end = submission.split('-')
104
105             tasks = tasks.filter(submission_time__gte=parse_date(start),
106                                  submission_time__lte=parse_date(end) + timedelta(days=1))
107             selected_filters.append((u'Data zlecenia: ' + submission, 'submission', submission))
108
109         if finish:
110             start, end = finish.split('-')
111
112             tasks = tasks.filter(finish_time__gte=parse_date(start),
113                                  finish_time__lte=parse_date(end) + timedelta(days=1))
114             selected_filters.append((u'Data zakończenia: ' + finish, 'finish', finish))
115
116         tasks = tasks.distinct()
117
118     checked_status = {i: widget.is_checked() for i, widget in enumerate(filters['status'])}
119
120     columns = ColumnsForm(QueryDict(request.COOKIES.get('columns', '')))
121
122     displayed = None
123     if columns.is_valid():
124         displayed = {int(c) for c in columns.cleaned_data['columns']}
125
126     # if invalid or empty
127     if not displayed:
128         displayed = set(columns.fields['columns'].initial)
129
130     context = {'filters': filters, 'checked_status': checked_status, 'selected_filters': selected_filters,
131                'columns': ColumnsForm(initial={'columns': displayed}), 'displayed': displayed}
132
133     context.update(paginator_context(request, tasks))
134
135     return render(request, 'qcg/jobs.html', context)
136
137
138 @login_required
139 def job_details(request, job_id):
140     job = get_object_or_404(request.user.jobs.prefetch_related('tasks'), job_id=job_id)
141
142     return render(request, 'qcg/job.html', {'job': job})
143
144
145 @login_required
146 def task_details(request, job_id, task_id):
147     task = get_object_or_404(request.user.tasks.select_related('job').prefetch_related('allocations'),
148                              job__job_id=job_id, task_id=task_id)
149
150     return render(request, 'qcg/task.html', {'task': task})
151
152
153 @login_required
154 def job_new(request):
155     if request.method == 'POST':
156         QCG.start()
157
158         form = JobDescriptionForm(request.POST)
159         env_formset = EnvFormSet(request.POST)
160
161         if form.is_valid() and env_formset.is_valid():
162             print form.cleaned_data
163
164             desc = JobDescription(Credential(request.session['proxy']))
165
166             application = form.cleaned_data['application']
167             if '/' in application:
168                 app, ver = application.split('1', 1)
169                 desc.application.set_name(app)
170                 desc.application.set_version(ver)
171             else:
172                 desc.application.set_name(application)
173
174             # TODO script
175             # TODO executable
176             desc.arguments = form.cleaned_data['arguments']
177             desc.note = form.cleaned_data['note']
178             desc.grant = form.cleaned_data['grant']
179             desc.host_candidates = [(form.cleaned_data['host'], 'type?')]  # FIXME WTF ?!?
180             desc.properties = form.cleaned_data['properties']
181             # TODO queue
182             # TODO procs
183             # TODO nodes
184             desc.wall_time = timedelta(seconds=form.cleaned_data['wall_time'])  # FIXME odpowiedni typ pola
185             desc.memory = form.cleaned_data['memory']
186             desc.memory_per_slot = form.cleaned_data['memory_per_slot']
187             desc.variable = [(env['name'], env['value']) for env in env_formset.cleaned_data if not env['DELETE']]
188             desc.modules = form.cleaned_data['modules']
189             desc.natives = form.cleaned_data['native']
190             desc.reservation = ("LOCAL", form.cleaned_data['reservation'])
191             # TODO input
192             # TODO stage_in
193             # TODO stage_out
194             # TODO monitoring
195             # TODO notify_type
196             # TODO notify_address
197             # TODO watch_output_type
198             # TODO watch_output_address
199             # TODO watch_output_pattern
200             # TODO preprocess_type
201             # TODO preprocess_cmd
202             # TODO preprocess_script
203             # TODO postprocess_type
204             # TODO postprocess_cmd
205             # TODO postprocess_script
206             desc.persistent = form.cleaned_data['persistent']
207
208             for prop in ('arguments', 'note', 'grant', 'host_candidates', 'wall_time', 'memory',
209                          'memory_per_slot', 'properties', 'variable', 'modules', 'natives', 'persistent', 'reservation'):
210                 print prop, type(getattr(desc, prop)), repr(getattr(desc, prop))
211
212             print desc.xml_description
213
214     else:
215         form = JobDescriptionForm()
216         env_formset = EnvFormSet()
217
218     return render(request, 'qcg/job_new.html', {'form': form, 'env_formset': env_formset})