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