docbow/docbow_project/docbow/profile_views.py

351 lines
14 KiB
Python

from __future__ import print_function
import urllib.parse
from django.shortcuts import redirect
from django.views.generic.edit import UpdateView, FormView
from django.views.generic.base import TemplateResponseMixin, View
from django.contrib import messages
from django.contrib.auth.models import User
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext as _
from django.http import HttpResponseRedirect
from django.db.transaction import atomic
from django_journal.models import Journal
import requests
from docbow_project.docbow import models
from docbow_project.docbow import forms
from docbow_project.docbow import cbv
from docbow_project.docbow import utils
from docbow_project.docbow import app_settings
class ProfileView(cbv.FormWithRequestMixin, cbv.FormWithPostTarget, UpdateView):
form_class = forms.ProfileForm
template_name = 'docbow/profile.html'
prefix = 'profile'
success_url = '#profile'
def get_object(self):
try:
return models.DocbowProfile.objects.get(user=self.request.user)
except models.DocbowProfile.DoesNotExist:
return None
def is_post_target(self):
return 'profile-validate' in self.request.POST
def form_valid(self, form):
self.request.record('update-profile', 'modified its profile', **form.cleaned_data)
return super(ProfileView, self).form_valid(form)
class DelegateView(cbv.FormWithPostTarget, FormView):
form_class = forms.DelegationForm
template_name = 'docbow/delegate.html'
success_url = '#delegate'
prefix = 'delegate'
def __init__(self, *args, **kwargs):
super(DelegateView, self).__init__(*args, **kwargs)
def add_journal_to_delegations(self, delegations):
delegations__to = [delegation.to for delegation in delegations]
journals = (
Journal.objects.for_objects(delegations__to)
.filter(tag__name='login')
.order_by('-time')[: len(delegations__to) * 5]
)
journal_by_users = dict()
for journal in journals:
for objectdata in journal.objectdata_set.all():
if objectdata.tag.name == 'delegate':
journal_by_users.setdefault(objectdata.object_id, []).append(journal.time)
for delegation in delegations:
delegation.journals = journal_by_users.get(delegation.to.id, [])[:5]
@property
def delegations(self):
qs = models.Delegation.objects.all()
qs = qs.filter(by=self.request.user)
qs = qs.select_related()
qs = qs.prefetch_related('to__docbowprofile')
self.add_journal_to_delegations(qs)
return qs
def get_form_kwargs(self, **kwargs):
kwargs = super(DelegateView, self).get_form_kwargs(**kwargs)
kwargs['user'] = self.request.user
kwargs['delegatees'] = [delegation.to for delegation in self.delegations]
kwargs['request'] = self.request
return kwargs
def delete(self, delegation):
request = self.request
delegation.delete()
delegate_user = delegation.to
request.record(
'delete-delegation',
'deleted delegation ' '{delegation} to user {delegated}',
delegation=delegation.id,
delegated=delegate_user,
)
user = request.user
# notify delegate
ctx = {
'user': utils.clean_ldap_user(user),
'delegate': delegate_user,
'to': [delegate_user.email],
'reply_to': user.email,
}
models.Notification.objects.create(kind='delete-delegation', ctx=ctx)
messages.info(request, _('Delegation %s supressed') % delegate_user)
messages.info(request, _('%s has been notified.') % delegate_user.email)
request.record(
'notify', 'notified {email} of ' 'the deletion of its delegate user', email=delegate_user.email
)
# delete guest accounts
if delegation.guest_delegate:
if 'mellon' in app_settings.settings.INSTALLED_APPS and delegate_user.saml_identifiers.count():
err, json_data, err_desc = utils.a2_wscall(
urllib.parse.urljoin(
app_settings.settings.AUTHENTIC_URL,
'api/users/%s' % delegate_user.saml_identifiers.first().name_id,
),
'delete',
)
delegate_user.delete()
request.record(
'delete-delegate',
'deleted delegate ' 'user {username}, {first_name} {last_name}, ' '({email})',
username=delegate_user.username,
first_name=delegate_user.first_name,
last_name=delegate_user.last_name,
email=delegate_user.email,
)
return HttpResponseRedirect(self.success_url)
def is_post_target(self):
if 'delegate-create' in self.request.POST:
return True
for delegation in self.delegations:
username = delegation.to.username
if 'delegate-delete-{username}.x'.format(username=username) in self.request.POST:
return True
return False
@atomic
def post(self, request, *args, **kwargs):
if 'delegate-create' in request.POST:
return super(DelegateView, self).post(request, *args, **kwargs)
for delegation in self.delegations:
username = delegation.to.username
if 'delegate-delete-{username}.x'.format(username=username) in self.request.POST:
return self.delete(delegation)
return self.get(request, *args, **kwargs)
def form_valid(self, form):
request = self.request
is_guest = not form.cleaned_data.get('existing_user')
ctx = {
'user': utils.clean_ldap_user(request.user),
'reply_to': request.user.email,
'is_guest': is_guest,
}
if is_guest:
delegate_username = utils.get_free_delegation_number(request.user)
delegate_user = User(
username=delegate_username,
first_name=form.cleaned_data.get('first_name', ''),
last_name=form.cleaned_data.get('last_name', ''),
email=form.cleaned_data.get('email', ''),
)
delegate_user.set_unusable_password()
delegate_user.save()
models.DocbowProfile.objects.create(
user=delegate_user,
is_guest=True,
accept_notifications=app_settings.DEFAULT_ACCEPT_NOTIFICATIONS_FOR_GUEST,
)
delegation, created = models.Delegation.objects.get_or_create(by=request.user, to=delegate_user)
if 'mellon' in app_settings.settings.INSTALLED_APPS:
import mellon
ctx['sso'] = True
issuer = mellon.models.Issuer.objects.filter(
entity_id__startswith=app_settings.settings.AUTHENTIC_URL
).first()
if not issuer:
raise ImproperlyConfigured('Mellon issuer not found')
mellon.models.UserSAMLIdentifier.objects.create(
name_id=form.cleaned_data['name_id'],
issuer=issuer,
user=delegate_user,
)
request.record(
'create-delegate',
'created delegate with ' 'parameters {first_name} {last_name} <{email}>',
**form.cleaned_data,
)
ctx.update(
{
'password_reset_link': utils.make_password_reset_url(request, delegate_user),
'to': [form.cleaned_data['email']],
'delegate': delegate_user,
'delegation': delegation,
}
)
messages.info(request, _('New delegation to user %s created.') % delegate_user.username)
messages.info(
request, _('A notification was sent to %s about this new delegation') % delegate_user.email
)
else:
delegate_user = form.cleaned_data.get('existing_user')
delegate_username = delegate_user.username
delegation, created = models.Delegation.objects.get_or_create(by=request.user, to=delegate_user)
ctx.update(
{
'to': models.all_emails(delegate_user),
'delegate': delegate_user,
'delegation': delegation,
}
)
messages.info(request, _('New delegation to user %s created.') % delegate_user.username)
messages.info(
request,
_('A notification was sent to %s about this new delegation') % delegate_user.get_full_name(),
)
models.Notification.objects.create(kind='new-delegation', ctx=ctx)
request.record(
'create-delegation', 'created delegation to ' 'user {delegated}', delegated=delegate_user
)
return super(DelegateView, self).form_valid(form)
def get_context_data(self, **kwargs):
ctx = super(DelegateView, self).get_context_data(**kwargs)
ctx['delegations'] = self.delegations
ctx['received_delegations'] = self.request.user.delegations_by.all()
ctx['delegate_to_existing_user'] = app_settings.DELEGATE_TO_EXISTING_USER
return ctx
class PasswordChangeView(cbv.FormWithPostTarget, FormView):
template_name = 'registration/password_change_form.html'
form_class = forms.PasswordChangeFormWithLogging
prefix = 'password-change'
success_url = '#password-change'
def is_post_target(self):
return 'password-change-validate' in self.request.POST
def form_valid(self, form):
messages.info(self.request, _('Password changed'))
form.save()
return super(PasswordChangeView, self).form_valid(form)
def get_form_kwargs(self, **kwargs):
kwargs = super(PasswordChangeView, self).get_form_kwargs(**kwargs)
kwargs['user'] = self.request.user
return kwargs
class EmailView(cbv.FormWithPostTarget, UpdateView):
form_class = forms.EmailForm
template_name = 'docbow/email.html'
prefix = 'email'
success_url = '#email'
def get_object(self):
return self.request.user
def form_valid(self, form):
messages.info(self.request, _('Email changed'))
self.request.record('update-email', 'modified its email', **form.cleaned_data)
return super(EmailView, self).form_valid(form)
class NotificationPreferenceView(cbv.FormWithPostTarget, cbv.FormWithRequestMixin, FormView):
form_class = forms.NotificationPreferencesForm
template_name = 'docbow/notifications.html'
success_url = '#notifications'
prefix = 'notifications'
def form_valid(self, form):
form.save()
messages.info(self.request, _('Notification preferences saved'))
return super(NotificationPreferenceView, self).form_valid(form)
def get_context_data(self, **kwargs):
ctx = super(NotificationPreferenceView, self).get_context_data(**kwargs)
ctx['mobile_phone'] = app_settings.MOBILE_PHONE
ctx['mobile_phone_paragraph'] = _(
u'If You would like to receive a SMS alert each '
u'time your inbox receives a document, provide your '
u'mobile phone number. If you do not fill this field '
u'you won\'t receive any SMS alert'
)
return ctx
class FullProfileView(TemplateResponseMixin, View):
# multiplex all profile views
template_name = 'docbow/full-profile.html'
subviews = (
('notifications_form', NotificationPreferenceView),
('delegate_form', DelegateView),
)
if 'mellon' not in app_settings.settings.INSTALLED_APPS:
subviews = subviews + (('password_change_form', PasswordChangeView),)
if app_settings.MOBILE_PHONE or app_settings.PERSONAL_EMAIL:
subviews = (('profile_form', ProfileView),) + subviews
if app_settings.EDIT_EMAIL and 'mellon' not in app_settings.settings.INSTALLED_APPS:
subviews += (('email_form', EmailView),)
def dispatch(self, request, *args, **kwargs):
if models.is_guest(request.user):
self.subviews = filter(lambda s: s[0] != 'delegate_form', self.subviews)
print(self.subviews)
return super(FullProfileView, self).dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
ctx = {}
for var_name, view_class in self.subviews:
res = self.get_view(var_name, view_class)
if isinstance(res, dict):
ctx.update(res)
else:
return res
return self.render_to_response(ctx)
def get_view(self, var_name, view_class):
view = view_class()
view.request, view.args, view.kwargs = self.request, self.args, self.kwargs
if hasattr(view, 'get_object'):
view.object = view.get_object()
if self.request.method == 'POST' and view.is_post_target():
res = view.post(self.request, *self.args, **self.kwargs)
if isinstance(res, HttpResponseRedirect):
return res
else:
ctx = res.context_data
ctx[var_name] = ctx.pop('form')
return ctx
else:
form_class = view.get_form_class()
form = view.get_form(form_class)
return view.get_context_data(**{var_name: form})
def get(self, request, *args, **kwargs):
ctx = {}
for var_name, view_class in self.subviews:
ctx.update(self.get_view(var_name, view_class))
return self.render_to_response(ctx)