Commit 98c934e7 authored by Mathéo VERGNOLLE's avatar Mathéo VERGNOLLE
Browse files

Merge branch 'Make-ChocapiX-build-again' into 'develop'

Make ChocapiX build again

See merge request !10
parents 47512e59 8cbb3f1c
Pipeline #9440 passed with stage
in 58 seconds
......@@ -13,3 +13,4 @@ venv/
bars_django/settings/prod.py
.admin_mdp
config_ldap.py
.vscode
image: python:2.7
image: python:3.9
build:
script:
- pip install coveralls
......
language: python
python:
- "2.7"
- "3.9"
install:
- "pip install coveralls"
- "pip install -r requirements_test.txt"
......
......@@ -4,10 +4,10 @@
# API REST pour Chocapix
Ce projet est l'API REST du site des bars d'étages.
Il est conçu avec le framework web [Django 1.8](https://www.djangoproject.com/) et utilise très largement le package [Django REST Framework](http://http://www.django-rest-framework.org/).
Il est conçu avec le framework web [Django 3.2.5](https://www.djangoproject.com/) et utilise très largement le package [Django REST Framework](http://http://www.django-rest-framework.org/).
## Installation rapide
L'application requiert Python 2.7. On utilise `pip` pour la gestion des dépendances.
L'application requiert Python 3.9. On utilise `pip` pour la gestion des dépendances.
```shell
pip install -r requirements.txt
./resetdb.sh
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
......@@ -21,8 +21,8 @@ class Migration(migrations.Migration):
('data', models.TextField(blank=True)),
('timestamp', models.DateTimeField(auto_now_add=True)),
('fixed', models.BooleanField(default=False)),
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('bar', models.ForeignKey(to='bars_core.Bar')),
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
('bar', models.ForeignKey(to='bars_core.Bar', on_delete=models.CASCADE)),
],
options={
},
......
# -*- coding: utf-8 -*-
import requests
import os
from django.db import models
from django.conf import settings
from rest_framework import serializers, viewsets
from bars_django.utils import VirtualField, permission_logic, CurrentBarCreateOnlyDefault, CurrentUserCreateOnlyDefault
from bars_django.utils import VirtualField, permission_logic, CurrentBarDefault
from bars_core.perms import PerBarPermissionsOrAnonReadOnly, BarRolePermissionLogic
from bars_core.models.bar import Bar
from bars_core.models.user import User
......@@ -15,8 +14,8 @@ from bars_core.models.user import User
@permission_logic(BarRolePermissionLogic())
class BugReport(models.Model):
bar = models.ForeignKey(Bar)
author = models.ForeignKey(User)
bar = models.ForeignKey(Bar, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE)
message = models.CharField(max_length=1000)
data = models.TextField(blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
......@@ -24,40 +23,48 @@ class BugReport(models.Model):
_type = VirtualField("BugReport")
def __unicode__(self):
return "#%d by %s at %s" % (self.id, unicode(self.author), unicode(self.timestamp))
return "#%d by %s at %s" % (self.id, str(self.author), str(self.timestamp))
class BugReportSerializer(serializers.ModelSerializer):
class Meta:
model = BugReport
fields = "__all__"
_type = VirtualField("BugReport")
bar = serializers.PrimaryKeyRelatedField(read_only=True, default=CurrentBarCreateOnlyDefault())
author = serializers.PrimaryKeyRelatedField(read_only=True, default=CurrentUserCreateOnlyDefault())
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
b = super(BugReportSerializer, self).create(data)
if settings.SLACK_HOOK:
proxies = settings.PROXIES
payload = {
"attachments": [
{
"fallback": u"Un bug a été reporté par _%s_ dans le bar _%s_" % (b.author.get_full_name(), b.bar.name),
"text": u"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"],
}
]
}
......@@ -65,13 +72,30 @@ class BugReportSerializer(serializers.ModelSerializer):
requests.post(url_slack, json=payload, proxies=proxies)
if settings.IRC_HOOK:
lines = []
lines.append(u"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
......@@ -80,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")
from mock import Mock, patch
from mock import patch
from rest_framework.test import APITestCase
from bars_core.models.user import User
from bars_core.models.bar import Bar
from bars_bugtracker.models import BugReport
import json
def reload(obj):
return obj.__class__.objects.get(pk=obj.pk)
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.create_data = {'message': 'test', 'data': 'error'}
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"}
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', self.create_data)
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)
......
from django.utils import timezone
from bars_core.models.user import User
from django.contrib.auth.backends import BaseBackend
class AuthenticationBackend(object):
def authenticate(self, username=None, password=None):
class AuthenticationBackend(BaseBackend):
def authenticate(self, request, username=None, password=None):
if username is None or password is None:
return
try:
user = User.objects.get(username=username)
user = User.objects.get_by_natural_key(username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
return
def get_user(self, user_id):
try:
......@@ -17,16 +24,19 @@ class AuthenticationBackend(object):
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
......@@ -34,8 +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
obtain_jwt_token = ObtainJSONWebTokenWrapper.as_view()
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.utils.timezone
......@@ -62,8 +62,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=127, choices=[(b'customer', b'customer'), (b'moneymanager', b'moneymanager'), (b'policeman', b'policeman'), (b'admin', b'admin'), (b'inventorymanager', b'inventorymanager'), (b'appromanager', b'appromanager'), (b'newsmanager', b'newsmanager'), (b'accountmanager', b'accountmanager'), (b'staff', b'staff')])),
('last_modified', models.DateTimeField(auto_now=True)),
('bar', models.ForeignKey(to='bars_core.Bar')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('bar', models.ForeignKey(to='bars_core.Bar', on_delete=models.CASCADE)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
],
options={
},
......@@ -72,13 +72,13 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='account',
name='bar',
field=models.ForeignKey(to='bars_core.Bar'),
field=models.ForeignKey(to='bars_core.Bar', on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
model_name='account',
name='owner',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AlterUniqueTogether(
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
......@@ -19,7 +19,7 @@ class Migration(migrations.Migration):
('success', models.BooleanField()),
('sent_username', models.CharField(max_length=128)),
('ip', models.CharField(max_length=15)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)),
],
options={
},
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import datetime
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment