Merge branch 'Aufinal/let_it_go' into 'master'

Change le fonctionnement du gel de compte

Closes #280

See merge request klub-dev-ens/gestioCOF!493
This commit is contained in:
Tom Hubrecht 2021-06-15 15:24:44 +00:00
commit 8743301105
19 changed files with 169 additions and 65 deletions

View file

@ -356,7 +356,9 @@ class TestReventeManageTest(TestCase):
def test_can_get(self):
client = Client()
client.force_login(self.user)
client.force_login(
self.user, backend="django.contrib.auth.backends.ModelBackend"
)
r = client.get(self.url)
self.assertEqual(r.status_code, 200)

View file

@ -27,7 +27,9 @@ class TestHomeView(TestCase):
def test_get(self, mock_messages):
user = User.objects.create_user(username="random_user")
give_bds_buro_permissions(user)
self.client.force_login(user)
self.client.force_login(
user, backend="django.contrib.auth.backends.ModelBackend"
)
resp = self.client.get(reverse("bds:home"))
self.assertEquals(resp.status_code, 200)
@ -44,7 +46,7 @@ class TestRegistrationView(TestCase):
self.assertRedirects(resp, login_url(next=url))
# Logged-in but unprivileged GET
client.force_login(user)
client.force_login(user, backend="django.contrib.auth.backends.ModelBackend")
resp = client.get(url)
self.assertEquals(resp.status_code, 403)
@ -64,7 +66,7 @@ class TestRegistrationView(TestCase):
self.assertRedirects(resp, login_url(next=url))
# Logged-in but unprivileged GET
client.force_login(user)
client.force_login(user, backend="django.contrib.auth.backends.ModelBackend")
resp = client.get(url)
self.assertEquals(resp.status_code, 403)

View file

@ -54,7 +54,9 @@ class CSVExportAccessTest(MessagePatch, TestCase):
def test_get(self):
client = Client()
client.force_login(self.staff)
client.force_login(
self.staff, backend="django.contrib.auth.backends.ModelBackend"
)
r = client.get(self.url)
self.assertEqual(r.status_code, 200)
@ -66,7 +68,7 @@ class CSVExportAccessTest(MessagePatch, TestCase):
def test_unauthorised(self):
client = Client()
client.force_login(self.u1)
client.force_login(self.u1, backend="django.contrib.auth.backends.ModelBackend")
r = client.get(self.url)
self.assertEqual(r.status_code, 403)
@ -86,7 +88,9 @@ class CSVExportContentTest(MessagePatch, CSVResponseMixin, TestCase):
)
self.staff = make_staff_user("staff")
self.client = Client()
self.client.force_login(self.staff)
self.client.force_login(
self.staff, backend="django.contrib.auth.backends.ModelBackend"
)
def test_simple_event(self):
self.event.subscribers.set([self.u1, self.u2])

View file

@ -111,11 +111,17 @@ CORS_ORIGIN_WHITELIST = ("bda.ens.fr", "www.bda.ens.fr" "cof.ens.fr", "www.cof.e
# Auth-related stuff
# ---
AUTHENTICATION_BACKENDS += [
"gestioncof.shared.COFCASBackend",
"kfet.auth.backends.GenericBackend",
]
AUTHENTICATION_BACKENDS = (
[
# Must be in first
"kfet.auth.backends.BlockFrozenAccountBackend"
]
+ AUTHENTICATION_BACKENDS
+ [
"gestioncof.shared.COFCASBackend",
"kfet.auth.backends.GenericBackend",
]
)
LOGIN_URL = "cof-login"
LOGIN_REDIRECT_URL = "home"

View file

@ -641,7 +641,7 @@ class ClubListViewTests(ViewTestCaseMixin, TestCase):
def test_as_staff(self):
u = self.users["staff"]
c = Client()
c.force_login(u)
c.force_login(u, backend="django.contrib.auth.backends.ModelBackend")
r = c.get(self.url)
@ -686,7 +686,7 @@ class ClubMembersViewTests(ViewTestCaseMixin, TestCase):
self.c.respos.add(u)
c = Client()
c.force_login(u)
c.force_login(u, backend="django.contrib.auth.backends.ModelBackend")
r = c.get(self.url)
self.assertEqual(r.status_code, 200)

View file

@ -1,4 +1,5 @@
from django.contrib.auth import get_user_model
from django.core.exceptions import PermissionDenied
from kfet.models import Account, GenericTeamToken
@ -37,3 +38,36 @@ class GenericBackend(BaseKFetBackend):
team_token.delete()
return get_kfet_generic_user()
class BlockFrozenAccountBackend:
def authenticate(self, request, **kwargs):
return None
def get_user(self, user_id):
return None
def has_perm(self, user_obj, perm, obj=None):
app_label, _ = perm.split(".")
if app_label == "kfet":
if (
hasattr(user_obj, "profile")
and hasattr(user_obj.profile, "account_kfet")
and user_obj.profile.account_kfet.is_frozen
):
raise PermissionDenied
# Dans le cas général, on se réfère aux autres backends
return False
def has_module_perms(self, user_obj, app_label):
if app_label == "kfet":
if (
hasattr(user_obj, "profile")
and hasattr(user_obj.profile, "account_kfet")
and user_obj.profile.account_kfet.is_frozen
):
raise PermissionDenied
# Dans le cas général, on se réfère aux autres backends
return False

View file

@ -61,7 +61,7 @@ class AccountForm(forms.ModelForm):
class Meta:
model = Account
fields = ["trigramme", "promo", "nickname", "is_frozen"]
fields = ["trigramme", "promo", "nickname"]
widgets = {"trigramme": forms.TextInput(attrs={"autocomplete": "off"})}
@ -119,6 +119,12 @@ class AccountPwdForm(forms.Form):
return self.account
class AccountFrozenForm(forms.ModelForm):
class Meta:
model = Account
fields = ["is_frozen"]
class CofForm(forms.ModelForm):
def clean_is_cof(self):
instance = getattr(self, "instance", None)

View file

@ -0,0 +1,17 @@
# Generated by Django 2.2.17 on 2021-02-23 22:51
from django.db import migrations
def unfreeze_accounts(apps, schema_editor):
Account = apps.get_model("kfet", "Account")
Account.objects.all().update(is_frozen=False)
class Migration(migrations.Migration):
dependencies = [
("kfet", "0075_remove_accountnegative_balance_offset"),
]
operations = [migrations.RunPython(unfreeze_accounts, migrations.RunPython.noop)]

View file

@ -0,0 +1,30 @@
# Generated by Django 2.2.17 on 2021-02-23 23:22
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("kfet", "0076_unfreeze_accounts"),
]
operations = [
migrations.AlterModelOptions(
name="operation",
options={
"permissions": (
("perform_deposit", "Effectuer une charge"),
(
"perform_negative_operations",
"Enregistrer des commandes en négatif",
),
("cancel_old_operations", "Annuler des commandes non récentes"),
(
"perform_commented_operations",
"Enregistrer des commandes avec commentaires",
),
)
},
),
]

View file

@ -180,9 +180,6 @@ class Account(models.Model):
return set(), False
if self.need_comment:
perms.add("kfet.perform_commented_operations")
# Checking is frozen account
if self.is_frozen:
perms.add("kfet.override_frozen_protection")
new_balance = self.balance + amount
if new_balance < 0 and amount < 0:
# Retrieving overdraft amount limit
@ -726,7 +723,6 @@ class Operation(models.Model):
permissions = (
("perform_deposit", "Effectuer une charge"),
("perform_negative_operations", "Enregistrer des commandes en négatif"),
("override_frozen_protection", "Forcer le gel d'un compte"),
("cancel_old_operations", "Annuler des commandes non récentes"),
(
"perform_commented_operations",

View file

@ -211,7 +211,7 @@ class OpenKfetConsumerTest(ChannelTestCase):
)
t.user_permissions.add(is_team)
c = WSClient()
c.force_login(t)
c.force_login(t, backend="django.contrib.auth.backends.ModelBackend")
# connect
c.send_and_consume(
@ -251,7 +251,9 @@ class OpenKfetScenarioTest(ChannelTestCase):
self.r_c.login(username="root", password="root")
# its client (for websockets)
self.r_c_ws = WSClient()
self.r_c_ws.force_login(self.r)
self.r_c_ws.force_login(
self.r, backend="django.contrib.auth.backends.ModelBackend"
)
self.kfet_open = OpenKfet(
cache_prefix="test_kfetopen_%s" % random.randrange(2 ** 20)

View file

@ -150,6 +150,12 @@ function getErrorsHtml(data) {
content += '<li>Opération invalide sur le compte ' + data['errors']['account'] + '</li>';
content += '</ul>';
}
if ('frozen' in data['errors']) {
content += 'Général';
content += '<ul>';
content += '<li>Les comptes suivants sont gelés : ' + data['errors']['frozen'].join(", ") + '</li>';
content += '</ul>';
}
return content;
}
@ -206,6 +212,17 @@ function requestAuth(data, callback, focus_next = null) {
});
}
function displayErrors(html) {
$.alert({
title: 'Erreurs',
content: html,
backgroundDismiss: true,
animation: 'top',
closeAnimation: 'bottom',
keyboardEnabled: true,
});
}
/**
* Setup jquery-confirm

View file

@ -32,6 +32,7 @@ Modification de mes informations
{% csrf_token %}
{% include 'kfet/form_snippet.html' with form=user_info_form %}
{% include 'kfet/form_snippet.html' with form=account_form %}
{% include 'kfet/form_snippet.html' with form=frozen_form %}
{% include 'kfet/form_snippet.html' with form=group_form %}
{% include 'kfet/form_snippet.html' with form=pwd_form %}
{% include 'kfet/form_snippet.html' with form=negative_form %}

View file

@ -340,21 +340,6 @@ $(document).ready(function() {
$('#id_comment').val('');
}
// -----
// Errors ajax
// -----
function displayErrors(html) {
$.alert({
title: 'Erreurs',
content: html,
backgroundDismiss: true,
animation: 'top',
closeAnimation: 'bottom',
keyboardEnabled: true,
});
}
// -----
// Perform operations
// -----

View file

@ -121,6 +121,9 @@ $(document).ready(function () {
case 403:
requestAuth(data, performTransfers);
break;
case 400:
displayErrors(getErrorsHtml(data));
break;
}
});
}

View file

@ -1926,8 +1926,7 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
["[kfet] Enregistrer des commandes avec commentaires"],
)
def test_group_on_acc_frozen(self):
user_add_perms(self.users["team"], ["kfet.override_frozen_protection"])
def test_error_on_acc_frozen(self):
self.account.is_frozen = True
self.account.save()
@ -1944,30 +1943,9 @@ class KPsulPerformOperationsViewTests(ViewTestCaseMixin, TestCase):
)
resp = self.client.post(self.url, data)
self._assertResponseOk(resp)
def test_invalid_group_on_acc_frozen_requires_perm(self):
self.account.is_frozen = True
self.account.save()
data = dict(
self.base_post_data,
**{
"comment": "A comment to explain it",
"form-TOTAL_FORMS": "1",
"form-0-type": "purchase",
"form-0-amount": "",
"form-0-article": str(self.article.pk),
"form-0-article_nb": "2",
}
)
resp = self.client.post(self.url, data)
self.assertEqual(resp.status_code, 403)
self.assertEqual(resp.status_code, 400)
json_data = json.loads(resp.content.decode("utf-8"))
self.assertEqual(
json_data["errors"]["missing_perms"], ["[kfet] Forcer le gel d'un compte"]
)
self.assertEqual(json_data["errors"]["frozen"], [self.account.trigramme])
def test_invalid_group_checkout(self):
self.checkout.valid_from -= timedelta(days=300)

View file

@ -253,7 +253,10 @@ class ViewTestCaseMixin(TestCaseMixin):
self.register_user(label, user)
if self.auth_user:
self.client.force_login(self.users[self.auth_user])
self.client.force_login(
self.users[self.auth_user],
backend="django.contrib.auth.backends.ModelBackend",
)
def tearDown(self):
del self.users_base

View file

@ -38,6 +38,7 @@ from kfet.config import kfet_config
from kfet.decorators import teamkfet_required
from kfet.forms import (
AccountForm,
AccountFrozenForm,
AccountNegativeForm,
AccountNoTriForm,
AccountPwdForm,
@ -349,10 +350,11 @@ def account_update(request, trigramme):
return HttpResponseForbidden
user_info_form = UserInfoForm(instance=account.user)
group_form = UserGroupForm(instance=account.user)
account_form = AccountForm(instance=account)
group_form = UserGroupForm(instance=account.user)
frozen_form = AccountFrozenForm(request.POST, instance=account)
pwd_form = AccountPwdForm()
if hasattr(account, "negative"):
negative_form = AccountNegativeForm(instance=account.negative)
else:
@ -362,6 +364,7 @@ def account_update(request, trigramme):
self_update = request.user == account.user
account_form = AccountForm(request.POST, instance=account)
group_form = UserGroupForm(request.POST, instance=account.user)
frozen_form = AccountFrozenForm(request.POST, instance=account)
pwd_form = AccountPwdForm(request.POST, account=account)
forms = []
@ -374,6 +377,7 @@ def account_update(request, trigramme):
if request.user.has_perm("kfet.manage_perms"):
forms.append(group_form)
forms.append(frozen_form)
elif group_form.has_changed():
warnings.append("statut d'équipe")
@ -431,6 +435,7 @@ def account_update(request, trigramme):
"user_info_form": user_info_form,
"account": account,
"account_form": account_form,
"frozen_form": frozen_form,
"group_form": group_form,
"negative_form": negative_form,
"pwd_form": pwd_form,
@ -1051,6 +1056,9 @@ def kpsul_perform_operations(request):
)
need_comment = operationgroup.on_acc.need_comment
if operationgroup.on_acc.is_frozen:
data["errors"]["frozen"] = [operationgroup.on_acc.trigramme]
# Filling data of each operations
# + operationgroup + calculating other stuffs
for operation in operations:
@ -1672,7 +1680,11 @@ def perform_transfers(request):
negative_accounts = []
# Checking if ok on all accounts
frozen = set()
for account in to_accounts_balances:
if account.is_frozen:
frozen.add(account.trigramme)
(perms, stop) = account.perms_to_perform_operation(
amount=to_accounts_balances[account]
)
@ -1681,6 +1693,10 @@ def perform_transfers(request):
if stop:
negative_accounts.append(account.trigramme)
if len(frozen):
data["errors"]["frozen"] = list(frozen)
return JsonResponse(data, status=400)
if stop_all or not request.user.has_perms(required_perms):
missing_perms = get_missing_perms(required_perms, request.user)
if missing_perms:

View file

@ -77,7 +77,9 @@ class PetitCoursInscriptionViewTestCase(ViewTestCaseMixin, TestCase):
self.subject2 = create_petitcours_subject(name="Matière 2")
def test_get_forbidden_user_not_cof(self):
self.client.force_login(self.users["user"])
self.client.force_login(
self.users["user"], backend="django.contrib.auth.backends.ModelBackend"
)
resp = self.client.get(self.url)
self.assertRedirects(resp, reverse("cof-denied"))