require login for gridftp view
[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             print env_formset.cleaned_data
164
165             desc = JobDescription(Credential(request.session['proxy']))
166
167             direct_map = ('arguments', 'note', 'grant', 'hosts', 'properties', 'queue', 'procs', 'wall_time', 'memory',
168                           'memory_per_slot', 'modules', 'native', 'notify', 'preprocess', '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             if form.cleaned_data['application']:
175                 desc.set_application(*form.cleaned_data['application'])
176             if form.cleaned_data['nodes']:
177                 desc.set_nodes(*form.cleaned_data['nodes'])
178             if form.cleaned_data['reservation']:
179                 desc.set_reservation(form.cleaned_data['reservation'])
180             if form.cleaned_data['watch_output']:
181                 desc.set_watch_output(form.cleaned_data['watch_output'], form.cleaned_data['watch_output_pattern'])
182             desc.env_variables += [(env['name'], env['value'])
183                                    for env in env_formset.cleaned_data if env and not env['DELETE']]
184             # TODO script
185             # TODO executable
186             # TODO input
187             # TODO stage_in
188             # TODO stage_out
189             # TODO monitoring
190
191             for prop in direct_map + ('application', 'nodes', 'env_variables', 'reservation', 'watch_output'):
192                 print prop, type(getattr(desc, prop)), repr(getattr(desc, prop))
193
194             print desc.xml_description
195
196         print repr(form.errors)
197         print repr(env_formset.errors)
198     else:
199         form = JobDescriptionForm()
200         env_formset = EnvFormSet()
201
202     errors = form.errors or (env_formset.is_bound and not env_formset.is_valid)
203
204     return render(request, 'qcg/job_new.html', {'form': form, 'env_formset': env_formset, 'errors': errors})
205
206
207 @login_required
208 def gridftp(request):
209     return render(request, 'qcg/gridftp.html')