1
|
|
|
################################################################# |
2
|
|
|
# MET v2 Metadate Explorer Tool |
3
|
|
|
# |
4
|
|
|
# This Software is Open Source. See License: https://github.com/TERENA/met/blob/master/LICENSE.md |
5
|
|
|
# Copyright (c) 2012, TERENA All rights reserved. |
6
|
|
|
# |
7
|
|
|
# This Software is based on MET v1 developed for TERENA by Yaco Sistemas, http://www.yaco.es/ |
8
|
|
|
# MET v2 was developed for TERENA by Tamim Ziai, DAASI International GmbH, http://www.daasi.de |
9
|
|
|
# Current version of MET has been revised for performance improvements by Andrea Biancini, |
10
|
|
|
# Consortium GARR, http://www.garr.it |
11
|
|
|
######################################################################################### |
12
|
|
|
|
13
|
|
|
import re, time |
14
|
|
|
import pytz |
15
|
|
|
import operator |
16
|
|
|
import simplejson as json |
17
|
|
|
import numpy as np |
18
|
|
|
from urllib import unquote |
19
|
|
|
from datetime import datetime |
20
|
|
|
from dateutil import tz |
21
|
|
|
|
22
|
|
|
from django.conf import settings |
23
|
|
|
from django.db.models import Count, Q |
24
|
|
|
from django.contrib import messages |
25
|
|
|
from django.contrib.auth import logout |
26
|
|
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger |
27
|
|
|
from django.core.urlresolvers import reverse |
28
|
|
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest |
29
|
|
|
from django.shortcuts import render_to_response, get_object_or_404 |
30
|
|
|
from django.template import RequestContext |
31
|
|
|
from django.utils.translation import ugettext_lazy as _ |
32
|
|
|
from django.utils import timezone |
33
|
|
|
|
34
|
|
|
from chartit import DataPool, Chart |
35
|
|
|
|
36
|
|
|
from datetime import datetime |
37
|
|
|
|
38
|
|
|
from met.metadataparser.decorators import user_can_edit |
39
|
|
|
from met.metadataparser.models import Federation, Entity, EntityStat, EntityCategory, Entity_Federations, TOP_LENGTH, FEDERATION_TYPES |
40
|
|
|
from met.metadataparser.forms import (FederationForm, EntityForm, EntityCommentForm, |
41
|
|
|
EntityProposalForm, ServiceSearchForm, ChartForm, SearchEntitiesForm) |
42
|
|
|
|
43
|
|
|
from met.metadataparser.summary_export import export_summary |
44
|
|
|
from met.metadataparser.query_export import export_query_set |
45
|
|
|
from met.metadataparser.entity_export import export_entity |
46
|
|
|
from met.metadataparser.xmlparser import DESCRIPTOR_TYPES |
47
|
|
|
from met.metadataparser.utils import send_mail |
48
|
|
|
|
49
|
|
|
if settings.PROFILE: |
50
|
|
|
from silk.profiling.profiler import silk_profile as profile |
51
|
|
|
else: |
52
|
|
|
from met.metadataparser.templatetags.decorators import noop_decorator as profile |
53
|
|
|
|
54
|
|
|
RESCUE_SLASH = re.compile(r"^(http(?:|s):/)([^/])") |
55
|
|
|
|
56
|
|
|
def increment_current_toplength(request): |
57
|
|
|
current_top_length = request.session.get('currentTopLength', TOP_LENGTH) |
58
|
|
|
current_top_length += TOP_LENGTH |
59
|
|
|
|
60
|
|
|
if current_top_length > Entity.objects.all().count(): |
61
|
|
|
current_top_length -= TOP_LENGTH |
62
|
|
|
|
63
|
|
|
request.session['currentTopLength'] = current_top_length |
64
|
|
|
return HttpResponseRedirect(reverse('most_federated_entities')) |
65
|
|
|
|
66
|
|
|
def decrement_current_toplength(request): |
67
|
|
|
current_top_length = request.session.get('currentTopLength', TOP_LENGTH) |
68
|
|
|
current_top_length -= TOP_LENGTH |
69
|
|
|
|
70
|
|
|
if current_top_length <= 0: |
71
|
|
|
current_top_length = TOP_LENGTH |
72
|
|
|
|
73
|
|
|
request.session['currentTopLength'] = current_top_length |
74
|
|
|
return HttpResponseRedirect(reverse('most_federated_entities')) |
75
|
|
|
|
76
|
|
|
def _index_export(export, export_format, objects): |
77
|
|
|
counters = ( |
78
|
|
|
('all', {}), |
79
|
|
|
('IDPSSO', {'types__xmlname': 'IDPSSODescriptor'}), |
80
|
|
|
('SPSSO', {'types__xmlname': 'SPSSODescriptor'}), |
81
|
|
|
) |
82
|
|
|
|
83
|
|
|
if not export in ['interfederations', 'federations', 'most_federated_entities']: |
84
|
|
|
return HttpResponseBadRequest('Not valid export query') |
85
|
|
|
|
86
|
|
|
if export == 'most_federated_entities': |
87
|
|
|
return export_query_set(export_format, objects['most_federated_entities'], |
88
|
|
|
'most_federated_entities', ('entityid', 'types', 'name', 'federations')) |
89
|
|
|
else: |
90
|
|
|
return export_summary(export_format, objects[export], |
91
|
|
|
'entity_set', '%s_summary' % export, |
92
|
|
|
counters) |
93
|
|
|
|
94
|
|
|
@profile(name='Index page') |
95
|
|
|
def index(request): |
96
|
|
|
ff = Federation.objects.all().order_by('name') |
97
|
|
|
federations = [] |
98
|
|
|
interfederations = [] |
99
|
|
|
for f in ff: |
100
|
|
|
if f.is_interfederation: |
101
|
|
|
interfederations.append(f) |
102
|
|
|
else: |
103
|
|
|
federations.append(f) |
104
|
|
|
|
105
|
|
|
cc = Entity.objects.values('federations__id', 'types__xmlname').annotate(Count('federations__id'), Count('types__xmlname')) |
106
|
|
|
counts = {} |
107
|
|
|
for curtype in DESCRIPTOR_TYPES: |
108
|
|
|
counts[curtype] = [] |
109
|
|
|
for c in cc: |
110
|
|
|
if c['types__xmlname'] == curtype: |
111
|
|
|
counts[curtype].append(c) |
112
|
|
|
counts['All'] = Entity.objects.values('federations__id').annotate(Count('federations__id')) |
113
|
|
|
|
114
|
|
|
totals = Entity.objects.values('types__xmlname').annotate(Count('types__xmlname')) |
115
|
|
|
|
116
|
|
|
fed_countries = Entity.objects.values('federations__country').annotate(Count('federations__country')) |
117
|
|
|
|
118
|
|
|
params = { |
119
|
|
|
'settings': settings, |
120
|
|
|
'interfederations': interfederations, |
121
|
|
|
'federations': federations, |
122
|
|
|
'fed_countries': fed_countries, |
123
|
|
|
'entity_types': DESCRIPTOR_TYPES, |
124
|
|
|
'federation_path': request.path, |
125
|
|
|
'counts': counts, |
126
|
|
|
'totals': totals, |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
export = request.GET.get('export', None) |
130
|
|
|
export_format = request.GET.get('format', None) |
131
|
|
|
if export and export_format: |
132
|
|
|
return _index_export(export, export_format, params) |
133
|
|
|
|
134
|
|
|
return render_to_response('metadataparser/index.html', params, context_instance=RequestContext(request)) |
135
|
|
|
|
136
|
|
|
@profile(name='Most Federated Entities page') |
137
|
|
|
def most_federated_entities(request): |
138
|
|
|
# Entities with count how many federations belongs to, and sorted by most first |
139
|
|
|
current_top_length = request.session.get('currentTopLength', TOP_LENGTH) |
140
|
|
|
most_federated_entities = Entity.get_most_federated_entities(maxlength=current_top_length, cache_expire=24*60*60) |
141
|
|
|
|
142
|
|
|
params = { |
143
|
|
|
'settings': settings, |
144
|
|
|
'most_federated_entities': most_federated_entities, |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
export = request.GET.get('export', None) |
148
|
|
|
export_format = request.GET.get('format', None) |
149
|
|
|
if export and export_format: |
150
|
|
|
return _index_export(export, export_format, params) |
151
|
|
|
|
152
|
|
|
return render_to_response('metadataparser/most_federated_entities.html', params, context_instance=RequestContext(request)) |
153
|
|
|
|
154
|
|
|
def _paginate_fed(ob_entities, page): |
155
|
|
|
paginator = Paginator(ob_entities, 20) |
156
|
|
|
|
157
|
|
|
try: |
158
|
|
|
ob_entities = paginator.page(page) |
159
|
|
|
except PageNotAnInteger: |
160
|
|
|
ob_entities = paginator.page(1) |
161
|
|
|
except EmptyPage: |
162
|
|
|
ob_entities = paginator.page(paginator.num_pages) |
163
|
|
|
|
164
|
|
|
adjacent_pages = 5 |
165
|
|
|
page_range = [n for n in \ |
166
|
|
|
range(ob_entities.number - adjacent_pages, ob_entities.number + adjacent_pages + 1) \ |
167
|
|
|
if n > 0 and n <= ob_entities.paginator.num_pages] |
168
|
|
|
|
169
|
|
|
return { |
170
|
|
|
'page_range': page_range, |
171
|
|
|
'cur_page_number': ob_entities.number, |
172
|
|
|
'num_pages': ob_entities.paginator.num_pages, |
173
|
|
|
'num_objects': ob_entities.paginator.count, |
174
|
|
|
'objects': ob_entities.object_list, |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
@profile(name='Federation view') |
178
|
|
|
def federation_view(request, federation_slug=None): |
179
|
|
|
if federation_slug: |
180
|
|
|
request.session['%s_process_done' % federation_slug] = False |
181
|
|
|
request.session['%s_num_entities' % federation_slug] = 0 |
182
|
|
|
request.session['%s_cur_entities' % federation_slug] = 0 |
183
|
|
|
request.session.save() |
184
|
|
|
|
185
|
|
|
federation = get_object_or_404(Federation, slug=federation_slug) |
186
|
|
|
if federation.registration_authority: |
187
|
|
|
categories = EntityCategory.objects.all().filter( |
188
|
|
|
Q(category_id__icontains=federation.registration_authority) | |
189
|
|
|
Q(category_id__icontains='http://refeds.org') | |
190
|
|
|
Q(category_id__icontains='http://www.geant.net')) |
191
|
|
|
else: |
192
|
|
|
categories = EntityCategory.objects.all().filter( |
193
|
|
|
Q(category_id__icontains='http://refeds.org') | |
194
|
|
|
Q(category_id__icontains='http://www.geant.net')) |
195
|
|
|
|
196
|
|
|
ob_entities = Entity.objects.filter(federations__id=federation.id) |
197
|
|
|
entity_type = None |
198
|
|
|
if request.GET and 'entity_type' in request.GET: |
199
|
|
|
entity_type = request.GET['entity_type'] |
200
|
|
|
ob_entities = ob_entities.filter(types__xmlname=entity_type) |
201
|
|
|
|
202
|
|
|
entity_category = None |
203
|
|
|
if request.GET and 'entity_category' in request.GET: |
204
|
|
|
entity_category = request.GET['entity_category'] |
205
|
|
|
|
206
|
|
|
ob_entities = ob_entities.prefetch_related('types', 'federations') |
207
|
|
|
pagination = _paginate_fed(ob_entities, request.GET.get('page')) |
208
|
|
|
|
209
|
|
|
entities = [] |
210
|
|
|
for entity in pagination['objects']: |
211
|
|
|
entity.curfed = federation |
212
|
|
|
if entity_category is None or entity_category in [c.category_id for c in entity.entity_categories.all()]: |
213
|
|
|
entities.append({ |
214
|
|
|
'entityid': entity.entityid, |
215
|
|
|
'name': entity.name, |
216
|
|
|
'absolute_url': entity.get_absolute_url(), |
217
|
|
|
'types': [unicode(item) for item in entity.types.all()], |
218
|
|
|
'federations': [(unicode(item.name), item.get_absolute_url()) for item in entity.federations.all()], |
219
|
|
|
}) |
220
|
|
|
|
221
|
|
|
if 'format' in request.GET: |
222
|
|
|
return export_query_set(request.GET.get('format'), entities, |
223
|
|
|
'entities_search_result', ('entityid', 'types', 'federations')) |
224
|
|
|
|
225
|
|
|
context = RequestContext(request) |
226
|
|
|
user = context.get('user', None) |
227
|
|
|
add_entity = user and user.has_perm('metadataparser.add_federation') |
228
|
|
|
pie_chart = fed_pie_chart(request, federation.id) |
229
|
|
|
|
230
|
|
|
return render_to_response('metadataparser/federation_view.html', |
231
|
|
|
{'settings': settings, |
232
|
|
|
'federation': federation, |
233
|
|
|
'entity_types': DESCRIPTOR_TYPES, |
234
|
|
|
'entity_type': entity_type or 'All', |
235
|
|
|
'fed_types': dict(FEDERATION_TYPES), |
236
|
|
|
'entities': entities, |
237
|
|
|
'categories': categories, |
238
|
|
|
'show_filters': True, |
239
|
|
|
'add_entity': add_entity, |
240
|
|
|
'lang': request.GET.get('lang', 'en'), |
241
|
|
|
'update_entities': request.GET.get('update', 'false'), |
242
|
|
|
'statcharts': [pie_chart], |
243
|
|
|
'pagination': pagination, |
244
|
|
|
}, context_instance=context) |
245
|
|
|
|
246
|
|
|
|
247
|
|
|
@user_can_edit(Federation) |
248
|
|
|
def federation_edit_post(request, federation, form): |
249
|
|
|
modify = True if federation else False |
250
|
|
|
form.save() |
251
|
|
|
|
252
|
|
|
if not modify: |
253
|
|
|
form.instance.editor_users.add(request.user) |
254
|
|
|
if 'file' in form.changed_data or 'file_url' in form.changed_data: |
255
|
|
|
form.instance.process_metadata() |
256
|
|
|
|
257
|
|
|
messages.success(request, _('Federation %s successfully' % 'modified' if modify else 'created')) |
258
|
|
|
return HttpResponseRedirect(form.instance.get_absolute_url() + '?update=true') |
259
|
|
|
|
260
|
|
|
|
261
|
|
|
@user_can_edit(Federation) |
262
|
|
|
def federation_edit(request, federation_slug=None): |
263
|
|
|
federation = get_object_or_404(Federation, slug=federation_slug) if federation_slug else None |
264
|
|
|
|
265
|
|
|
if request.method == 'POST': |
266
|
|
|
form = FederationForm(request.POST, request.FILES, instance=federation) |
267
|
|
|
if not form.is_valid(): |
268
|
|
|
messages.error(request, _('Please correct the errors indicated below')) |
269
|
|
|
else: |
270
|
|
|
return federation_edit_post(request, federation, form) |
271
|
|
|
else: |
272
|
|
|
form = FederationForm(instance=federation) |
273
|
|
|
|
274
|
|
|
context = RequestContext(request) |
275
|
|
|
user = context.get('user', None) |
276
|
|
|
delete_federation = user and user.has_perm('metadataparser.delete_federation') |
277
|
|
|
return render_to_response('metadataparser/federation_edit.html', |
278
|
|
|
{'settings': settings, 'form': form, 'delete_federation': delete_federation}, |
279
|
|
|
context_instance=RequestContext(request)) |
280
|
|
|
|
281
|
|
|
|
282
|
|
|
@user_can_edit(Federation) |
283
|
|
|
def federation_update_entities(request, federation_slug=None): |
284
|
|
|
federation = get_object_or_404(Federation, slug=federation_slug) |
285
|
|
|
federation.process_metadata_entities(request=request, federation_slug=federation_slug) |
286
|
|
|
|
287
|
|
|
messages.success(request, _('Federation entities updated succesfully')) |
288
|
|
|
return HttpResponse("Done. All entities updated.", content_type='text/plain') |
289
|
|
|
|
290
|
|
|
|
291
|
|
|
def entityupdate_progress(request, federation_slug=None): |
292
|
|
|
data = { 'done': False } |
293
|
|
|
if federation_slug: |
294
|
|
|
data = { 'done': request.session.get('%s_process_done' % federation_slug, False), |
295
|
|
|
'tot': request.session.get('%s_num_entities' % federation_slug, 0), |
296
|
|
|
'num': request.session.get('%s_cur_entities' % federation_slug, 0) } |
297
|
|
|
|
298
|
|
|
return HttpResponse(json.dumps(data), content_type='application/javascript') |
299
|
|
|
|
300
|
|
|
|
301
|
|
|
@user_can_edit(Federation, True) |
302
|
|
|
def federation_delete(request, federation_slug): |
303
|
|
|
federation = get_object_or_404(Federation, slug=federation_slug) |
304
|
|
|
|
305
|
|
|
for entity in federation.entity_set.all(): |
306
|
|
|
if len(entity.federations.all()) == 1: |
307
|
|
|
entity.delete() |
308
|
|
|
|
309
|
|
|
messages.success(request, |
310
|
|
|
_(u"%(federation)s federation was deleted successfully" |
311
|
|
|
% {'federation': unicode(federation)})) |
312
|
|
|
federation.delete() |
313
|
|
|
return HttpResponseRedirect(reverse('index')) |
314
|
|
|
|
315
|
|
|
|
316
|
|
|
@profile(name='Index charts') |
317
|
|
|
def federation_charts(request, federation_slug=None): |
318
|
|
|
if federation_slug is None: |
319
|
|
|
federation = None |
320
|
|
|
else: |
321
|
|
|
federation = get_object_or_404(Federation, slug=federation_slug) |
322
|
|
|
|
323
|
|
|
if request.method == 'POST': |
324
|
|
|
form = ChartForm(request.POST, request.FILES, instance=federation) |
325
|
|
|
|
326
|
|
|
if form.is_valid(): |
327
|
|
|
stats_config_dict = getattr(settings, "STATS") |
328
|
|
|
service_terms = stats_config_dict['statistics']['entity_by_type']['terms'] |
329
|
|
|
protocol_terms = stats_config_dict['statistics']['entity_by_protocol']['terms'] |
330
|
|
|
|
331
|
|
|
protocols = stats_config_dict['protocols'] |
332
|
|
|
|
333
|
|
|
from_time = datetime.fromordinal(form.cleaned_data['fromDate'].toordinal()) |
334
|
|
|
if timezone.is_naive(from_time): |
335
|
|
|
from_time = pytz.utc.localize(from_time) |
336
|
|
|
to_time = datetime.fromordinal(form.cleaned_data['toDate'].toordinal() + 1) |
337
|
|
|
if timezone.is_naive(to_time): |
338
|
|
|
to_time = pytz.utc.localize(to_time) |
339
|
|
|
|
340
|
|
|
service_stats = EntityStat.objects.filter( federation=federation \ |
341
|
|
|
, feature__in = service_terms \ |
342
|
|
|
, time__gte = from_time \ |
343
|
|
|
, time__lte = to_time).order_by("time") |
344
|
|
|
|
345
|
|
|
protocol_stats = EntityStat.objects.filter( federation=federation \ |
346
|
|
|
, feature__in = protocol_terms \ |
347
|
|
|
, time__gte = from_time \ |
348
|
|
|
, time__lte = to_time).order_by("time") |
349
|
|
|
|
350
|
|
|
s_chart = [] |
351
|
|
|
|
352
|
|
|
if len(service_stats) > 0: |
353
|
|
|
cur_data = service_stats[0].time.strftime('%d/%m/%y') |
354
|
|
|
cur_stat = { 'date': cur_data } |
355
|
|
|
for s in service_stats: |
356
|
|
|
if s.time.strftime('%d/%m/%y') != cur_data: |
357
|
|
|
s_chart.append(cur_stat) |
358
|
|
|
cur_data = s.time.strftime('%d/%m/%y') |
359
|
|
|
cur_stat = { 'date': cur_data } |
360
|
|
|
|
361
|
|
|
cur_stat[s.feature] = s.value |
362
|
|
|
s_chart.append(cur_stat) |
363
|
|
|
|
364
|
|
|
p_chart = [] |
365
|
|
|
if len(protocol_stats) > 0: |
366
|
|
|
cur_data = protocol_stats[0].time.strftime('%d/%m/%y') |
367
|
|
|
cur_stat = { 'date': cur_data } |
368
|
|
|
for p in protocol_stats: |
369
|
|
|
if p.time.strftime('%d/%m/%y') != cur_data: |
370
|
|
|
p_chart.append(cur_stat) |
371
|
|
|
cur_data = p.time.strftime('%d/%m/%y') |
372
|
|
|
cur_stat = { 'date': cur_data } |
373
|
|
|
|
374
|
|
|
cur_stat[p.feature] = p.value |
375
|
|
|
p_chart.append(cur_stat) |
376
|
|
|
|
377
|
|
|
p_chart_axis_max = 0 |
378
|
|
|
for p in p_chart: |
379
|
|
|
newval = p['sp_shib1'] + p['idp_shib1'] |
380
|
|
|
if newval > p_chart_axis_max: p_chart_axis_max = newval |
381
|
|
|
newval = p['sp_saml1'] + p['idp_saml1'] |
382
|
|
|
if newval > p_chart_axis_max: p_chart_axis_max = newval |
383
|
|
|
newval = p['sp_saml2'] + p['idp_saml2'] |
384
|
|
|
if newval > p_chart_axis_max: p_chart_axis_max = newval |
385
|
|
|
|
386
|
|
|
return render_to_response('metadataparser/federation_chart.html', |
387
|
|
|
{'form': form, |
388
|
|
|
'statcharts': True, |
389
|
|
|
's_chart': s_chart, |
390
|
|
|
'p_chart': p_chart, |
391
|
|
|
'p_chart_axis_max': p_chart_axis_max, |
392
|
|
|
}, |
393
|
|
|
context_instance=RequestContext(request)) |
394
|
|
|
|
395
|
|
|
else: |
396
|
|
|
messages.error(request, _('Please correct the errors indicated' |
397
|
|
|
' below')) |
398
|
|
|
else: |
399
|
|
|
form = ChartForm(instance=federation) |
400
|
|
|
|
401
|
|
|
return render_to_response('metadataparser/federation_chart.html', |
402
|
|
|
{'settings': settings, 'form': form}, |
403
|
|
|
context_instance=RequestContext(request)) |
404
|
|
|
|
405
|
|
|
|
406
|
|
|
def stats_chart(stats_config_dict, request, stats, entity, protocols=None): |
407
|
|
|
terms = stats_config_dict['statistics'][entity]['terms'] |
408
|
|
|
title = stats_config_dict['statistics'][entity]['title'] |
409
|
|
|
x_title = stats_config_dict['statistics'][entity]['x_title'] |
410
|
|
|
y_title = stats_config_dict['statistics'][entity]['y_title'] |
411
|
|
|
chart_type = 'column' |
412
|
|
|
stacking = True |
413
|
|
|
term_names = stats_config_dict['feature_names'] |
414
|
|
|
time_format = stats_config_dict['time_format'] |
415
|
|
|
statdata = _create_statdata('bar', stats, terms, term_names) |
416
|
|
|
|
417
|
|
|
series_options = [] |
418
|
|
|
for stack in range(len(protocols) if protocols else 1): |
419
|
|
|
for term in terms: |
420
|
|
|
if not protocols or term.endswith(protocols[stack]): |
421
|
|
|
series_options += \ |
422
|
|
|
[{'options':{ |
423
|
|
|
'type': chart_type, |
424
|
|
|
'stacking': stacking, |
425
|
|
|
'stack': stack, |
426
|
|
|
}, |
427
|
|
|
'terms':{ |
428
|
|
|
'time_%s' %term: [{term_names[term]: {'stack': stack, }}], |
429
|
|
|
}}] |
430
|
|
|
|
431
|
|
|
chart_options = _get_chart_options('bar', title, x_title, y_title) |
432
|
|
|
|
433
|
|
|
return Chart( |
434
|
|
|
datasource = statdata, |
435
|
|
|
series_options = series_options, |
436
|
|
|
chart_options = chart_options, |
437
|
|
|
x_sortf_mapf_mts=(None, lambda i: datetime.fromtimestamp(time.mktime(i.replace(tzinfo=tz.gettz('UTC')).astimezone(tz.tzlocal()).timetuple())).strftime(time_format), False) |
438
|
|
|
) |
439
|
|
|
|
440
|
|
|
|
441
|
|
|
|
442
|
|
|
def _create_statdata(chart_type, stats, terms=None, term_names=None): |
443
|
|
|
if chart_type == 'bar': |
444
|
|
|
statdata = DataPool( |
445
|
|
|
series=[{'options': { |
446
|
|
|
'source': stats.filter(feature=term)}, |
447
|
|
|
'legend_by': 'feature', |
448
|
|
|
'terms': [{'time_%s' %term :'time'}, |
449
|
|
|
{term_names[term] : 'value', 'name': 'feature'}] |
450
|
|
|
} for term in terms] |
451
|
|
|
) |
452
|
|
|
elif chart_type == 'pie': |
453
|
|
|
statdata = DataPool( |
454
|
|
|
series=[{'options': { 'source': stats }, |
455
|
|
|
'legend_by': 'feature', |
456
|
|
|
'terms': ['feature', 'value'], |
457
|
|
|
}] |
458
|
|
|
) |
459
|
|
|
else: |
460
|
|
|
statdata = None |
461
|
|
|
|
462
|
|
|
return statdata |
463
|
|
|
|
464
|
|
|
def _get_chart_options(chart_type, title=None, x_title=None, y_title=None): |
465
|
|
|
if chart_type == 'bar': |
466
|
|
|
chart_options = {'title': { 'text': title }, |
467
|
|
|
'xAxis': { |
468
|
|
|
'title': { 'text': x_title }, |
469
|
|
|
'labels': { |
470
|
|
|
'rotation': -45, |
471
|
|
|
'align': 'right' |
472
|
|
|
}, |
473
|
|
|
'max': 10, |
474
|
|
|
}, |
475
|
|
|
'yAxis': { |
476
|
|
|
'title': { 'text': y_title }, |
477
|
|
|
'minorTickInterval': 'auto' |
478
|
|
|
}, |
479
|
|
|
'credits': { 'enabled': False }, |
480
|
|
|
'scrollbar': { 'enabled': True }, |
481
|
|
|
'zoomType': 'xy', |
482
|
|
|
} |
483
|
|
|
elif chart_type == 'pie': |
484
|
|
|
chart_options = { |
485
|
|
|
'title': { 'text': ' ' }, |
486
|
|
|
'credits': { 'enabled': False } |
487
|
|
|
} |
488
|
|
|
else: |
489
|
|
|
chart_options = None |
490
|
|
|
|
491
|
|
|
return chart_options |
492
|
|
|
|
493
|
|
|
def fed_pie_chart(request, federation_id): |
494
|
|
|
stats_config_dict = getattr(settings, "STATS") |
495
|
|
|
terms = stats_config_dict['statistics']['entity_by_type']['terms'] |
496
|
|
|
stats = EntityStat.objects.filter(federation=federation_id, \ |
497
|
|
|
feature__in=terms).order_by('-time')[0:len(terms)] |
498
|
|
|
statdata = _create_statdata('pie', stats) |
499
|
|
|
series_options = \ |
500
|
|
|
[{'options': { 'type': 'pie', 'stacking': False, 'size': '70%' }, |
501
|
|
|
'terms':{ 'feature': [ 'value' ] }}] |
502
|
|
|
chart_options = _get_chart_options('pie') |
503
|
|
|
|
504
|
|
|
return Chart( |
505
|
|
|
datasource = statdata, |
506
|
|
|
series_options = series_options, |
507
|
|
|
chart_options = chart_options, |
508
|
|
|
) |
509
|
|
|
|
510
|
|
|
|
511
|
|
|
|
512
|
|
|
@profile(name='Entity view') |
513
|
|
|
def entity_view(request, entityid): |
514
|
|
|
entityid = unquote(entityid) |
515
|
|
|
entityid = RESCUE_SLASH.sub("\\1/\\2", entityid) |
516
|
|
|
|
517
|
|
|
entity = get_object_or_404(Entity, entityid=entityid) |
518
|
|
|
|
519
|
|
|
if 'federation' in request.GET: |
520
|
|
|
federation = get_object_or_404(Federation, slug=request.GET.get('federation')) |
521
|
|
|
entity.curfed = federation |
522
|
|
|
else: |
523
|
|
|
federation = entity.federations.all()[0] |
524
|
|
|
entity.curfed = federation |
525
|
|
|
|
526
|
|
|
if 'format' in request.GET: |
527
|
|
|
return export_entity(request.GET.get('format'), entity) |
528
|
|
|
|
529
|
|
|
if 'viewxml' in request.GET: |
530
|
|
|
serialized = entity.xml |
531
|
|
|
response = HttpResponse(serialized, content_type='application/xml') |
532
|
|
|
return response |
533
|
|
|
|
534
|
|
|
return render_to_response('metadataparser/entity_view.html', |
535
|
|
|
{'settings': settings, |
536
|
|
|
'entity': entity, |
537
|
|
|
'lang': request.GET.get('lang', 'en') |
538
|
|
|
}, context_instance=RequestContext(request)) |
539
|
|
|
|
540
|
|
|
|
541
|
|
|
@user_can_edit(Entity) |
542
|
|
|
def entity_edit_post(request, form, federation, entity): |
543
|
|
|
form.save() |
544
|
|
|
if federation and not federation in form.instance.federations.all(): |
545
|
|
|
form.instance.federations.add(federation) |
546
|
|
|
form.instance.save() |
547
|
|
|
|
548
|
|
|
if entity: |
549
|
|
|
messages.success(request, _('Entity modified successfully')) |
550
|
|
|
else: |
551
|
|
|
messages.success(request, _('Entity created successfully')) |
552
|
|
|
|
553
|
|
|
return HttpResponseRedirect(form.instance.get_absolute_url()) |
554
|
|
|
|
555
|
|
|
|
556
|
|
|
|
557
|
|
|
@user_can_edit(Entity) |
558
|
|
|
def entity_edit(request, federation_slug=None, entity_id=None): |
559
|
|
|
entity = None |
560
|
|
|
federation = None |
561
|
|
|
if federation_slug: |
562
|
|
|
federation = get_object_or_404(Federation, slug=federation_slug) |
563
|
|
|
if entity_id: |
564
|
|
|
entity = get_object_or_404(Entity, id=entity_id, |
565
|
|
|
federations__id=federation.id) |
566
|
|
|
if entity_id and not federation_slug: |
567
|
|
|
entity = get_object_or_404(Entity, id=entity_id) |
568
|
|
|
|
569
|
|
|
if request.method == 'POST': |
570
|
|
|
form = EntityForm(request.POST, request.FILES, instance=entity) |
571
|
|
|
if form.is_valid(): |
572
|
|
|
return entity_edit_post(request, form, federation, entity) |
573
|
|
|
else: |
574
|
|
|
messages.error(request, _('Please correct the errors indicated below')) |
575
|
|
|
else: |
576
|
|
|
form = EntityForm(instance=entity) |
577
|
|
|
|
578
|
|
|
return render_to_response('metadataparser/entity_edit.html', |
579
|
|
|
{'settings': settings, |
580
|
|
|
'form': form, |
581
|
|
|
'federation': federation}, |
582
|
|
|
context_instance=RequestContext(request)) |
583
|
|
|
|
584
|
|
|
|
585
|
|
|
@user_can_edit(Entity, True) |
586
|
|
|
def entity_delete(request, entity_id): |
587
|
|
|
entity = get_object_or_404(Entity, id=entity_id) |
588
|
|
|
messages.success(request, |
589
|
|
|
_(u"%(entity)s entity was deleted successfully" |
590
|
|
|
% {'entity': unicode(entity)})) |
591
|
|
|
entity.delete() |
592
|
|
|
return HttpResponseRedirect(reverse('index')) |
593
|
|
|
|
594
|
|
|
|
595
|
|
|
def entity_comment(request, federation_slug=None, entity_id=None): |
596
|
|
|
entity = None |
597
|
|
|
federation = None |
598
|
|
|
if federation_slug: |
599
|
|
|
federation = get_object_or_404(Federation, slug=federation_slug) |
600
|
|
|
if entity_id: |
601
|
|
|
entity = get_object_or_404(Entity, id=entity_id, |
602
|
|
|
federations__id=federation.id) |
603
|
|
|
if entity_id and not federation_slug: |
604
|
|
|
entity = get_object_or_404(Entity, id=entity_id) |
605
|
|
|
|
606
|
|
|
if request.method == 'POST': |
607
|
|
|
form = EntityCommentForm(request.POST, request.FILES, instance=entity) |
608
|
|
|
if form.is_valid(): |
609
|
|
|
mail_config = getattr(settings, "MAIL_CONFIG") |
610
|
|
|
try: |
611
|
|
|
subject = mail_config['comment_subject'] %entity |
612
|
|
|
send_mail(form.data['email'], subject, form.data['comment']) |
613
|
|
|
messages.success(request, _('Comment posted successfully')) |
614
|
|
|
except Exception, errorMessage: |
615
|
|
|
messages.error(request, _('Comment could not be posted successfully: %s' %errorMessage)) |
616
|
|
|
|
617
|
|
|
return HttpResponseRedirect(form.instance.get_absolute_url()) |
618
|
|
|
|
619
|
|
|
else: |
620
|
|
|
messages.error(request, _('Please correct the errors indicated' |
621
|
|
|
' below')) |
622
|
|
|
else: |
623
|
|
|
form = EntityCommentForm(instance=entity) |
624
|
|
|
|
625
|
|
|
return render_to_response('metadataparser/entity_comment.html', |
626
|
|
|
{'settings': settings, |
627
|
|
|
'form': form, |
628
|
|
|
}, |
629
|
|
|
context_instance=RequestContext(request)) |
630
|
|
|
|
631
|
|
|
|
632
|
|
|
def entity_proposal(request, federation_slug=None, entity_id=None): |
633
|
|
|
entity = None |
634
|
|
|
federation = None |
635
|
|
|
if federation_slug: |
636
|
|
|
federation = get_object_or_404(Federation, slug=federation_slug) |
637
|
|
|
if entity_id: |
638
|
|
|
entity = get_object_or_404(Entity, id=entity_id, |
639
|
|
|
federations__id=federation.id) |
640
|
|
|
if entity_id and not federation_slug: |
641
|
|
|
entity = get_object_or_404(Entity, id=entity_id) |
642
|
|
|
|
643
|
|
|
if request.method == 'POST': |
644
|
|
|
form = EntityProposalForm(request.POST, request.FILES, instance=entity) |
645
|
|
|
|
646
|
|
|
if form.is_valid(): |
647
|
|
|
mail_config = getattr(settings, "MAIL_CONFIG") |
648
|
|
|
try: |
649
|
|
|
subject = mail_config['proposal_subject'] %entity |
650
|
|
|
my_dict = dict(form.data.iterlists()) |
651
|
|
|
body = mail_config['proposal_body'] % (entity, ', '.join(my_dict['federations']), form.data['comment']) |
652
|
|
|
send_mail(form.data['email'], subject, body) |
653
|
|
|
messages.success(request, _('Proposal posted successfully')) |
654
|
|
|
except Exception, errorMessage: |
655
|
|
|
messages.error(request, _('Proposal could not be posted successfully: %s' %errorMessage)) |
656
|
|
|
|
657
|
|
|
return HttpResponseRedirect(form.instance.get_absolute_url()) |
658
|
|
|
|
659
|
|
|
else: |
660
|
|
|
messages.error(request, _('Please correct the errors indicated' |
661
|
|
|
' below')) |
662
|
|
|
else: |
663
|
|
|
form = EntityProposalForm(instance=entity) |
664
|
|
|
|
665
|
|
|
return render_to_response('metadataparser/entity_proposal.html', |
666
|
|
|
{'settings': settings, |
667
|
|
|
'form': form, |
668
|
|
|
}, |
669
|
|
|
context_instance=RequestContext(request)) |
670
|
|
|
|
671
|
|
|
def search_service(request): |
672
|
|
|
filters = {} |
673
|
|
|
objects = [] |
674
|
|
|
|
675
|
|
|
if 'entityid' in request.GET: |
676
|
|
|
form = ServiceSearchForm(request.GET) |
677
|
|
|
if form.is_valid(): |
678
|
|
|
entityid = form.cleaned_data['entityid'] |
679
|
|
|
entityid = entityid.strip() |
680
|
|
|
filters['entityid__icontains'] = entityid |
681
|
|
|
else: |
682
|
|
|
form = ServiceSearchForm() |
683
|
|
|
entity_type = request.GET.get('entity_type', None) |
684
|
|
|
|
685
|
|
|
if entity_type: |
686
|
|
|
filters['entity_type'] = entity_type |
687
|
|
|
|
688
|
|
|
if filters: |
689
|
|
|
objects = Entity.objects.filter(**filters) |
690
|
|
|
|
691
|
|
|
if objects and 'format' in request.GET.keys(): |
692
|
|
|
entities = [] |
693
|
|
|
for entity in objects: |
694
|
|
|
entities.append({ |
695
|
|
|
'entityid': entity.entityid, |
696
|
|
|
'name': entity.name, |
697
|
|
|
'absolute_url': entity.get_absolute_url(), |
698
|
|
|
'types': [unicode(item) for item in entity.types.all()], |
699
|
|
|
'federations': [(unicode(item.name), item.get_absolute_url()) for item in entity.federations.all()], |
700
|
|
|
}) |
701
|
|
|
|
702
|
|
|
return export_query_set(request.GET.get('format'), entities, |
703
|
|
|
'entities_search_result', ('entityid', 'types', 'federations')) |
704
|
|
|
|
705
|
|
|
entities = [] |
706
|
|
|
for entity in objects: |
707
|
|
|
entities.append({ |
708
|
|
|
'entityid': entity.entityid, |
709
|
|
|
'name': entity.name, |
710
|
|
|
'absolute_url': entity.get_absolute_url(), |
711
|
|
|
'types': [unicode(item) for item in entity.types.all()], |
712
|
|
|
'federations': [(unicode(item.name), item.get_absolute_url()) for item in entity.federations.all()], |
713
|
|
|
}) |
714
|
|
|
|
715
|
|
|
return render_to_response('metadataparser/service_search.html', |
716
|
|
|
{'settings': settings, |
717
|
|
|
'searchform': form, |
718
|
|
|
'object_list': entities, |
719
|
|
|
'show_filters': False, |
720
|
|
|
}, context_instance=RequestContext(request)) |
721
|
|
|
|
722
|
|
|
def met_logout(request): |
723
|
|
|
logout(request) |
724
|
|
|
return HttpResponseRedirect(request.GET.get("next", "/")) |
725
|
|
|
|
726
|
|
|
|
727
|
|
|
@profile(name='Search entities') |
728
|
|
|
def search_entities(request): |
729
|
|
|
if request.method == 'POST': |
730
|
|
|
form = SearchEntitiesForm(request.POST) |
731
|
|
|
|
732
|
|
|
if form.is_valid(): |
733
|
|
|
filters = {} |
734
|
|
|
args = () |
735
|
|
|
|
736
|
|
|
entity_type = form.cleaned_data['entity_type'] |
737
|
|
|
if entity_type and entity_type != 'All': |
738
|
|
|
filters['types__name'] = entity_type |
739
|
|
|
|
740
|
|
|
federations = form.cleaned_data['federations'] |
741
|
|
|
if federations and not 'All' in federations: |
742
|
|
|
q_list = [Q(federations__id=f) for f in federations] |
743
|
|
|
args = (reduce(operator.or_, q_list),) |
744
|
|
|
|
745
|
|
|
entity_id = form.cleaned_data['entityid'] |
746
|
|
|
if entity_id and entity_id != '': |
747
|
|
|
filters['entityid__icontains'] = entity_id |
748
|
|
|
|
749
|
|
|
ob_entities = Entity.objects.all() |
750
|
|
|
if args: |
751
|
|
|
ob_entities = ob_entities.filter(*args) |
752
|
|
|
if filters: |
753
|
|
|
ob_entities = ob_entities.filter(**filters) |
754
|
|
|
|
755
|
|
|
entity_category = form.cleaned_data['entity_category'] |
756
|
|
|
if entity_category and entity_category != 'All': |
757
|
|
|
eid_list = [] |
758
|
|
|
|
759
|
|
|
for entity in ob_entities.all(): |
760
|
|
|
feds = Entity_Federations.objects.filter(entity=entity) |
761
|
|
|
|
762
|
|
|
if federations and not 'All' in federations: |
763
|
|
|
ec_list = [Q(federation__id=f) for f in federations] |
764
|
|
|
ec_args = (reduce(operator.or_, ec_list),) |
765
|
|
|
feds = feds.filter(*ec_args) |
766
|
|
|
|
767
|
|
|
feds.prefetch_related('entity_categories') |
768
|
|
|
feds = feds.filter(entity_categories__category_id=entity_category) |
769
|
|
|
eid_list.extend([ Q(entityid=f.entity.entityid) for f in feds]) |
770
|
|
|
|
771
|
|
|
eid_args = (reduce(operator.or_, eid_list),) |
772
|
|
|
ob_entities = ob_entities.filter(*eid_args) |
773
|
|
|
|
774
|
|
|
ob_entities = ob_entities.prefetch_related('types', 'federations') |
775
|
|
|
pagination = _paginate_fed(ob_entities, form.cleaned_data['page']) |
776
|
|
|
|
777
|
|
|
entities = [] |
778
|
|
|
for entity in pagination['objects']: |
779
|
|
|
entities.append({ |
780
|
|
|
'entityid': entity.entityid, |
781
|
|
|
'name': entity.name, |
782
|
|
|
'absolute_url': entity.get_absolute_url(), |
783
|
|
|
'types': [unicode(item) for item in entity.types.all()], |
784
|
|
|
'federations': [(unicode(item.name), item.get_absolute_url()) for item in entity.federations.all()], |
785
|
|
|
}) |
786
|
|
|
|
787
|
|
|
export_format = form.cleaned_data['export_format'] |
788
|
|
|
if export_format: |
789
|
|
|
return export_query_set(export_format, entities, |
790
|
|
|
'entities_search_result', ('entityid', 'types', 'federations')) |
791
|
|
|
|
792
|
|
|
return render_to_response('metadataparser/search_entities.html', |
793
|
|
|
{'settings': settings, |
794
|
|
|
'form': form, |
795
|
|
|
'object_list': entities, |
796
|
|
|
'show_filters': False, |
797
|
|
|
'pagination': pagination, |
798
|
|
|
}, context_instance=RequestContext(request)) |
799
|
|
|
|
800
|
|
|
else: |
801
|
|
|
messages.error(request, _('Please correct the errors indicated' |
802
|
|
|
' below')) |
803
|
|
|
else: |
804
|
|
|
form = SearchEntitiesForm() |
805
|
|
|
|
806
|
|
|
return render_to_response('metadataparser/search_entities.html', |
807
|
|
|
{'form': form}, |
808
|
|
|
context_instance=RequestContext(request)) |
809
|
|
|
|
810
|
|
|
|
811
|
|
|
|