from urllib import quote
from functools import wraps
from datetime import datetime, timedelta
+from collections import defaultdict
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.utils import IntegrityError
from django.forms.fields import URLField
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, \
- HttpResponseRedirect, HttpResponseBadRequest
+ HttpResponseRedirect, HttpResponseBadRequest, Http404
from django.shortcuts import redirect
-from django.template import RequestContext, loader
+from django.template import RequestContext, loader as template_loader
from django.utils.http import urlencode
from django.utils.translation import ugettext as _
from django.views.generic.create_update import (create_object, delete_object,
get_model_and_form_class)
from django.views.generic.list_detail import object_list, object_detail
from django.http import HttpResponseBadRequest
+from django.core.xheaders import populate_xheaders
from astakos.im.models import (
AstakosUser, ApprovalTerms, AstakosGroup, Resource,
FeedbackForm, SignApprovalTermsForm,
ExtendedPasswordChangeForm, EmailChangeForm,
AstakosGroupCreationForm, AstakosGroupSearchForm,
- AstakosGroupUpdateForm, AddGroupMembersForm)
+ AstakosGroupUpdateForm, AddGroupMembersForm,
+ AstakosGroupSortForm, MembersSortForm,
+ TimelineForm)
from astakos.im.functions import (send_feedback, SendMailError,
invite as invite_func, logout as auth_logout,
activate as activate_func,
switch_account_to_shibboleth,
send_admin_notification,
SendNotificationError)
+from astakos.im.endpoints.quotaholder import timeline_charge
from astakos.im.settings import (
COOKIE_NAME, COOKIE_DOMAIN, SITENAME, LOGOUT_NEXT,
- LOGGING_LEVEL
-)
+ LOGGING_LEVEL, PAGINATE_BY)
from astakos.im.tasks import request_billing
logger = logging.getLogger(__name__)
+DB_REPLACE_GROUP_SCHEME = """REPLACE(REPLACE("auth_group".name, 'http://', ''),
+ 'https://', '')"""
+
def render_response(template, tab=None, status=200, reset_cookie=False,
context_instance=None, **kwargs):
"""
if tab is None:
tab = template.partition('_')[0].partition('.html')[0]
kwargs.setdefault('tab', tab)
- html = loader.render_to_string(
+ html = template_loader.render_to_string(
template, kwargs, context_instance=context_instance)
response = HttpResponse(html, status=status)
if reset_cookie:
logger.log(LOGGING_LEVEL, msg)
if user and user.is_active:
next = request.POST.get('next', '')
- transaction.commit()
+ transaction.commit()
return prepare_response(request, user, next=next)
messages.add_message(request, status, message)
- transaction.commit()
+ transaction.commit()
return render_response(on_success,
context_instance=get_context(request, extra_context))
except SendMailError, e:
return response
messages.success(request, _('You have successfully logged out.'))
context = get_context(request, extra_context)
- response.write(loader.render_to_string(template, context_instance=context))
+ response.write(template_loader.render_to_string(template, context_instance=context))
return response
@transaction.commit_manually
-def activate(request, greeting_email_template_name='im/welcome_email.txt', helpdesk_email_template_name='im/helpdesk_notification.txt'):
+def activate(request, greeting_email_template_name='im/welcome_email.txt',
+ helpdesk_email_template_name='im/helpdesk_notification.txt'):
"""
Activates the user identified by the ``auth`` request parameter, sends a welcome email
and renews the user token.
except:
return HttpResponseBadRequest(_('No such group kind'))
- template_loader = loader
post_save_redirect = '/im/group/%(id)s/'
context_processors = None
model, form_class = get_model_and_form_class(
@signed_terms_required
@login_required
def group_list(request):
- list = request.user.astakos_groups.select_related().all()
- return object_list(request, queryset=list,
- extra_context=dict(
- is_search=False
- )
- )
+ none = request.user.astakos_groups.none()
+ q = AstakosGroup.objects.raw("""
+ SELECT auth_group.id,
+ %s AS groupname,
+ im_groupkind.name AS kindname,
+ im_astakosgroup.*,
+ owner.email AS groupowner,
+ (SELECT COUNT(*) FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND date_joined IS NOT NULL) AS approved_members_num,
+ (SELECT CASE WHEN(
+ SELECT date_joined FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND person_id = %s) IS NULL
+ THEN 0 ELSE 1 END) AS membership_status
+ FROM im_astakosgroup
+ INNER JOIN im_membership ON (
+ im_astakosgroup.group_ptr_id = im_membership.group_id)
+ INNER JOIN auth_group ON(im_astakosgroup.group_ptr_id = auth_group.id)
+ INNER JOIN im_groupkind ON (im_astakosgroup.kind_id = im_groupkind.id)
+ LEFT JOIN im_astakosuser_owner ON (
+ im_astakosuser_owner.astakosgroup_id = im_astakosgroup.group_ptr_id)
+ LEFT JOIN auth_user as owner ON (
+ im_astakosuser_owner.astakosuser_id = owner.id)
+ WHERE im_membership.person_id = %s
+ """ % (DB_REPLACE_GROUP_SCHEME, request.user.id, request.user.id))
+ d = defaultdict(list)
+ for g in q:
+ if request.user.email == g.groupowner:
+ d['own'].append(g)
+ else:
+ d['other'].append(g)
+
+ # validate sorting
+ fields = ('own', 'other')
+ for f in fields:
+ v = globals()['%s_sorting' % f] = request.GET.get('%s_sorting' % f)
+ if v:
+ form = AstakosGroupSortForm({'sort_by': v})
+ if not form.is_valid():
+ globals()['%s_sorting' % f] = form.cleaned_data.get('sort_by')
+ return object_list(request, queryset=none,
+ extra_context={'is_search':False,
+ 'mine': d['own'],
+ 'other': d['other'],
+ 'own_sorting': own_sorting,
+ 'other_sorting': other_sorting,
+ 'own_page': request.GET.get('own_page', 1),
+ 'other_page': request.GET.get('other_page', 1)
+ })
@signed_terms_required
@login_required
def group_detail(request, group_id):
+ q = AstakosGroup.objects.select_related().filter(pk=group_id)
+ q = q.extra(select={
+ 'is_member': """SELECT CASE WHEN EXISTS(
+ SELECT id FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND person_id = %s)
+ THEN 1 ELSE 0 END""" % request.user.id,
+ 'is_owner': """SELECT CASE WHEN EXISTS(
+ SELECT id FROM im_astakosuser_owner
+ WHERE astakosgroup_id = im_astakosgroup.group_ptr_id
+ AND astakosuser_id = %s)
+ THEN 1 ELSE 0 END""" % request.user.id,
+ 'kindname': """SELECT name FROM im_groupkind
+ WHERE id = im_astakosgroup.kind_id"""})
+
+ model = q.model
+ context_processors = None
+ mimetype = None
try:
- group = AstakosGroup.objects.select_related().get(id=group_id)
+ obj = q.get()
except AstakosGroup.DoesNotExist:
- return HttpResponseBadRequest(_('Invalid group.'))
- form = AstakosGroupUpdateForm(instance=group)
- search_form = AddGroupMembersForm()
- return object_detail(request,
- AstakosGroup.objects.all(),
- object_id=group_id,
- extra_context={'quota': group.quota,
- 'form': form,
- 'search_form': search_form}
- )
-
+ raise Http404("No %s found matching the query" % (
+ model._meta.verbose_name))
+
+ update_form = AstakosGroupUpdateForm(instance=obj)
+ addmembers_form = AddGroupMembersForm()
+ if request.method == 'POST':
+ update_data = {}
+ addmembers_data = {}
+ for k,v in request.POST.iteritems():
+ if k in update_form.fields:
+ update_data[k] = v
+ if k in addmembers_form.fields:
+ addmembers_data[k] = v
+ update_data = update_data or None
+ addmembers_data = addmembers_data or None
+ update_form = AstakosGroupUpdateForm(update_data, instance=obj)
+ addmembers_form = AddGroupMembersForm(addmembers_data)
+ if update_form.is_valid():
+ update_form.save()
+ if addmembers_form.is_valid():
+ map(obj.approve_member, addmembers_form.valid_users)
+ addmembers_form = AddGroupMembersForm()
+
+ template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
+ t = template_loader.get_template(template_name)
+ c = RequestContext(request, {
+ 'object': obj,
+ }, context_processors)
+
+ # validate sorting
+ sorting= request.GET.get('sorting')
+ if sorting:
+ form = MembersSortForm({'sort_by': sorting})
+ if form.is_valid():
+ sorting = form.cleaned_data.get('sort_by')
+
+ extra_context = {'update_form': update_form,
+ 'addmembers_form': addmembers_form,
+ 'page': request.GET.get('page', 1),
+ 'sorting': sorting}
+ for key, value in extra_context.items():
+ if callable(value):
+ c[key] = value()
+ else:
+ c[key] = value
+ response = HttpResponse(t.render(c), mimetype=mimetype)
+ populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
+ return response
-@signed_terms_required
-@login_required
-def group_update(request, group_id):
- if request.method != 'POST':
- return HttpResponseBadRequest('Method not allowed.')
- try:
- group = AstakosGroup.objects.select_related().get(id=group_id)
- except AstakosGroup.DoesNotExist:
- return HttpResponseBadRequest(_('Invalid group.'))
- form = AstakosGroupUpdateForm(request.POST, instance=group)
- if form.is_valid():
- form.save()
- search_form = AddGroupMembersForm()
- return object_detail(request,
- AstakosGroup.objects.all(),
- object_id=group_id,
- extra_context={'quota': group.quota,
- 'form': form,
- 'search_form': search_form})
@signed_terms_required
@login_required
def group_search(request, extra_context=None, **kwargs):
+ q = request.GET.get('q')
+ sorting = request.GET.get('sorting')
if request.method == 'GET':
- form = AstakosGroupSearchForm()
+ form = AstakosGroupSearchForm({'q': q} if q else None)
else:
form = AstakosGroupSearchForm(get_query(request))
if form.is_valid():
q = form.cleaned_data['q'].strip()
- queryset = AstakosGroup.objects.select_related(
- ).filter(name__contains=q)
- return object_list(
- request,
- queryset,
- template_name='im/astakosgroup_list.html',
- extra_context=dict(form=form,
- is_search=True))
- return render_response(
- template='im/astakosgroup_list.html',
- form=form,
- context_instance=get_context(request, extra_context),
- is_search=False
- )
+ if q:
+ queryset = AstakosGroup.objects.select_related()
+ queryset = queryset.filter(name__contains=q)
+ queryset = queryset.filter(approval_date__isnull=False)
+ queryset = queryset.extra(select={
+ 'groupname': DB_REPLACE_GROUP_SCHEME,
+ 'kindname': "im_groupkind.name",
+ 'approved_members_num': """
+ SELECT COUNT(*) FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND date_joined IS NOT NULL""",
+ 'membership_approval_date': """
+ SELECT date_joined FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND person_id = %s""" % request.user.id,
+ 'is_member': """
+ SELECT CASE WHEN EXISTS(
+ SELECT date_joined FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND person_id = %s)
+ THEN 1 ELSE 0 END""" % request.user.id,
+ 'is_owner': """
+ SELECT CASE WHEN EXISTS(
+ SELECT id FROM im_astakosuser_owner
+ WHERE astakosgroup_id = im_astakosgroup.group_ptr_id
+ AND astakosuser_id = %s)
+ THEN 1 ELSE 0 END""" % request.user.id})
+ if sorting:
+ # TODO check sorting value
+ queryset = queryset.order_by(sorting)
+ else:
+ queryset = AstakosGroup.objects.none()
+ return object_list(
+ request,
+ queryset,
+ paginate_by=PAGINATE_BY,
+ page=request.GET.get('page') or 1,
+ template_name='im/astakosgroup_list.html',
+ extra_context=dict(form=form,
+ is_search=True,
+ q=q,
+ sorting=sorting))
@signed_terms_required
@login_required
def group_all(request, extra_context=None, **kwargs):
- if request.method != 'POST':
- return HttpResponseBadRequest(_('Bad method'))
+ q = AstakosGroup.objects.select_related()
+ q = q.filter(approval_date__isnull=False)
+ q = q.extra(select={
+ 'groupname': DB_REPLACE_GROUP_SCHEME,
+ 'kindname': "im_groupkind.name",
+ 'approved_members_num': """
+ SELECT COUNT(*) FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND date_joined IS NOT NULL""",
+ 'membership_approval_date': """
+ SELECT date_joined FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND person_id = %s""" % request.user.id,
+ 'is_member': """
+ SELECT CASE WHEN EXISTS(
+ SELECT date_joined FROM im_membership
+ WHERE group_id = im_astakosgroup.group_ptr_id
+ AND person_id = %s)
+ THEN 1 ELSE 0 END""" % request.user.id})
+ sorting = request.GET.get('sorting')
+ if sorting:
+ # TODO check sorting value
+ q = q.order_by(sorting)
return object_list(
request,
- AstakosGroup.objects.select_related().all(),
+ q,
+ paginate_by=PAGINATE_BY,
+ page=request.GET.get('page') or 1,
template_name='im/astakosgroup_list.html',
extra_context=dict(form=AstakosGroupSearchForm(),
- is_search=True))
+ is_search=True,
+ sorting=sorting))
@signed_terms_required
def group_join(request, group_id):
m = Membership(group_id=group_id,
person=request.user,
- date_requested=datetime.now()
- )
+ date_requested=datetime.now())
try:
m.save()
post_save_redirect = reverse(
'group_detail',
- kwargs=dict(group_id=group_id)
- )
+ kwargs=dict(group_id=group_id))
return HttpResponseRedirect(post_save_redirect)
except IntegrityError, e:
logger.exception(e)
try:
m = Membership.objects.select_related().get(
group__id=group_id,
- person=request.user
- )
+ person=request.user)
except Membership.DoesNotExist:
return HttpResponseBadRequest(_('Invalid membership.'))
if request.user in m.group.owner.all():
template_name='im/astakosgroup_list.html',
post_delete_redirect=reverse(
'group_detail',
- kwargs=dict(group_id=group_id)
- )
- )
+ kwargs=dict(group_id=group_id)))
def handle_membership(func):
try:
m = Membership.objects.select_related().get(
group__id=group_id,
- person__id=user_id
- )
+ person__id=user_id)
except Membership.DoesNotExist:
return HttpResponseBadRequest(_('Invalid membership.'))
else:
if request.user not in m.group.owner.all():
return HttpResponseForbidden(_('User is not a group owner.'))
func(request, m)
- return render_response(
- template='im/astakosgroup_detail.html',
- context_instance=get_context(request),
- object=m.group,
- quota=m.group.quota
- )
+ return group_detail(request, group_id)
return wrapper
messages.success(request, msg)
except BaseException, e:
logger.exception(e)
+ realname = membership.person.realname
msg = _('Something went wrong during %s\'s approval.' % realname)
messages.error(request, msg)
messages.error(request, msg)
-
-
-@signed_terms_required
-@login_required
-def add_members(request, group_id):
- if request.method != 'POST':
- return HttpResponseBadRequest(_('Bad method'))
- try:
- group = AstakosGroup.objects.select_related().get(id=group_id)
- except AstakosGroup.DoesNotExist:
- return HttpResponseBadRequest(_('Invalid group.'))
- search_form = AddGroupMembersForm(request.POST)
- if search_form.is_valid():
- users = search_form.get_valid_users()
- map(group.approve_member, users)
- search_form = AddGroupMembersForm()
- form = AstakosGroupUpdateForm(instance=group)
- return object_detail(request,
- AstakosGroup.objects.all(),
- object_id=group_id,
- extra_context={'quota': group.quota,
- 'form': form,
- 'search_form' : search_form}
- )
-
-
@signed_terms_required
@login_required
def resource_list(request):
return render_response(
template='im/astakosuserquota_list.html',
- context_instance=get_context(request),
- quota=request.user.quota
- )
+ context_instance=get_context(request))
def group_create_list(request):
return render_response(
template='im/astakosgroup_create_list.html',
- context_instance=get_context(request),
- )
+ context_instance=get_context(request),)
@signed_terms_required
try:
status, data = r.result
- data=clear_billing_data(data)
+ data=_clear_billing_data(data)
if status != 200:
messages.error(request, _('Service response status: %d' % status))
except:
start=int(start),
month_last_day=month_last_day)
-def clear_billing_data(data):
+def _clear_billing_data(data):
# remove addcredits entries
def isnotcredit(e):
data['bill_addcredits'] = filter(servicefilter('addcredits'), data['bill'])
return data
+
+@signed_terms_required
+@login_required
+def timeline(request):
+# data = {'entity':request.user.email}
+ timeline_body = ()
+ timeline_header = ()
+# form = TimelineForm(data)
+ form = TimelineForm()
+ if request.method == 'POST':
+ data = request.POST
+ form = TimelineForm(data)
+ if form.is_valid():
+ data = form.cleaned_data
+ timeline_header = ('entity', 'resource',
+ 'event name', 'event date',
+ 'incremental cost', 'total cost')
+ timeline_body = timeline_charge(
+ data['entity'], data['resource'],
+ data['start_date'], data['end_date'],
+ data['details'], data['operation'])
+
+ return render_response(template='im/timeline.html',
+ context_instance=get_context(request),
+ form=form,
+ timeline_header=timeline_header,
+ timeline_body=timeline_body)
+ return data