1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 ''' A view functions is simply a Python function that takes a Web request and
27 returns a Web response. This response can be the HTML contents of a Web page,
28 or a redirect, or the 404 and 500 error, or an XML document, or an image...
29 or anything.'''
30
31 import os
32 import sys
33 import locale
34 import calendar
35 import datetime
36 import traceback
37 import logging
38 import re
39
40 import omeroweb.webclient.views
41
42 from time import time
43
44 from omero_version import omero_version
45
46 from django.conf import settings
47 from django.contrib.sessions.backends.cache import SessionStore
48 from django.core import template_loader
49 from django.core.cache import cache
50 from django.core.urlresolvers import reverse
51 from django.http import HttpResponse, HttpRequest, HttpResponseRedirect, Http404
52 from django.shortcuts import render_to_response
53 from django.template import RequestContext as Context
54 from django.utils import simplejson
55 from django.utils.translation import ugettext as _
56 from django.views.defaults import page_not_found, server_error
57 from django.views import debug
58 from django.core.cache import cache
59 from django.utils.encoding import smart_str
60
61 from webclient.webclient_gateway import OmeroWebGateway
62
63 from forms import LoginForm, ForgottonPasswordForm, ExperimenterForm, \
64 GroupForm, GroupOwnerForm, MyAccountForm, ChangePassword, \
65 ContainedExperimentersForm, UploadPhotoForm, \
66 EnumerationEntry, EnumerationEntries
67
68 from omeroweb.webadmin.webadmin_utils import toBoolean, upgradeCheck
69
70 from omeroweb.connector import Server
71
72 from omeroweb.webclient.decorators import login_required
73 from omeroweb.connector import Connector
74
75 logger = logging.getLogger(__name__)
81 """ Subclass for adding additional data to the 'context' dict passed to templates """
82
83 - def prepare_context(self, request, context, *args, **kwargs):
84 """
85 We extend the webclient render_response to check if any groups are created.
86 If not, add an appropriate message to the template context
87 """
88 super(render_response_admin, self).prepare_context(request, context, *args, **kwargs)
89
90 noGroupsCreated = kwargs["conn"].isAnythingCreated()
91 if noGroupsCreated:
92 msg = _('User must be in a group - You have not created any groups yet. Click <a href="%s">here</a> to create a group') % (reverse(viewname="wamanagegroupid", args=["new"]))
93 context['ome']['message'] = msg
94
95
96
97
98 from omero.rtypes import *
99 from omero.model import PermissionsI
103
104 def isLdapUser(eid):
105 try:
106 if len(auth.val) > 0:
107 for a in auth.val:
108 for k,v in a.val.iteritems():
109 if long(eid) == long(v.val):
110 return True
111 except:
112 return False
113 return False
114
115 experimentersList = list(conn.getObjects("Experimenter"))
116
117 auth = conn.listLdapAuthExperimenters()
118 experimenters = list()
119 for exp in experimentersList:
120 exp.ldapUser = isLdapUser(exp.id)
121 experimenters.append(exp)
122 return experimenters
123
133
135 formGroups = list()
136 for gr in groups:
137 flag = False
138 if gr.name in excluded_names:
139 flag = True
140 if gr.id in excluded_ids:
141 flag = True
142 if not flag:
143 formGroups.append(gr)
144 return formGroups
145
147 groupsList = list(conn.listOwnedGroups())
148 ownedGroups = list()
149 for gr in groupsList:
150 flag = False
151 if gr.name in excluded_names:
152 flag = True
153 if gr.id in excluded_ids:
154 flag = True
155 if not flag:
156 ownedGroups.append(gr)
157 return ownedGroups
158
161 if newFile.content_type.startswith("image"):
162 f = newFile.content_type.split("/")
163 format = f[1].upper()
164 else:
165 format = newFile.content_type
166
167 conn.uploadMyUserPhoto(smart_str(newFile.name), format, newFile.read())
168
181
183 p = None
184 if group.details.getPermissions() is None:
185 raise AttributeError('Object has no permissions')
186 else:
187 p = group.details.getPermissions()
188
189 flag = None
190 if p.isGroupAnnotate():
191 flag = 2
192 elif p.isGroupRead():
193 flag = 1
194 elif p.isUserRead():
195 flag = 0
196
197 return flag
198
201 if ids is not None and len(ids)>0:
202 return list(conn.getObjects("ExperimenterGroup", ids))
203 return list()
204
206 if ids is not None and len(ids)>0:
207 return list(conn.getObjects("Experimenter", ids))
208 return list()
209
211 if not list1 and not list2: return list()
212 if not list1: return list(list2)
213 if not list2: return list(list1)
214 result = list()
215 result.extend(list1)
216 result.extend(list2)
217 return set(result)
218
221 if pixel_type == "int8" or pixel_type == "uint8":
222 return 1
223 elif pixel_type == "int16" or pixel_type == "uint16":
224 return 2
225 elif pixel_type == "int32" or pixel_type == "uint32" or pixel_type == "float":
226 return 4
227 elif pixel_type == "double":
228 return 8;
229 else:
230 raise AttributeError("Unknown pixel type: %s" % (pixel_type))
231
233 tt = dict()
234 for p in pixels_list:
235 oid = p.details.owner.id.val
236 p_size = p.sizeX.val * p.sizeY.val * p.sizeZ.val * p.sizeC.val * p.sizeT.val
237 p_size = p_size*_bytes_per_pixel(p.pixelsType.value.val)
238 if tt.has_key(oid):
239 tt[oid]['data']+=p_size
240 else:
241 tt[oid] = dict()
242 tt[oid]['label']=exps[oid]
243 tt[oid]['data']=p_size
244
245 for pof in pixels_originalFiles_list:
246 oid = pof.details.owner.id.val
247 p_size = pof.parent.size.val
248 if tt.has_key(oid):
249 tt[oid]['data']+=p_size
250
251 return tt
252
254 loading = False
255 usage_map = dict()
256 exps = dict()
257 for e in list(conn.getObjects("Experimenter")):
258 exps[e.id] = e.getNameWithInitial()
259
260 PAGE_SIZE = 1000
261 offset = long(offset)
262
263 ctx = conn.createServiceOptsDict()
264 if conn.isAdmin():
265 ctx.setOmeroGroup(-1)
266 else:
267 ctx.setOmeroGroup(conn.getEventContext().groupId)
268
269 p = omero.sys.ParametersI()
270 p.page(offset, PAGE_SIZE)
271 pixels_list = conn.getQueryService().findAllByQuery(
272 "select p from Pixels as p join fetch p.pixelsType " \
273 "order by p.id", p, ctx)
274
275
276 if len(pixels_list) > 0:
277 pids = omero.rtypes.rlist([p.id for p in pixels_list])
278 p2 = omero.sys.ParametersI()
279 p2.add("pids", pids)
280 pixels_originalFiles_list = conn.getQueryService().findAllByQuery(
281 "select m from PixelsOriginalFileMap as m join fetch m.parent " \
282 "where m.child.id in (:pids)", p2, ctx)
283
284 count = len(pixels_list)
285 usage_map = _usage_map_helper(pixels_list, pixels_originalFiles_list, exps)
286
287 count = len(pixels_list)
288 offset += count
289
290 if count == PAGE_SIZE:
291 loading = True
292
293 return {'loading':loading, 'offset':offset, 'usage':usage_map}
294
309
310 if request.method == 'POST':
311 form = ForgottonPasswordForm(data=request.REQUEST.copy())
312 if form.is_valid():
313 server_id = request.REQUEST.get('server')
314 try:
315 conn = getGuestConnection(server_id)
316 if not conn.isForgottenPasswordSet():
317 error = "This server cannot reset password. Please contact your administrator."
318 conn = None
319 except Exception, x:
320 logger.error(traceback.format_exc())
321 error = "Internal server error, please contact administrator."
322
323 if conn is not None:
324 try:
325 conn.reportForgottenPassword(smart_str(request.REQUEST.get('username')), smart_str(request.REQUEST.get('email')))
326 error = "Password was reseted. Check you mailbox."
327 form = None
328 except omero.SecurityViolation, sv:
329 logger.error(traceback.format_exc())
330 error = sv.message
331 except Exception:
332 logger.error(traceback.format_exc())
333 error = "Internal server error, please contact administrator."
334 else:
335 form = ForgottonPasswordForm()
336
337 context = {'error':error, 'form':form, 'omero_version':omero_version}
338 t = template_loader.get_template(template)
339 c = Context(request, context)
340 rsp = t.render(c)
341 return HttpResponse(rsp)
342
343 @login_required()
344 -def index(request, **kwargs):
345 conn = None
346 try:
347 conn = kwargs["conn"]
348 except:
349 logger.error(traceback.format_exc())
350
351 if conn.isAdmin():
352 return HttpResponseRedirect(reverse("waexperimenters"))
353 else:
354 return HttpResponseRedirect(reverse("wamyaccount"))
355
356 @login_required()
357 -def logout(request, **kwargs):
360
361 @login_required(isAdmin=True)
362 @render_response_admin()
363 -def experimenters(request, conn=None, **kwargs):
364 template = "webadmin/experimenters.html"
365
366 experimenterList = prepare_experimenterList(conn)
367
368 context = {'experimenterList':experimenterList}
369 context['template'] = template
370 return context
371
372 @login_required(isAdmin=True)
373 @render_response_admin()
374 -def manage_experimenter(request, action, eid=None, conn=None, **kwargs):
375 template = "webadmin/experimenter_form.html"
376
377 groups = list(conn.getObjects("ExperimenterGroup"))
378 groups.sort(key=lambda x: x.getName().lower())
379
380 if action == 'new':
381 form = ExperimenterForm(initial={'with_password':True, 'active':True, 'groups':otherGroupsInitialList(groups)})
382 context = {'form':form}
383 elif action == 'create':
384 if request.method != 'POST':
385 return HttpResponseRedirect(reverse(viewname="wamanageexperimenterid", args=["new"]))
386 else:
387 name_check = conn.checkOmeName(request.REQUEST.get('omename'))
388 email_check = conn.checkEmail(request.REQUEST.get('email'))
389
390 initial={'with_password':True, 'groups':otherGroupsInitialList(groups)}
391 form = ExperimenterForm(initial=initial, data=request.REQUEST.copy(), name_check=name_check, email_check=email_check)
392 if form.is_valid():
393 logger.debug("Create experimenter form:" + str(form.cleaned_data))
394 omename = form.cleaned_data['omename']
395 firstName = form.cleaned_data['first_name']
396 middleName = form.cleaned_data['middle_name']
397 lastName = form.cleaned_data['last_name']
398 email = form.cleaned_data['email']
399 institution = form.cleaned_data['institution']
400 admin = toBoolean(form.cleaned_data['administrator'])
401 active = toBoolean(form.cleaned_data['active'])
402 defaultGroup = form.cleaned_data['default_group']
403 otherGroups = form.cleaned_data['other_groups']
404 password = form.cleaned_data['password']
405
406
407
408 if defaultGroup is None:
409 defaultGroup = otherGroups[0]
410 for g in groups:
411 if long(defaultGroup) == g.id:
412 dGroup = g
413 break
414
415 listOfOtherGroups = set()
416
417 for g in groups:
418 for og in otherGroups:
419
420 if long(og) == long(dGroup.id):
421 pass
422 elif long(og) == g.id:
423 listOfOtherGroups.add(g)
424
425 conn.createExperimenter(omename, firstName, lastName, email, admin, active, dGroup, listOfOtherGroups, password, middleName, institution)
426 return HttpResponseRedirect(reverse("waexperimenters"))
427 context = {'form':form}
428 elif action == 'edit' :
429 experimenter, defaultGroup, otherGroups, isLdapUser, hasAvatar = prepare_experimenter(conn, eid)
430 try:
431 defaultGroupId = defaultGroup.id
432 except:
433 defaultGroupId = None
434
435 initial={'omename': experimenter.omeName, 'first_name':experimenter.firstName,
436 'middle_name':experimenter.middleName, 'last_name':experimenter.lastName,
437 'email':experimenter.email, 'institution':experimenter.institution,
438 'administrator': experimenter.isAdmin(), 'active': experimenter.isActive(),
439 'default_group': defaultGroupId, 'other_groups':[g.id for g in otherGroups],
440 'groups':otherGroupsInitialList(groups)}
441 experimenter_is_me = (conn.getEventContext().userId == long(eid))
442 form = ExperimenterForm(experimenter_is_me=experimenter_is_me, initial=initial)
443 password_form = ChangePassword()
444 context = {'form':form, 'eid': eid, 'ldapAuth': isLdapUser, 'password_form':password_form}
445 elif action == 'save':
446 experimenter, defaultGroup, otherGroups, isLdapUser, hasAvatar = prepare_experimenter(conn, eid)
447 if request.method != 'POST':
448 return HttpResponseRedirect(reverse(viewname="wamanageexperimenterid", args=["edit", experimenter.id]))
449 else:
450 name_check = conn.checkOmeName(request.REQUEST.get('omename'), experimenter.omeName)
451 email_check = conn.checkEmail(request.REQUEST.get('email'), experimenter.email)
452 initial={'active':True, 'groups':otherGroupsInitialList(groups)}
453
454 form = ExperimenterForm(initial=initial, data=request.POST.copy(), name_check=name_check, email_check=email_check)
455
456 if form.is_valid():
457 logger.debug("Update experimenter form:" + str(form.cleaned_data))
458 omename = form.cleaned_data['omename']
459 firstName = form.cleaned_data['first_name']
460 middleName = form.cleaned_data['middle_name']
461 lastName = form.cleaned_data['last_name']
462 email = form.cleaned_data['email']
463 institution = form.cleaned_data['institution']
464 admin = toBoolean(form.cleaned_data['administrator'])
465 active = toBoolean(form.cleaned_data['active'])
466 if experimenter.getId() == conn.getUserId():
467 active = True
468 defaultGroup = form.cleaned_data['default_group']
469 otherGroups = form.cleaned_data['other_groups']
470
471
472
473 if defaultGroup is None:
474 defaultGroup = otherGroups[0]
475 for g in groups:
476 if long(defaultGroup) == g.id:
477 dGroup = g
478 break
479
480 listOfOtherGroups = set()
481
482 for g in groups:
483 for og in otherGroups:
484
485 if long(og) == long(dGroup.id):
486 pass
487 elif long(og) == g.id:
488 listOfOtherGroups.add(g)
489
490 conn.updateExperimenter(experimenter, omename, firstName, lastName, email, admin, active, dGroup, listOfOtherGroups, middleName, institution)
491 return HttpResponseRedirect(reverse("waexperimenters"))
492 context = {'form':form, 'eid': eid, 'ldapAuth': isLdapUser}
493
494
495
496 else:
497 return HttpResponseRedirect(reverse("waexperimenters"))
498
499 context['template'] = template
500 return context
501
502
503 @login_required()
504 @render_response_admin()
505 -def manage_password(request, eid, conn=None, **kwargs):
534
535
536 @login_required(isAdmin=True)
537 @render_response_admin()
538 -def groups(request, conn=None, **kwargs):
539 template = "webadmin/groups.html"
540
541 groups = conn.getObjects("ExperimenterGroup")
542
543 context = {'groups':groups}
544 context['template'] = template
545 return context
546
547
548 @login_required(isAdmin=True)
549 @render_response_admin()
550 -def manage_group(request, action, gid=None, conn=None, **kwargs):
569
570 if action == 'new':
571 form = GroupForm(initial={'experimenters':experimenters, 'permissions': 0})
572 context = {'form':form}
573 elif action == 'create':
574 if request.method != 'POST':
575 return HttpResponseRedirect(reverse(viewname="wamanagegroupid", args=["new"]))
576 else:
577 name_check = conn.checkGroupName(request.REQUEST.get('name'))
578 form = GroupForm(initial={'experimenters':experimenters}, data=request.POST.copy(), name_check=name_check)
579 if form.is_valid():
580 logger.debug("Create group form:" + str(form.cleaned_data))
581 name = form.cleaned_data['name']
582 description = form.cleaned_data['description']
583 owners = form.cleaned_data['owners']
584 members = form.cleaned_data['members']
585 permissions = form.cleaned_data['permissions']
586
587 perm = setActualPermissions(permissions)
588 listOfOwners = getSelectedExperimenters(conn, owners)
589 gid = conn.createGroup(name, perm, listOfOwners, description)
590 new_members = getSelectedExperimenters(conn, mergeLists(members,owners))
591 group = conn.getObject("ExperimenterGroup", gid)
592 conn.setMembersOfGroup(group, new_members)
593
594 return HttpResponseRedirect(reverse("wagroups"))
595 context = {'form':form}
596 elif action == 'edit':
597 context = getEditFormContext()
598 elif action == 'save':
599 group = conn.getObject("ExperimenterGroup", gid)
600
601 if request.method != 'POST':
602 return HttpResponseRedirect(reverse(viewname="wamanagegroupid", args=["edit", group.id]))
603 else:
604 permissions = getActualPermissions(group)
605
606 name_check = conn.checkGroupName(request.REQUEST.get('name'), group.name)
607 form = GroupForm(initial={'experimenters':experimenters}, data=request.POST.copy(), name_check=name_check)
608 context = {'form':form, 'gid': gid, 'permissions': permissions}
609 if form.is_valid():
610 logger.debug("Update group form:" + str(form.cleaned_data))
611 name = form.cleaned_data['name']
612 description = form.cleaned_data['description']
613 owners = form.cleaned_data['owners']
614 permissions = form.cleaned_data['permissions']
615 members = form.cleaned_data['members']
616
617 listOfOwners = getSelectedExperimenters(conn, owners)
618 if permissions != int(permissions):
619 perm = setActualPermissions(permissions)
620 else:
621 perm = None
622 conn.updateGroup(group, name, perm, listOfOwners, description)
623
624 new_members = getSelectedExperimenters(conn, mergeLists(members,owners))
625 removalFails = conn.setMembersOfGroup(group, new_members)
626 if len(removalFails) == 0:
627 return HttpResponseRedirect(reverse("wagroups"))
628
629 msgs = []
630
631 for e in removalFails:
632 url = reverse("wamanageexperimenterid", args=["edit", e.id])
633 msgs.append("Can't remove user <a href='%s'>%s</a> from their only group"
634 % (url, e.getFullName()))
635
636 context = getEditFormContext()
637 context['ome'] = {}
638 context['ome']['message'] = "<br>".join(msgs)
639 else:
640 return HttpResponseRedirect(reverse("wagroups"))
641
642 context['template'] = template
643 return context
644
645
646 @login_required(isGroupOwner=True)
647 @render_response_admin()
648 -def manage_group_owner(request, action, gid, conn=None, **kwargs):
649 template = "webadmin/group_form_owner.html"
650
651 userId = conn.getEventContext().userId
652 group = conn.getObject("ExperimenterGroup", gid)
653 memberIds = [m.id for m in group.getMembers()]
654 ownerIds = [e.id for e in group.getOwners()]
655 experimenters = list(conn.getObjects("Experimenter"))
656
657 experimenterDefaultIds = list()
658 for e in experimenters:
659 if e != userId and e.getDefaultGroup() is not None and e.getDefaultGroup().id == group.id:
660 experimenterDefaultIds.append(str(e.id))
661
662 if action == 'edit':
663 permissions = getActualPermissions(group)
664 form = GroupOwnerForm(initial={'permissions': permissions, 'members':memberIds, 'owners':ownerIds, 'experimenters':experimenters})
665 context = {'form':form, 'gid': gid, 'permissions': permissions, 'group':group, 'experimenterDefaultGroups':",".join(experimenterDefaultIds), 'ownerIds':(",".join(str(x) for x in ownerIds if x != userId)), 'userId':userId}
666 elif action == "save":
667 if request.method != 'POST':
668 return HttpResponseRedirect(reverse(viewname="wamyaccount", args=["edit", group.id]))
669 else:
670 form = GroupOwnerForm(data=request.POST.copy(), initial={'experimenters':experimenters})
671 if form.is_valid():
672 members = form.cleaned_data['members']
673 owners = form.cleaned_data['owners']
674 permissions = form.cleaned_data['permissions']
675
676 listOfOwners = getSelectedExperimenters(conn, owners)
677 conn.setOwnersOfGroup(group, listOfOwners)
678
679 new_members = getSelectedExperimenters(conn, members)
680 conn.setMembersOfGroup(group, new_members)
681
682 permissions = int(permissions)
683 if getActualPermissions(group) != permissions:
684 perm = setActualPermissions(permissions)
685 conn.updatePermissions(group, perm)
686
687 return HttpResponseRedirect(reverse("wamyaccount"))
688 context = {'form':form, 'gid': gid, 'permissions': permissions, 'group':group, 'experimenterDefaultGroups':",".join(experimenterDefaultIds), 'ownerIds':(",".join(str(x) for x in ownerIds if x != userId)), 'userId':userId}
689 else:
690 return HttpResponseRedirect(reverse("wamyaccount"))
691
692 context['template'] = template
693 return context
694
695
696 @login_required()
697 @render_response_admin()
698 -def my_account(request, action=None, conn=None, **kwargs):
699 template = "webadmin/myaccount.html"
700
701 experimenter, defaultGroup, otherGroups, isLdapUser, hasAvatar = prepare_experimenter(conn)
702 try:
703 defaultGroupId = defaultGroup.id
704 except:
705 defaultGroupId = None
706
707 ownedGroups = ownedGroupsInitial(conn)
708
709 password_form = ChangePassword()
710
711 form = None
712 if action == "save":
713 if request.method != 'POST':
714 return HttpResponseRedirect(reverse(viewname="wamyaccount", args=["edit"]))
715 else:
716 email_check = conn.checkEmail(request.REQUEST.get('email'), experimenter.email)
717 form = MyAccountForm(data=request.POST.copy(), initial={'groups':otherGroups}, email_check=email_check)
718 if form.is_valid():
719 firstName = form.cleaned_data['first_name']
720 middleName = form.cleaned_data['middle_name']
721 lastName = form.cleaned_data['last_name']
722 email = form.cleaned_data['email']
723 institution = form.cleaned_data['institution']
724 defaultGroupId = form.cleaned_data['default_group']
725 conn.updateMyAccount(experimenter, firstName, lastName, email, defaultGroupId, middleName, institution)
726 return HttpResponseRedirect(reverse("wamyaccount"))
727
728 else:
729 form = MyAccountForm(initial={'omename': experimenter.omeName, 'first_name':experimenter.firstName,
730 'middle_name':experimenter.middleName, 'last_name':experimenter.lastName,
731 'email':experimenter.email, 'institution':experimenter.institution,
732 'default_group':defaultGroupId, 'groups':otherGroups})
733
734 photo_size = conn.getExperimenterPhotoSize()
735
736 context = {'form':form, 'ldapAuth': isLdapUser, 'experimenter':experimenter, 'ownedGroups':ownedGroups, 'password_form':password_form}
737 context['template'] = template
738 return context
739
740
741 @login_required()
742 -def myphoto(request, conn=None, **kwargs):
745
746
747 @login_required()
748 @render_response_admin()
749 -def manage_avatar(request, action=None, conn=None, **kwargs):
782
783 @login_required()
784 @render_response_admin()
785 -def stats(request, conn=None, **kwargs):
786 template = "webadmin/statistics.html"
787 context= {'template': template}
788 return context
789
790 @login_required()
791 @render_response_admin()
792 -def drivespace(request, conn=None, **kwargs):
794
795
796 @login_required()
797 -def load_drivespace(request, conn=None, **kwargs):
798 offset = request.REQUEST.get('offset', 0)
799 rv = usersData(conn, offset)
800 return HttpResponse(simplejson.dumps(rv),mimetype='application/json')
801