Commit ffe53034 authored by Jean-samuel TETTEKPOE's avatar Jean-samuel TETTEKPOE
Browse files

Format code (with Black)

parent 7de554c6
Pipeline #9147 passed with stage
in 40 seconds
......@@ -29,39 +29,42 @@ class BugReport(models.Model):
class BugReportSerializer(serializers.ModelSerializer):
class Meta:
model = BugReport
fields = '__all__'
fields = "__all__"
_type = VirtualField("BugReport")
bar = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CreateOnlyDefault(CurrentBarDefault()))
author = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CreateOnlyDefault(serializers.CurrentUserDefault()))
bar = serializers.PrimaryKeyRelatedField(
read_only=True, default=serializers.CreateOnlyDefault(CurrentBarDefault())
)
author = serializers.PrimaryKeyRelatedField(
read_only=True,
default=serializers.CreateOnlyDefault(serializers.CurrentUserDefault()),
)
def create(self, data):
if 'author' not in data:
data['author'] = self.context['request'].user
if 'bar' not in data:
data['bar'] = self.context['request'].bar
if "author" not in data:
data["author"] = self.context["request"].user
if "bar" not in data:
data["bar"] = self.context["request"].bar
b = super(BugReportSerializer, self).create(data)
if settings.SLACK_HOOK:
proxies = settings.PROXIES
payload = {
"attachments": [
{
"fallback": "Un bug a été reporté par _%s_ dans le bar _%s_" % (b.author.get_full_name(), b.bar.name),
"text": "Un bug a été reporté par *%s* dans le bar *%s*" % (b.author.get_full_name(), b.bar.name),
"fallback": "Un bug a été reporté par _%s_ dans le bar _%s_"
% (b.author.get_full_name(), b.bar.name),
"text": "Un bug a été reporté par *%s* dans le bar *%s*"
% (b.author.get_full_name(), b.bar.name),
"color": "#D00000",
"fields": [
{
"title": "Message",
"value": b.message,
"short": False
},
{"title": "Message", "value": b.message, "short": False},
{
"title": "Contexte",
"value": "```%s```" % b.data,
"short": False
}
"short": False,
},
],
"mrkdwn_in": ["pretext", "text", "fields"]
"mrkdwn_in": ["pretext", "text", "fields"],
}
]
}
......@@ -69,13 +72,30 @@ class BugReportSerializer(serializers.ModelSerializer):
requests.post(url_slack, json=payload, proxies=proxies)
if settings.IRC_HOOK:
lines = []
lines.append("Un bug a été reporté par %c03%c%s%c%c dans le bar %c05%c%s%c%c" % (chr(3), chr(2), b.author.get_full_name(), chr(2), chr(3), chr(3), chr(2), b.bar.name, chr(2), chr(3)))
lines.append(
"Un bug a été reporté par %c03%c%s%c%c dans le bar %c05%c%s%c%c"
% (
chr(3),
chr(2),
b.author.get_full_name(),
chr(2),
chr(3),
chr(3),
chr(2),
b.bar.name,
chr(2),
chr(3),
)
)
lines.append("%c02%cMessage: %c%c" % (chr(3), chr(2), chr(2), chr(3)))
lines.append(b.message)
lines.append("%c02%cContexte: %c%c"% (chr(3), chr(2), chr(2), chr(3)))
lines.append("%c02%cContexte: %c%c" % (chr(3), chr(2), chr(2), chr(3)))
lines.append("%s" % b.data)
for line in lines:
requests.post(settings.IRC_HOOK_URL, data = {'key': settings.IRC_HOOK_KEY, 'message': line})
requests.post(
settings.IRC_HOOK_URL,
data={"key": settings.IRC_HOOK_KEY, "message": line},
)
return b
......@@ -84,7 +104,5 @@ class BugReportViewSet(viewsets.ModelViewSet):
queryset = BugReport.objects.all()
serializer_class = BugReportSerializer
permission_classes = (PerBarPermissionsOrAnonReadOnly,)
filter_fields = {
'bar': ['exact'],
'author': ['exact']}
search_fields = ('message', 'data')
filter_fields = {"bar": ["exact"], "author": ["exact"]}
search_fields = ("message", "data")
......@@ -7,36 +7,43 @@ from bars_bugtracker.models import BugReport
import json
class BugreportTests(APITestCase):
@classmethod
def setUpClass(self):
super(BugreportTests, self).setUpClass()
self.bar, _ = Bar.objects.get_or_create(id='natationjone')
self.user, _ = User.objects.get_or_create(username='bob')
self.bar, _ = Bar.objects.get_or_create(id="natationjone")
self.user, _ = User.objects.get_or_create(username="bob")
self.create_data = {'message': 'test', 'data': 'error'}
self.create_data = {"message": "test", "data": "error"}
def test_create_bugreport(self):
# Unauthenticated
response = self.client.post('/bugreport/?bar=natationjone', self.create_data)
response = self.client.post("/bugreport/?bar=natationjone", self.create_data)
self.assertEqual(response.status_code, 401)
def test_create_bugreport1(self):
# Wrong permissions
with patch.object(User, 'has_perm', return_value=False):
with patch.object(User, "has_perm", return_value=False):
self.client.force_authenticate(user=self.user)
response = self.client.post('/bugreport/?bar=natationjone', self.create_data)
response = self.client.post(
"/bugreport/?bar=natationjone", self.create_data
)
self.assertEqual(response.status_code, 403)
def test_create_bugreport2(self):
# Correct permissions
with patch.object(User, 'has_perm', return_value=True) as m:
with patch.object(User, "has_perm", return_value=True) as m:
self.client.force_authenticate(user=self.user)
response = self.client.post('/bugreport/?bar=natationjone', json.dumps(self.create_data), content_type="application/json")
response = self.client.post(
"/bugreport/?bar=natationjone",
json.dumps(self.create_data),
content_type="application/json",
)
self.assertEqual(response.status_code, 201)
self.assertEqual(m.call_args[0][0], 'bars_bugtracker.add_bugreport')
bugreport = BugReport.objects.get(id=response.data.get('id'))
self.assertEqual(m.call_args[0][0], "bars_bugtracker.add_bugreport")
bugreport = BugReport.objects.get(id=response.data.get("id"))
self.assertEqual(bugreport.bar, self.bar)
self.assertEqual(bugreport.author, self.user)
self.assertEqual(bugreport.message, self.create_data.get('message'))
self.assertEqual(bugreport.message, self.create_data.get("message"))
......@@ -10,80 +10,121 @@ from bars_core.models.role import Role
from bars_core.models.account import Account
from bars_core.models.loginattempt import LoginAttempt
class BarForm(ActionForm):
bar = forms.ModelChoiceField(queryset=Bar.objects.all())
class UserAdmin(admin.ModelAdmin):
list_display = ('username', 'firstname', 'lastname', 'email', 'pseudo')
list_filter = ('account__bar',)
ordering = ('pseudo', )
search_fields = ('lastname', 'firstname')
list_display = ("username", "firstname", "lastname", "email", "pseudo")
list_filter = ("account__bar",)
ordering = ("pseudo",)
search_fields = ("lastname", "firstname")
exclude = None
actions = ['admin', 'treso', 'respo_appro', 'respo_facho', 'respo_news', 'respo_inventaire']
actions = [
"admin",
"treso",
"respo_appro",
"respo_facho",
"respo_news",
"respo_inventaire",
]
action_form = BarForm
def admin(self, request, queryset):
for user in queryset:
bar = request.POST.get('bar')
bar = request.POST.get("bar")
Role.objects.create(name="admin", bar=Bar.objects.get(id=bar), user=user)
Role.objects.create(name="staff", bar=Bar.objects.get(id="root"), user=user)
admin.short_description = "Donner les droits de respo bar"
def treso(self, request, queryset):
for user in queryset:
bar = request.POST.get('bar')
Role.objects.create(name="treasurer", bar=Bar.objects.get(id=bar), user=user)
bar = request.POST.get("bar")
Role.objects.create(
name="treasurer", bar=Bar.objects.get(id=bar), user=user
)
treso.short_description = "Donner les droits de trésorier"
def respo_appro(self, request, queryset):
for user in queryset:
bar = request.POST.get('bar')
Role.objects.create(name="appromanager", bar=Bar.objects.get(id=bar), user=user)
Role.objects.create(name="itemcreator", bar=Bar.objects.get(id="root"), user=user)
bar = request.POST.get("bar")
Role.objects.create(
name="appromanager", bar=Bar.objects.get(id=bar), user=user
)
Role.objects.create(
name="itemcreator", bar=Bar.objects.get(id="root"), user=user
)
respo_appro.short_description = "Donner les droits de respo appro"
def respo_facho(self, request, queryset):
for user in queryset:
bar = request.POST.get('bar')
Role.objects.create(name="policeman", bar=Bar.objects.get(id=bar), user=user)
bar = request.POST.get("bar")
Role.objects.create(
name="policeman", bar=Bar.objects.get(id=bar), user=user
)
respo_facho.short_description = "Donner les droits de respo facho"
def respo_news(self, request, queryset):
for user in queryset:
bar = request.POST.get('bar')
Role.objects.create(name="newsmanager", bar=Bar.objects.get(id=bar), user=user)
bar = request.POST.get("bar")
Role.objects.create(
name="newsmanager", bar=Bar.objects.get(id=bar), user=user
)
respo_news.short_description = "Donner les droits de respo news"
def respo_inventaire(self, request, queryset):
for user in queryset:
bar = request.POST.get('bar')
Role.objects.create(name="inventorymanager", bar=Bar.objects.get(id=bar), user=user)
bar = request.POST.get("bar")
Role.objects.create(
name="inventorymanager", bar=Bar.objects.get(id=bar), user=user
)
respo_inventaire.short_description = "Donner les droits de respo inventaire"
class RoleAdmin(admin.ModelAdmin):
list_display = ('user', 'bar', 'name')
ordering = ('bar', 'user', 'name')
list_filter = ('bar', 'name', )
search_fields = ('user__username', 'user__firstname' )
exclude = None
list_display = ("user", "bar", "name")
ordering = ("bar", "user", "name")
list_filter = (
"bar",
"name",
)
search_fields = ("user__username", "user__firstname")
exclude = None
class AccountAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'owner', 'owner_firstname', 'owner_lastname', 'bar', 'money')
ordering = ('bar', )
list_filter = ('bar', )
search_fields = ('owner__lastname', 'owner__firstname', 'owner__username' )
list_display = (
"__unicode__",
"owner",
"owner_firstname",
"owner_lastname",
"bar",
"money",
)
ordering = ("bar",)
list_filter = ("bar",)
search_fields = ("owner__lastname", "owner__firstname", "owner__username")
exclude = None
def owner_firstname(self, obj):
return obj.owner.firstname
owner_firstname.short_description = 'Owner firstname'
owner_firstname.admin_order_field = 'owner__firstname'
owner_firstname.short_description = "Owner firstname"
owner_firstname.admin_order_field = "owner__firstname"
def owner_lastname(self, obj):
return obj.owner.lastname
owner_lastname.short_description = 'Owner lastname'
owner_lastname.admin_order_field = 'owner__lastname'
owner_lastname.short_description = "Owner lastname"
owner_lastname.admin_order_field = "owner__lastname"
admin.site.unregister(Group)
admin.site.register(User, UserAdmin)
......
......@@ -3,6 +3,7 @@ from django.utils import timezone
from bars_core.models.user import User
from django.contrib.auth.backends import BaseBackend
class AuthenticationBackend(BaseBackend):
def authenticate(self, request, username=None, password=None):
if username is None or password is None:
......@@ -23,16 +24,19 @@ class AuthenticationBackend(BaseBackend):
except User.DoesNotExist:
return None
from rest_framework_jwt.views import ObtainJSONWebToken
from bars_django.utils import get_client_ip
from bars_core.models.loginattempt import LoginAttempt
class ObtainJSONWebTokenWrapper(ObtainJSONWebToken):
def post(self, request):
response = super(ObtainJSONWebTokenWrapper, self).post(request)
ip = get_client_ip(request)
success = response.status_code != 400
sent_username = request.data.get('username')
sent_username = request.data.get("username")
try:
user = User.objects.get(username=sent_username)
user.previous_login = user.current_login
......@@ -40,6 +44,8 @@ class ObtainJSONWebTokenWrapper(ObtainJSONWebToken):
user.save()
except User.DoesNotExist:
user = None
LoginAttempt.objects.create(user=user, success=success, ip=ip, sent_username=sent_username)
LoginAttempt.objects.create(
user=user, success=success, ip=ip, sent_username=sent_username
)
return response
......@@ -17,13 +17,16 @@ from bars_core.perms import PerBarPermissionsOrAnonReadOnly, BarRolePermissionLo
class Account(models.Model):
class Meta:
unique_together = ("bar", "owner")
index_together = ["bar", "owner"] # Redundant ?
app_label = 'bars_core'
index_together = ["bar", "owner"] # Redundant ?
app_label = "bars_core"
bar = models.ForeignKey(Bar, on_delete=models.CASCADE)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
money = models.FloatField(default=0)
overdrawn_since = models.DateField(null=True) # set to date value when money becomes negative
overdrawn_since = models.DateField(
null=True
) # set to date value when money becomes negative
deleted = models.BooleanField(default=False)
last_modified = models.DateTimeField(auto_now=True)
......@@ -32,22 +35,24 @@ class Account(models.Model):
def save(self, *args, **kwargs):
if not self.pk:
Role.objects.get_or_create(name='customer', bar=self.bar, user=self.owner)
Role.objects.get_or_create(name="customer", bar=self.bar, user=self.owner)
super().save(*args, **kwargs)
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = '__all__'
read_only_fields = ('bar', 'money', 'overdrawn_since', 'last_modified')
fields = "__all__"
read_only_fields = ("bar", "money", "overdrawn_since", "last_modified")
_type = VirtualField("Account")
bar = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CreateOnlyDefault(CurrentBarDefault()))
bar = serializers.PrimaryKeyRelatedField(
read_only=True, default=serializers.CreateOnlyDefault(CurrentBarDefault())
)
def create(self, data):
if 'bar' not in data:
data['bar'] = self.context['request'].bar
if "bar" not in data:
data["bar"] = self.context["request"].bar
return super(AccountSerializer, self).create(data)
......@@ -56,12 +61,13 @@ class AccountViewSet(viewsets.ModelViewSet):
serializer_class = AccountSerializer
permission_classes = (PerBarPermissionsOrAnonReadOnly,)
filter_fields = {
'owner': ['exact'],
'owner__username': ['exact'],
'bar': ['exact'],
'money': ['lte', 'gte']}
"owner": ["exact"],
"owner__username": ["exact"],
"bar": ["exact"],
"money": ["lte", "gte"],
}
@action(methods=['get'], detail=False)
@action(methods=["get"], detail=False)
def me(self, request):
"""
Return the account of current user in current bar, if specified, or all accounts of current user otherwise.
......@@ -74,7 +80,9 @@ class AccountViewSet(viewsets.ModelViewSet):
"""
bar = request.bar
if bar is None:
serializer = self.serializer_class(request.user.account_set.all(), many=True)
serializer = self.serializer_class(
request.user.account_set.all(), many=True
)
else:
serializer = self.serializer_class(request.user.account_set.get(bar=bar))
return Response(serializer.data)
......@@ -110,8 +118,9 @@ class AccountViewSet(viewsets.ModelViewSet):
paramType: query
"""
from bars_stats.utils import compute_transaction_stats
f = lambda qs: qs.filter(accountoperation__target=pk)
aggregate = models.Sum('accountoperation__delta')
aggregate = models.Sum("accountoperation__delta")
stats = compute_transaction_stats(request, f, aggregate)
return Response(stats, 200)
......@@ -143,12 +152,13 @@ class AccountViewSet(viewsets.ModelViewSet):
paramType: query
"""
from bars_stats.utils import compute_total_spent
f = lambda qs: qs.filter(accountoperation__target=pk)
stats = compute_total_spent(request, f)
return Response(stats, 200)
@action(methods=['get'], detail=False)
@action(methods=["get"], detail=False)
def ranking(self, request):
"""
Return a ranking of all accounts in the bar, according to given rules.
......@@ -175,13 +185,16 @@ class AccountViewSet(viewsets.ModelViewSet):
paramType: query
"""
from bars_stats.utils import compute_ranking
ranking = compute_ranking(request, annotate=models.Sum('accountoperation__delta'))
ranking = compute_ranking(
request, annotate=models.Sum("accountoperation__delta")
)
if ranking is None:
return Response("I can only give a ranking within a bar", 400)
else:
return Response(ranking, 200)
@action(methods=['get'], detail=False)
@action(methods=["get"], detail=False)
def coheze_ranking(self, request):
"""
Return a ranking of all accounts in the bar, according to consumption in MealTransaction and other given rules.
......@@ -205,30 +218,41 @@ class AccountViewSet(viewsets.ModelViewSet):
from django.db.models import Sum, Count, Prefetch
from bars_transactions.models import Transaction
bar = request.query_params.get('bar', None)
bar = request.query_params.get("bar", None)
t_filter = {}
if bar is None:
return Response("I can only give a ranking within a bar", 400)
else:
t_filter['bar'] = bar
t_filter["bar"] = bar
t_filter['canceled'] = False
t_filter["canceled"] = False
date_start = request.query_params.get('date_start')
date_end = request.query_params.get('date_end', datetime.now())
date_start = request.query_params.get("date_start")
date_end = request.query_params.get("date_end", datetime.now())
if date_start is not None:
t_filter['timestamp__range'] = (date_start, date_end)
t_filter["timestamp__range"] = (date_start, date_end)
t_filter['type'] = "meal"
t_filter["type"] = "meal"
# Ensure that the MealTransaction involves at least 2 accounts (to avoid cheating...)
admissible_transactions = list(Transaction.objects.filter(**t_filter).annotate(nb_accounts=Count('accountoperation__target')).filter(nb_accounts__gte=2).values('id'))
admissible_transactions = [t['id'] for t in admissible_transactions]
ranking = Account.objects.filter(bar=bar, accountoperation__transaction__id__in=admissible_transactions).values('id').annotate(val=Sum('accountoperation__delta'))
admissible_transactions = list(
Transaction.objects.filter(**t_filter)
.annotate(nb_accounts=Count("accountoperation__target"))
.filter(nb_accounts__gte=2)
.values("id")
)
admissible_transactions = [t["id"] for t in admissible_transactions]
ranking = (
Account.objects.filter(
bar=bar, accountoperation__transaction__id__in=admissible_transactions
)
.values("id")
.annotate(val=Sum("accountoperation__delta"))
)
return Response(ranking, 200)
@action(methods=['get'], detail=True)
@action(methods=["get"], detail=True)
def sellitem_ranking(self, request, pk):
"""
Return a ranking of most consumed SellItems by the account, according to given rules.
......@@ -254,10 +278,11 @@ class AccountViewSet(viewsets.ModelViewSet):
"""
from bars_items.models.sellitem import SellItem
from bars_stats.utils import compute_ranking
f = {
'stockitems__itemoperation__transaction__accountoperation__target': pk,
'stockitems__itemoperation__transaction__type__in': ("buy", "meal"),
'stockitems__deleted': False
"stockitems__itemoperation__transaction__accountoperation__target": pk,
"stockitems__itemoperation__transaction__type__in": ("buy", "meal"),
"stockitems__deleted": False,
}
# Clean request.query_params to avoid conflicts in filtering
# TODO: find a workaround
......@@ -266,14 +291,31 @@ class AccountViewSet(viewsets.ModelViewSet):
if request.bar is None:
return Response("I can only give a ranking within a bar", 400)
ann = models.Count('stockitems__itemoperation__transaction')/models.Count('stockitems', distinct=True)
ann = models.Count("stockitems__itemoperation__transaction") / models.Count(
"stockitems", distinct=True
)
# Compute ranking according to count of purchase
ranking = compute_ranking(request, model=SellItem, t_path='stockitems__itemoperation__transaction__', filter=f, annotate=ann)
ranking = compute_ranking(
request,
model=SellItem,
t_path="stockitems__itemoperation__transaction__",
filter=f,
annotate=ann,
)
# Annotate ranking with quantities
ranking = ranking.annotate(total=models.Sum(models.F('stockitems__itemoperation__delta') * models.F('stockitems__itemoperation__target__unit_factor') * models.F('stockitems__itemoperation__transaction__accountoperation__delta') / models.F('stockitems__itemoperation__transaction__moneyflow')))
ranking = ranking.annotate(
total=models.Sum(
models.F("stockitems__itemoperation__delta")
* models.F("stockitems__itemoperation__target__unit_factor")
* models.F(
"stockitems__itemoperation__transaction__accountoperation__delta"
)
/ models.F("stockitems__itemoperation__transaction__moneyflow")
)
)
return Response(ranking, 200)
@action(methods=['get'], detail=True)
@action(methods=["get"], detail=True)
def magicbar_ranking(self, request, pk):
"""
Return a ranking of preferred SellItems of the given account, weighted by recent purchases.
......@@ -293,42 +335,73 @@ class AccountViewSet(viewsets.ModelViewSet):
"""
from bars_items.models.sellitem import SellItem
from bars_stats.utils import compute_ranking
f = {
'stockitems__itemoperation__transaction__accountoperation__target': pk,
"stockitems__itemoperation__transaction__accountoperation__target": pk,
#'stockitems__itemoperation__transaction__type__in': ("buy", "meal"),
'stockitems__deleted': False
"stockitems__deleted": False,
}
ann = models.Count('stockitems__itemoperation__transaction')/models.Count('stockitems', distinct=True)
ann = models.Count("stockitems__itemoperation__transaction") / models.Count(
"stockitems", distinct=True
)