gestioCOF/kfet/views.py
Aurélien Delobelle 4cb89aa005 Gestion des permissions dans K-Psul
- Ajout d'une méthode sur Account pour connaître les permissions
  nécessaires pour enregistrer des opérations en fonction du futur solde
  du compte
- Ajout d'une permission pour effectuer une charge sur un compte
- Ajoute que l'utilisateur connecté doit avoir toutes les permissions
  nécessaires pour enregistrer un groupe d'opérations. Si ce n'est pas
le cas, aucune opération n'est enregistrée et les permissions manquantes
sont envoyées en réponse.
- Dans le cas d'une charge ou d'un retrait, "article" et "article_nb" de
  Operation sont définis à NULL
2016-08-07 23:41:46 +02:00

463 lines
16 KiB
Python

from django.shortcuts import render, get_object_or_404, redirect
from django.core.exceptions import PermissionDenied, ValidationError
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.models import User, Permission
from django.http import HttpResponse, JsonResponse, Http404
from django.forms import modelformset_factory
from gestioncof.models import CofProfile, Clipper
from kfet.models import Account, Checkout, Article, Settings
from kfet.forms import *
from collections import defaultdict
@login_required
def home(request):
return render(request, "kfet/base.html")
def put_cleaned_data_in_dict(dict, form):
for field in form.cleaned_data:
dict[field] = form.cleaned_data[field]
# -----
# Account views
# -----
# Account - General
@login_required
@permission_required('account.is_team')
def account(request):
accounts = Account.objects.order_by('trigramme')
return render(request, "kfet/account.html", { 'accounts' : accounts })
@login_required
@permission_required('kfet.is_team')
def account_is_validandfree_ajax(request):
if not request.GET.get("trigramme"):
raise Http404
trigramme = request.GET.get("trigramme")
data = Account.is_validandfree(trigramme)
return JsonResponse(data)
# Account - Create
@login_required
@permission_required('account.is_team')
def account_create(request):
# A envoyer au template
data_template = {
'account_trigramme_form': AccountTriForm(),
'errors' : {},
}
# Enregistrement
if request.method == "POST":
# Pour indiquer la tentative d'enregistrement au template
# Checking permission
if not request.user.has_perm('kfet.add_account'):
raise PermissionDenied
# Peuplement des forms
username = request.POST.get('username')
try:
user = User.objects.get(username=username)
(cof, _) = CofProfile.objects.get_or_create(user=user)
user_form = UserForm(request.POST, instance=user)
cof_form = CofForm(request.POST, instance=cof)
except User.DoesNotExist:
user_form = UserForm(request.POST)
cof_form = CofForm(request.POST)
trigramme_form = AccountTriForm(request.POST)
account_form = AccountNoTriForm(request.POST)
# Ajout des erreurs pour le template
data_template['errors']['user_form'] = user_form.errors
data_template['errors']['cof_form'] = cof_form.errors
data_template['errors']['trigramme_form'] = trigramme_form.errors
data_template['errors']['account_form'] = account_form.errors
if all((user_form.is_valid(), cof_form.is_valid(),
trigramme_form.is_valid(), account_form.is_valid())):
data = {}
# Fill data for Account.save()
put_cleaned_data_in_dict(data, user_form)
put_cleaned_data_in_dict(data, cof_form)
try:
account = trigramme_form.save(data = data)
account_form = AccountNoTriForm(request.POST, instance=account)
account_form.save()
messages.success(request, 'Compte créé : %s' % account.trigramme)
except Account.UserHasAccount as e:
messages.error(request, \
"Cet utilisateur a déjà un compte K-Fêt : %s" % e.trigramme)
return render(request, "kfet/account_create.html", data_template)
def account_form_set_readonly_fields(user_form, cof_form):
user_form.fields['username'].widget.attrs['readonly'] = True
cof_form.fields['login_clipper'].widget.attrs['readonly'] = True
cof_form.fields['is_cof'].widget.attrs['disabled'] = True
@login_required
@permission_required('kfet.is_team')
def account_create_ajax(request, username=None, login_clipper=None):
user = None
if login_clipper:
# à partir d'un clipper
# le user associé à ce clipper ne devrait pas encore existé
clipper = get_object_or_404(Clipper, username = login_clipper)
try:
# Vérification que clipper ne soit pas déjà dans User
user = User.objects.get(username=login_clipper)
# Ici, on nous a menti, le user existe déjà
username = user.username
login_clipper = None
except User.DoesNotExist:
# Clipper (sans user déjà existant)
# UserForm - Prefill + Création
user_initial_data = {
'username' : login_clipper,
'email' : login_clipper + "@clipper.ens.fr"}
if clipper.fullname:
# Prefill du nom et prénom
names = clipper.fullname.split()
# Le premier, c'est le prénom
user_initial_data['first_name'] = names[0]
if len(names) > 1:
# Si d'autres noms -> tous dans le nom de famille
user_initial_data['last_name'] = " ".join(names[1:])
user_form = UserForm(initial = user_initial_data)
# CofForm - Prefill + Création
cof_initial_data = { 'login_clipper': login_clipper }
cof_form = CofForm(initial = cof_initial_data)
# AccountForm
account_form = AccountForm()
# Protection (read-only) des champs username et login_clipper
account_form_set_readonly_fields(user_form, cof_form)
if username:
# le user existe déjà
user = get_object_or_404(User, username=username)
# récupération du profil cof
(cof, _) = CofProfile.objects.get_or_create(user=user)
# UserForm + CofForm - Création à partir des instances existantes
user_form = UserForm(instance = user)
cof_form = CofForm(instance = cof)
# AccountForm
account_form = AccountNoTriForm()
# Protection (read-only) des champs username et login_clipper
account_form_set_readonly_fields(user_form, cof_form)
elif not login_clipper:
# connaît pas du tout, faut tout remplir
user_form = UserForm()
cof_form = CofForm()
account_form = AccountNoTriForm()
return render(request, "kfet/account_create_form.html", {
'account_form' : account_form,
'cof_form' : cof_form,
'user_form' : user_form,
})
# Account - Read
@login_required
def account_read(request, trigramme):
try:
account = Account.objects.get(trigramme=trigramme)
except Account.DoesNotExist:
raise Http404
# Checking permissions
if not request.user.has_perm('kfet.is_team') \
and request.user != account.user:
raise PermissionDenied
return render(request, "kfet/account_read.html", { 'account' : account })
# Account - Update
@login_required
def account_update(request, trigramme):
try:
account = Account.objects.get(trigramme=trigramme)
except Account.DoesNotExist:
raise Http404
# Checking permissions
if not request.user.has_perm('kfet.is_team') \
and request.user != account.user:
raise PermissionDenied
if request.method == "POST":
# Update attempt
# Checking permissions
if not request.user.has_perm('kfet.change_account') \
and request.user != account.user:
raise PermissionDenied
# Peuplement des forms
if request.user.has_perm('kfet.change_account'):
account_form = AccountForm(request.POST, instance = account)
else:
account_form = AccountRestrictForm(request.POST, instance = account)
cof_form = CofRestrictForm(request.POST, instance=account.cofprofile)
user_form = UserRestrictForm(request.POST, instance=account.user)
if all((account_form.is_valid(), cof_form.is_valid(), user_form.is_valid())):
data = {}
# Fill data for Account.save()
put_cleaned_data_in_dict(data, user_form)
put_cleaned_data_in_dict(data, cof_form)
# Updating
account_form.save(data = data)
if request.user == account.user:
messages.success(request, \
'Vos informations ont été mises à jour')
else:
messages.success(request, \
'Informations du compte %s mises à jour' % account.trigramme)
return redirect('kfet.account.read', account.trigramme)
else:
messages.error(request, \
'Informations non mises à jour. Corrigez les erreurs')
else:
# No update attempt
if request.user.has_perm('kfet.is_team'):
account_form = AccountForm(instance = account)
else:
account_form = AccountRestrictForm(instance = account)
cof_form = CofRestrictForm(instance = account.cofprofile)
user_form = UserRestrictForm(instance = account.user)
return render(request, "kfet/account_update.html", {
'account' : account,
'account_form' : account_form,
'cof_form' : cof_form,
'user_form' : user_form,
})
# -----
# Checkout views
# -----
# Checkout - General
class CheckoutList(ListView):
model = Checkout
template_name = 'kfet/checkout.html'
context_object_name = 'checkouts'
# Checkout - Create
class CheckoutCreate(SuccessMessageMixin, CreateView):
model = Checkout
template_name = 'kfet/checkout_create.html'
form_class = CheckoutForm
success_message = 'Nouvelle caisse : %(name)s'
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
if not self.request.user.has_perm('add_checkout'):
raise PermissionDenied
# Creating
form.instance.created_by = self.request.user.profile.account_kfet
return super(CheckoutCreate, self).form_valid(form)
# Checkout - Read
class CheckoutRead(DetailView):
model = Checkout
template_name = 'kfet/checkout_read.html'
context_object_name = 'checkout'
# Checkout - Update
class CheckoutUpdate(SuccessMessageMixin, UpdateView):
model = Checkout
template_name = 'kfet/checkout_update.html'
form_class = CheckoutRestrictForm
success_message = 'Informations mises à jour pour la caisse : %(name)s'
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
if not self.request.user.has_perm('change_checkout'):
raise PermissionDenied
# Updating
return super(CheckoutUpdate, self).form_valid(form)
# -----
# Article views
# -----
# Article - General
class ArticleList(ListView):
model = Article
queryset = Article.objects.order_by('category', '-is_sold', 'name')
template_name = 'kfet/article.html'
context_object_name = 'articles'
# Article - Create
class ArticleCreate(SuccessMessageMixin, CreateView):
model = Article
template_name = 'kfet/article_create.html'
form_class = ArticleForm
success_message = 'Nouvel item : %(category)s - %(name)s'
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
if not self.request.user.has_perm('add_article'):
raise PermissionDenied
# Creating
return super(ArticleCreate, self).form_valid(form)
# Article - Read
class ArticleRead(DetailView):
model = Article
template_name = 'kfet/article_read.html'
context_object_name = 'article'
# Article - Update
class ArticleUpdate(UpdateView):
model = Article
template_name = 'kfet/article_update.html'
form_class = ArticleRestrictForm
success_message = "Informations mises à jour pour l'article : %(name)s"
# Surcharge de la validation
def form_valid(self, form):
# Checking permission
if not self.request.user.has_perm('change_article'):
raise PermissionDenied
# Updating
return super(ArticleUpdate, self).form_valid(form)
# -----
# K-Psul
# -----
@permission_required('kfet.is_team')
def kpsul(request):
data = {}
data['operationgroup_form'] = KPsulOperationGroupForm()
data['trigramme_form'] = KPsulAccountForm()
data['checkout_form'] = KPsulCheckoutForm()
operation_formset = KPsulOperationFormSet(queryset=Operation.objects.none())
data['operation_formset'] = operation_formset
return render(request, 'kfet/kpsul.html', data)
@permission_required('kfet.is_team')
def kpsul_account_data(request):
trigramme = request.POST.get('trigramme', '')
account = get_object_or_404(Account, trigramme=trigramme)
data = { 'pk': account.pk, 'name': account.name, 'email': account.email,
'is_cof': account.is_cof, 'promo': account.promo,
'balance': account.balance, 'is_frozen': account.is_frozen,
'departement': account.departement, 'nickname': account.nickname }
return JsonResponse(data)
@permission_required('kfet.is_team')
def kpsul_checkout_data(request):
pk = request.POST.get('pk', 0)
checkout = get_object_or_404(Checkout, pk=pk)
data = { 'pk': checkout.pk, 'name': checkout.name, 'balance': checkout.balance,
'valid_from': checkout.valid_from, 'valid_to': checkout.valid_to }
return JsonResponse(data)
@permission_required('kfet.is_team')
def kpsul_perform_operations(request):
# Initializing response data
data = defaultdict(list)
# Checking operationgroup
operationgroup_form = KPsulOperationGroupForm(request.POST)
if not operationgroup_form.is_valid():
data['errors'].append({'operation_group': list(operationgroup_form.errors)})
# Checking operation_formset
operation_formset = KPsulOperationFormSet(request.POST)
if not operation_formset.is_valid():
data['errors'].append({'operations': list(operation_formset.errors) })
# Returning BAD REQUEST if errors
if 'errors' in data:
return JsonResponse(data, status=400)
# Pre-saving (no commit)
operationgroup = operationgroup_form.save(commit = False)
operations = operation_formset.save(commit = False)
# Retrieving COF grant
cof_grant = Settings.SUBVENTION_COF()
cof_grant_divisor = 1 + cof_grant / 100
# Initializing required perms
required_perms = []
# 1. Calculating amount of each PURCHASE operations
# 2. and total amount for operation group
# 3. Adding required permissions to perform each operation
for operation in operations:
# 1
if operation.type == Operation.PURCHASE:
operation.amount = - operation.article.price * operation.article_nb
if operationgroup.on_acc.is_cof:
operation.amount = operation.amount / cof_grant_divisor
# 2
operationgroup.amount += operation.amount
# 3
if operation.type == Operation.DEPOSIT:
required_perms.append('kfet.can_perform_deposit')
# Adding required permissions to perform operation group
opegroup_perms = operationgroup.on_acc.perms_to_perform_operation(
amount = operationgroup.amount)
required_perms += opegroup_perms
# Checking authenticated user has all perms
if not request.user.has_perms(required_perms):
# Sending BAD_REQUEST with missing perms
missing_perms = \
[ Permission.objects.get(codename=codename).name for codename in (
(perm.split('.'))[1] for perm in
required_perms if not request.user.has_perm(perm)
)]
data['errors'].append({'missing_perms': missing_perms })
return JsonResponse(data, status=400)
# If 1 perm is required, saving who perform the operations
operationgroup.valid_by = request.user.profile.account_kfet
# Filling cof status for statistics
operationgroup.is_cof = operationgroup.on_acc.is_cof
# Saving operation group
operationgroup.save()
data['operationgroup'] = operationgroup.pk
# Filling operationgroup id for each operations and saving
for operation in operations:
operation.group = operationgroup
operation.save()
data['operations'].append(operation.pk)
return JsonResponse(data)