regluit/libraryauth/views.py

277 lines
12 KiB
Python

import logging
import random
from django.conf import settings
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, render
from django.contrib.auth.forms import SetPasswordForm
from django.contrib.auth.views import login, password_reset, password_change
from django.contrib.auth import login as login_to_user
from django.contrib.auth import load_backend
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from django.views.generic.edit import FormView, CreateView, UpdateView, SingleObjectMixin
from registration.backends.model_activation.views import RegistrationView
from . import backends
from .models import Library
from .forms import AuthForm, LibraryForm, NewLibraryForm, RegistrationFormNoDisposableEmail, UserData
logger = logging.getLogger(__name__)
def get_library_or_404(library=None, library_id=None):
if library_id:
return get_object_or_404(Library, id=library_id)
else:
return get_object_or_404(Library, user__username=library)
def library(request, library=None, library_id=None,
extra_context={},
template='libraryauth/library.html',
**kwargs):
library=get_library_or_404(library=library, library_id=library_id)
context={ 'library':library,
'is_admin': request.user.is_staff or request.user==library.user,
'is_member': request.user.is_staff or library.has_user(request.user),
}
context.update(extra_context)
return render(request, template, context)
def join_library(request, library_id):
library=get_library_or_404(library_id=library_id)
return Authenticator(request,library).process(
reverse('library',args=[library.user]),
reverse('bad_library',args=[library.id]),
)
def superlogin(request, extra_context={}, **kwargs):
if request.method == 'POST' and request.user.is_anonymous():
username=request.POST.get("username", "")
try:
user=models.User.objects.get(username=username)
extra_context={"socials":user.profile.social_auths}
except:
pass
if request.GET.has_key("add"):
request.session["add_wishlist"]=request.GET["add"]
return login(request, extra_context=extra_context, authentication_form=AuthForm, **kwargs)
def social_aware_password_change(request, **kwargs):
if request.user.has_usable_password():
return password_change(request, **kwargs)
return password_change(request, password_change_form=SetPasswordForm, **kwargs)
class Authenticator:
request=None
library=None
def __init__(self, request, library, *args, **kwargs):
self.request = request
if isinstance(library , basestring):
self.library = Library.objects.get(user__username=library)
elif isinstance(library , Library):
self.library=library
else:
raise Exception
self.backend_class=getattr(backends,self.library.backend)
form_class = self.backend_class.form
if form_class:
self.form = form_class(request, self.library, *args, **kwargs)
else:
self.form = None
def process(self, success_url, deny_url):
logger.info('authenticator for %s at %s.'%(self.request.user, self.library))
if self.library.has_user(self.request.user):
return HttpResponseRedirect(success_url)
if self.backend_class().authenticate(self.request, self.library):
if self.request.user.is_authenticated():
self.library.add_user(self.request.user)
return HttpResponseRedirect(success_url)
else:
return superlogin(self.request, extra_context={'library':self.library}, template_name='libraryauth/library_login.html')
else:
return self.backend_class.authenticator().process(self, success_url, deny_url)
def allowed(self):
return self.backend_class().authenticate(self.request, self.library)
class BaseLibraryView:
model = Library
template_name="libraryauth/edit.html"
class CreateLibraryView(BaseLibraryView, CreateView):
form_class = NewLibraryForm
def get_initial(self):
return {'email': self.request.user.email}
def form_valid(self, form):
form.instance.owner = self.request.user
user = form.instance.user
user.email = form.cleaned_data['email']
user.save()
form.instance.user = user
form.instance.save()
form.instance.add_user(user) # library is a member of itself
form.instance.add_user(self.request.user) # library.owner is a member of library
context_data = self.get_context_data(form=form)
context_data['status'] = 'Library Updated'
return HttpResponseRedirect(reverse('library_admin',args=[form.instance.id]))
class UpdateLibraryView(BaseLibraryView, UpdateView):
pk_url_kwarg = 'library_id'
form_class = LibraryForm
def form_valid(self, form):
context_data = self.get_context_data(form=form)
form.instance.save()
context_data['status'] = 'Library Updated.'
return self.render_to_response(context_data)
def get_backend_form_class(self):
if self.object and self.object.backend:
backend_class=getattr(backends,self.object.backend)
return backend_class.admin_form
else:
return None
def get_backend_admin_forms(self):
if self.object and self.object.backend:
backend_models_name = '%s_auths' % self.object.backend
backend_models = getattr(self.object,backend_models_name)
backend_new_form = self.get_backend_form_class()(initial = {'library':self.object}, prefix="new")
backend_old_forms = [self.get_backend_form_class()(instance = backend_model, prefix="backend_%s"%backend_model.id) for backend_model in backend_models.all()]
return backend_old_forms + [backend_new_form]
else:
return []
def get_context_data(self, backend_form=None, form=None, **kwargs):
context = super(UpdateLibraryView,self).get_context_data(**kwargs)
backend_admin_forms = self.get_backend_admin_forms()
if backend_form:
backend_admin_forms = [ backend_form if backend_form.prefix== backend_admin_form.prefix else backend_admin_form for backend_admin_form in backend_admin_forms]
context['backend_admin_forms'] = backend_admin_forms
if form:
context['form'] = form
return context
def get(self, request, *args, **kwargs):
self.object = self.get_object()
# check permissions
if request.user not in [self.object.owner, self.object.user]:
context_data={'status': 'You\'re not permitted to edit this library.'}
return self.render_to_response(context_data)
form = self.get_form(self.form_class)
return self.render_to_response(self.get_context_data(form=form))
def post(self, request, *args, **kwargs):
# get the user instance (the library)
self.object = self.get_object()
# check permissions
if request.user not in [self.object.owner, self.object.user]:
context_data={'status': 'You\'re not permitted to edit this library.'}
return self.render_to_response(context_data)
# determine if backend form is being submitted
# uses the name of the form's submit button
if 'backend_submit' in request.POST or 'backend_delete' in request.POST:
# get the form
form_class = self.get_backend_form_class()
form_model = form_class.Meta.model
backend_id = request.POST['id']
if 'backend_submit' in request.POST:
# we're editing the backend
if backend_id is None or backend_id=="None":
backend_model_instance = form_model(library=self.object)
form = form_class(data=request.POST, instance=backend_model_instance, prefix="new")
else:
backend_model_instance = form_model.objects.get(id=backend_id)
form = form_class(data=request.POST, instance=backend_model_instance, prefix="backend_%s"%request.POST['id'])
if form.is_valid():
form.save()
status = 'User Validation Updated.'
context_data = self.get_context_data( form=self.form_class(instance=self.object))
else:
status = 'Problem with User Validation.'
context_data = self.get_context_data(backend_form=form, form=self.form_class(instance=self.object))
else:
#deleting a backend
if backend_id is not None and backend_id!="None":
backend_model_instance = form_model.objects.get(id=backend_id)
backend_model_instance.delete()
status = 'Deleted.'
else:
status = 'Nothing to delete.'
context_data = self.get_context_data( form=self.form_class(instance=self.object))
context_data['status'] = status
return self.render_to_response(context_data)
else:
# just use regular post handler
form = self.get_form(self.form_class)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
@login_required
def login_as_library(request, library_id):
library=get_library_or_404(library_id=library_id)
if request.user == library.owner:
login_user(request, library.user)
return HttpResponseRedirect(reverse('library_admin',args=[library.id]))
def login_user(request, user):
"""
Log in a user without requiring credentials (using ``login`` from
``django.contrib.auth``, first finding a matching backend).
magic from https://djangosnippets.org/snippets/1547/
"""
if not hasattr(user, 'backend'):
for backend in settings.AUTHENTICATION_BACKENDS:
if user == load_backend(backend).get_user(user.pk):
user.backend = backend
break
if hasattr(user, 'backend'):
return login_to_user(request, user)
robot_qs = {
'user',
'user/register',
'node/add',
}
class CustomRegistrationView(RegistrationView):
form_class = RegistrationFormNoDisposableEmail
def form_valid(self, form):
q = self.request.session.get('q', False)
if q and q in robot_qs:
return self.render_to_response({'form':form})
return super(CustomRegistrationView,self).form_valid(form)
def edit_user(request, redirect_to=None):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('superlogin'))
form=UserData()
if request.method == 'POST':
if 'change_username' in request.POST.keys():
form = UserData(request.POST)
form.oldusername = request.user.username
if form.is_valid(): # All validation rules pass, go and change the username
request.user.username=form.cleaned_data['username']
request.user.save()
if 'set_password' in request.POST.keys() and form.cleaned_data.has_key('set_password'):
if not request.user.has_usable_password():
request.user.set_password(form.cleaned_data['set_password'])
request.user.save()
return HttpResponseRedirect(redirect_to if redirect_to else reverse('home')) # Redirect after POST
return render(request,'registration/user_change_form.html', {'form': form})