Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
6 changes: 6 additions & 0 deletions MEDIapoyo_wizard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
MEDIapoyo offers an eco-friendly, AI-powered health assistant
designed to help students manage their health proactively,
reduce illness-related anxiety, and provide first-step basic
guidance while they await a professional diagnosis.
It's a solution developed during the days of MoroccoAI innovAI Hackathon.
Note: the ML models are not integrated with the project for the moment.
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3 changes: 3 additions & 0 deletions MEDIapoyo_wizard/backend/backend/accounts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
6 changes: 6 additions & 0 deletions MEDIapoyo_wizard/backend/backend/accounts/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class AccountsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "accounts"
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.1.3 on 2024-12-01 01:20

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = []

operations = [
migrations.CreateModel(
name="CustomUser",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("username", models.CharField(max_length=150, unique=True)),
("email", models.EmailField(max_length=254, unique=True)),
("password", models.CharField(max_length=255)),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Generated by Django 5.1.3 on 2024-12-01 03:41

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("accounts", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Conversation",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=255)),
("last_message", models.TextField(blank=True, null=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
12 changes: 12 additions & 0 deletions MEDIapoyo_wizard/backend/backend/accounts/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

# accounts/models.py
from django.db import models

class CustomUser(models.Model):
# Champs pour le modèle d'utilisateur
username = models.CharField(max_length=150, unique=True)
email = models.EmailField(unique=True)
password = models.CharField(max_length=255)

def __str__(self):
return self.username
18 changes: 18 additions & 0 deletions MEDIapoyo_wizard/backend/backend/accounts/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# accounts/serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)

class Meta:
model = User
fields = ['username', 'email', 'password']

def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
email=validated_data['email'],
password=validated_data['password']
)
return user
3 changes: 3 additions & 0 deletions MEDIapoyo_wizard/backend/backend/accounts/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
13 changes: 13 additions & 0 deletions MEDIapoyo_wizard/backend/backend/accounts/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# accounts/urls.py
from django.urls import path
from .views import CreateUserView
from .views import LoginView
from .views import LogoutView
#from .views import ProtectedEndpointView

urlpatterns = [
path('create-user/', CreateUserView.as_view(), name='create-user'),
path("login/", LoginView.as_view(), name="login"),
# path("protected-endpoint/", ProtectedEndpointView.as_view(), name="protected-endpoint"),
path("logout/", LogoutView.as_view(), name="logout"),
]
100 changes: 100 additions & 0 deletions MEDIapoyo_wizard/backend/backend/accounts/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import logging
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth import authenticate
from .serializers import UserSerializer
from .models import CustomUser
from rest_framework_simplejwt.exceptions import InvalidToken

# Set up logging
logger = logging.getLogger(__name__)

class CreateUserView(APIView):
def post(self, request):
# Récupérer les données du formulaire envoyées
username = request.data.get('username')
email = request.data.get('email')

# Vérifier si l'utilisateur existe déjà
if CustomUser.objects.filter(username=username).exists():
return Response({"detail": "Username already exists"}, status=status.HTTP_400_BAD_REQUEST)

if CustomUser.objects.filter(email=email).exists():
return Response({"detail": "Email already exists"}, status=status.HTTP_400_BAD_REQUEST)

# Si l'utilisateur n'existe pas, on continue avec la création
serializer = UserSerializer(data=request.data)

if serializer.is_valid(): # Si les données sont valides
serializer.save()
return Response({"detail": "User created successfully"}, status=status.HTTP_201_CREATED)

# Si les données sont invalides, on renvoie les erreurs
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class LoginView(APIView):
def post(self, request):
# Récupérer les données du formulaire
username = request.data.get("username")
password = request.data.get("password")

# Vérifier si les données sont présentes
if not username or not password:
return Response(
{"detail": "Username and password are required."},
status=status.HTTP_400_BAD_REQUEST,
)

# Authentifier l'utilisateur
user = authenticate(username=username, password=password)

if user is not None:
# Créer un jeton JWT
refresh = RefreshToken.for_user(user)
access_token = str(refresh.access_token)

return Response(
{
"access_token": access_token,
"refresh_token": str(refresh),
},
status=status.HTTP_200_OK,
)
else:
return Response(
{"detail": "Invalid credentials"},
status=status.HTTP_401_UNAUTHORIZED,
)


class LogoutView(APIView):
permission_classes = [IsAuthenticated]

def post(self, request):
auth_header = request.headers.get('Authorization')
if not auth_header:
logger.error("Pas de jeton trouvé dans l'en-tête Authorization.")
return Response({"detail": "Jeton manquant."}, status=status.HTTP_400_BAD_REQUEST)

try:
# Extraire le jeton Bearer
token = auth_header.split(' ')[1]
refresh_token = RefreshToken(token)

# Blacklister le jeton
refresh_token.blacklist()

# Répondre à la déconnexion
return Response({"detail": "Déconnexion réussie."}, status=status.HTTP_200_OK)
except InvalidToken:
# Si le jeton est invalide
logger.error("Jeton invalide lors de la tentative de déconnexion.")
return Response({"detail": "Jeton invalide."}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
# Gérer toute autre exception
logger.error(f"Erreur lors de la déconnexion: {str(e)}")
return Response({"detail": str(e)}, status=status.HTTP_400_BAD_REQUEST)
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
16 changes: 16 additions & 0 deletions MEDIapoyo_wizard/backend/backend/backend/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for backend project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")

application = get_asgi_application()
Loading