Skip to content

Commit 119886d

Browse files
authored
Merge pull request #9 from Decibels-UTC/back
Back
2 parents 93779ed + 40eea74 commit 119886d

35 files changed

+2074
-27
lines changed

.idea/misc.xml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 5.0.1 on 2024-02-04 11:46
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('app', '0001_initial'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='item',
15+
name='type',
16+
field=models.CharField(choices=[('light', 'Light'), ('son', 'Son'), ('structure', 'Structure'), ('autre', 'Autre')], default='autre', max_length=20),
17+
preserve_default=False,
18+
),
19+
]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 5.0.1 on 2024-02-04 14:55
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('app', '0002_item_type'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='item',
16+
name='price',
17+
field=models.FloatField(validators=[django.core.validators.MinValueValidator(0)]),
18+
),
19+
]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.0.1 on 2024-02-04 18:40
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('app', '0003_alter_item_price'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='item',
15+
name='state',
16+
field=models.CharField(choices=[('neuf', 'Neuf'), ('use', 'Usé'), ('reparable', 'Réparable'), ('casse', 'Cassé')], default='neuf', max_length=20),
17+
),
18+
]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 5.0.1 on 2024-02-05 00:40
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('app', '0004_item_state'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='item',
16+
name='power',
17+
field=models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)]),
18+
),
19+
]

backend/app/models.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,51 @@
11
from django.db import models
22
from django.core.validators import MaxValueValidator, MinValueValidator
33

4+
45
# Create your models here.
56
class Item(models.Model):
7+
TYPES_CHOICES1 = [
8+
('light', 'Light'),
9+
('son', 'Son'),
10+
('structure', 'Structure'),
11+
('autre', 'Autre'),
12+
]
13+
TYPES_CHOICES2 = [
14+
('neuf', 'Neuf'),
15+
('use', 'Usé'),
16+
('reparable', 'Réparable'),
17+
('casse', 'Cassé'),
18+
]
619
id = models.AutoField(primary_key=True)
720
name = models.CharField(max_length = 150)
821
brand = models.CharField(max_length = 150, null=True, blank=True)
9-
price = models.IntegerField(validators=[MinValueValidator(0)])
22+
price = models.FloatField(validators=[MinValueValidator(0)])
23+
state = models.CharField(max_length=20, choices=TYPES_CHOICES2, default='neuf')
24+
power = models.IntegerField(validators=[MinValueValidator(0)],default=0)
1025
quantity = models.IntegerField(validators=[MinValueValidator(0)])
1126
modification_reason = models.CharField(max_length = 500, null=True, blank=True)
27+
type = models.CharField(max_length=20, choices=TYPES_CHOICES1)
1228
creation = models.DateTimeField(auto_now=True)
1329
removed = models.DateTimeField(null=True, blank=True)
1430
modification_date = models.DateTimeField(auto_now=True)
1531

32+
33+
34+
35+
36+
37+
38+
39+
40+
41+
42+
43+
44+
45+
46+
47+
48+
49+
50+
1651

backend/app/serializer.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,39 @@
11
from rest_framework import serializers
22
from . models import *
3+
from django.contrib.auth import get_user_model, authenticate
34

45
class ItemSerializer(serializers.ModelSerializer):
56
class Meta:
67
model = Item
7-
fields = ['id','name' , 'brand', 'price', 'quantity', 'modification_reason', 'creation', 'removed', 'modification_date']
8+
fields = ['id','name' , 'brand','state', 'price','type', 'quantity', 'modification_reason', 'creation', 'removed', 'modification_date']
9+
10+
11+
class LoginSerializer(serializers.Serializer):
12+
username = serializers.CharField(label="Username", write_only=True)
13+
password = serializers.CharField(
14+
label="Password",
15+
style={'input_type': 'password'},
16+
trim_whitespace=False,
17+
write_only=True
18+
)
19+
20+
def validate(self, attrs):
21+
username = attrs.get('username')
22+
password = attrs.get('password')
23+
24+
if username and password:
25+
user = authenticate(request=self.context.get('request'), username=username, password=password)
26+
if not user:
27+
msg = 'Access denied: wrong username or password.'
28+
raise serializers.ValidationError(msg, code='authorization')
29+
attrs['user'] = user
30+
else:
31+
msg = 'Both "username" and "password" are required.'
32+
raise serializers.ValidationError(msg, code='authorization')
33+
34+
return attrs
35+
36+
37+
838

939

backend/app/views.py

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
from django.shortcuts import render
22
from rest_framework.views import APIView
33
from . models import *
4+
from django.shortcuts import get_object_or_404
45
from . serializer import *
56
from rest_framework.response import Response
7+
from rest_framework import status
8+
from datetime import datetime, timezone
9+
from django.contrib.auth import get_user_model, login, logout
10+
from rest_framework.authentication import SessionAuthentication
11+
from rest_framework import permissions, status
12+
from rest_framework.authtoken.models import Token
13+
from rest_framework.permissions import IsAuthenticated
14+
from django.contrib.auth.models import User
15+
from datetime import timedelta
16+
17+
18+
19+
620

721
# Create your views here.
822

@@ -14,11 +28,15 @@ def get(self, request):
1428
"name" : output.name,
1529
"brand" : output.brand,
1630
"price" : output.price,
31+
"power" : output.power,
32+
"type": output.type,
33+
"state": output.state,
1734
"quantity" : output.quantity,
1835
"modification_reason" : output.modification_reason,
1936
"creation" : output.creation,
2037
"removed" : output.removed,
21-
"modification_date" : output.modification_date}
38+
"modification_date" : output.modification_date,
39+
}
2240
for output in Item.objects.all()
2341
]
2442

@@ -30,8 +48,85 @@ def post(self, request):
3048
serializer.save()
3149
return Response(serializer.data)
3250

33-
def update(self, request):
34-
serializer = ItemSerializer(data=request.data)
35-
if serializer.is_valid(raise_exception=True):
36-
serializer.save()
37-
return Response(serializer.data)
51+
def put(self, request, pk):
52+
try:
53+
item = Item.objects.get(pk=pk)
54+
except Item.DoesNotExist:
55+
return Response({"error": "Item not found"}, status=status.HTTP_404_NOT_FOUND)
56+
57+
if(item.name != None):
58+
item.name = request.data.get("name", item.name)
59+
if (item.brand != None):
60+
item.brand = request.data.get("brand", item.brand)
61+
if (item.price != None):
62+
item.price = request.data.get("price", item.price)
63+
if (item.type != None):
64+
item.type = request.data.get("type", item.type)
65+
if (item.quantity != None):
66+
item.quantity = request.data.get("quantity", item.quantity)
67+
if(item.quantity == 0):
68+
item.removed = datetime.now(timezone.utc);
69+
if (item.modification_reason != None):
70+
item.modification_reason = request.data.get("modification_reason", item.modification_reason)
71+
if item.modification_reason == "item deleted":
72+
item.removed = datetime.now(timezone.utc);
73+
if (item.state != None):
74+
item.state = request.data.get("state", item.state)
75+
if (item.power != None):
76+
item.power = request.data.get("power", item.power)
77+
78+
item.save()
79+
80+
return Response({
81+
"id":item.id,
82+
"name" : item.name,
83+
"brand" : item.brand,
84+
"price" : item.price,
85+
"power" : item.power,
86+
"type": item.type,
87+
"state": item.state,
88+
"quantity" : item.quantity,
89+
"modification_reason" : item.modification_reason,
90+
"creation" : item.creation,
91+
"removed" : item.removed,
92+
"modification_date" : item.modification_date}
93+
)
94+
95+
96+
97+
98+
class LoginView(APIView):
99+
permission_classes = (permissions.AllowAny,)
100+
101+
def post(self, request, format=None):
102+
serializer = LoginSerializer(data=self.request.data, context={'request': self.request})
103+
serializer.is_valid(raise_exception=True)
104+
user = serializer.validated_data['user']
105+
login(request, user)
106+
107+
# Générer un token pour l'utilisateur authentifié
108+
token, created = Token.objects.get_or_create(user=user)
109+
110+
# Définir une date d'expiration pour le token
111+
expiry_duration = timedelta(minutes=30) # Le token expire après 30 minutes
112+
token.expires = datetime.now() + expiry_duration
113+
token.save()
114+
115+
# Renvoyer le token dans la réponse
116+
return Response({'token': token.key}, status=status.HTTP_200_OK)
117+
118+
class LogoutView(APIView):
119+
def post(self, request, format=None):
120+
if request.user.is_authenticated:
121+
request.user.auth_token.delete()
122+
return Response(status=status.HTTP_200_OK)
123+
124+
class VerifyTokenView(APIView):
125+
def get(self, request):
126+
token = request.META.get('HTTP_AUTHORIZATION', '')[6:] # Retirez 'Token ' du début
127+
try:
128+
token_obj = Token.objects.get(key=token)
129+
user = User.objects.get(id=token_obj.user_id)
130+
return Response({'user': user.username})
131+
except Token.DoesNotExist:
132+
return Response({'error': 'Token does not exist'}, status=401)

backend/backend/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
'app',
4141
'rest_framework',
4242
'corsheaders',
43+
'rest_framework.authtoken',
4344
]
4445

4546
MIDDLEWARE = [

backend/backend/urls.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,9 @@
2020

2121
urlpatterns = [
2222
# path('youwillneverfindme/', admin.site.urls),
23-
path('', ItemView.as_view(), name="Main")
23+
path('', ItemView.as_view(), name="Main"),
24+
path('items/<int:pk>/', ItemView.as_view(), name='item-update'),
25+
path('login/', LoginView.as_view(), name='login'),
26+
path('logout/', LogoutView.as_view(), name='logout'),
27+
path('verify-token/', VerifyTokenView.as_view(), name='verify-token'),
2428
]

backend/db.sqlite3

28 KB
Binary file not shown.

0 commit comments

Comments
 (0)