0be3d7327b033cdcadaa0f084dc10cb28200b6f7
[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             direct_map = ('application', 'arguments', 'note', 'grant', 'hosts', 'properties', 'queue', 'procs', 'nodes',
167                           'wall_time', 'memory', 'memory_per_slot', 'modules', 'native', 'notify', 'preprocess',
168                           'postprocess', 'persistent')
169
170             for name in direct_map:
171                 if form.cleaned_data[name]:
172                     setattr(desc, name, form.cleaned_data[name])
173
174             desc.reservation = ('LOCAL', form.cleaned_data['reservation'])
175             desc.watch_output = (form.cleaned_data['watch_output'], form.cleaned_data['watch_output_pattern'])
176             desc.env_variables += [(env['name'], env['value']) for env in env_formset.cleaned_data if not env['DELETE']]
177             # TODO script
178             # TODO executable
179             # TODO input
180             # TODO stage_in
181             # TODO stage_out
182             # TODO monitoring
183
184             for prop in direct_map + ('env_variables', 'reservation', 'watch_output'):
185                 print prop, type(getattr(desc, prop)), repr(getattr(desc, prop))
186
187             print desc.xml_description
188
189         print repr(form.errors)
190         print repr(env_formset.errors)
191     else:
192         form = JobDescriptionForm()
193         env_formset = EnvFormSet()
194
195     errors = form.errors or (env_formset.is_bound and not env_formset.is_valid)
196
197     return render(request, 'qcg/job_new.html', {'form': form, 'env_formset': env_formset, 'errors': errors})