diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..552701230f66d6c45e1baa14bf88e4691be4e910 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +*.idx filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..eba74f4cd2e2acfb1470300d69b58d8cff458c68 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +venv/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..f1c18598963f31b7dd270b3c374489c40721536f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +# read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker +# you will also find guides on how best to write your Dockerfile + + +# Use an official Python runtime as a parent image +FROM python:3.9 + +# Set the working directory to /code +WORKDIR /code + +# Copy the current directory contents into the container at /code +COPY . /code/ + +# Install any needed packages specified in requirements.txt +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# Expose port 8000 for Django development server +# EXPOSE 8000 + +# Collect static files +# RUN python manage.py collectstatic --noinput + +# Run the Django development server +CMD ["python", "manage.py", "runserver", "0.0.0.0:7860"] + + +# FROM python:3.9 + +# WORKDIR /code + +# COPY ./requirements.txt /code/requirements.txt + +# RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# COPY . . + +# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"] \ No newline at end of file diff --git a/authentication/__init__.py b/authentication/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/authentication/__pycache__/__init__.cpython-310.pyc b/authentication/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e75835b14ec996bde798de2d47b5d5800beb0ccb Binary files /dev/null and b/authentication/__pycache__/__init__.cpython-310.pyc differ diff --git a/authentication/__pycache__/admin.cpython-310.pyc b/authentication/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37f466e39ad1ff6e762a653dad8a0653d5246828 Binary files /dev/null and b/authentication/__pycache__/admin.cpython-310.pyc differ diff --git a/authentication/__pycache__/apps.cpython-310.pyc b/authentication/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95d0a6f96cfb235c562bc5a1d124bc7cbdf9aff0 Binary files /dev/null and b/authentication/__pycache__/apps.cpython-310.pyc differ diff --git a/authentication/__pycache__/models.cpython-310.pyc b/authentication/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..380018a16ecb6d604a779ddc8afe52dd734c1d52 Binary files /dev/null and b/authentication/__pycache__/models.cpython-310.pyc differ diff --git a/authentication/__pycache__/serializers.cpython-310.pyc b/authentication/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c14fac3bd0bd66fe95be135af862ad8dec076cde Binary files /dev/null and b/authentication/__pycache__/serializers.cpython-310.pyc differ diff --git a/authentication/__pycache__/urls.cpython-310.pyc b/authentication/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..174c207a364787d583d98e35f1d9884284f25acb Binary files /dev/null and b/authentication/__pycache__/urls.cpython-310.pyc differ diff --git a/authentication/__pycache__/views.cpython-310.pyc b/authentication/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efb66fdf260ea9fc88797e3b3b4f53a7cacfffc7 Binary files /dev/null and b/authentication/__pycache__/views.cpython-310.pyc differ diff --git a/authentication/admin.py b/authentication/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..9d6769fed6bb48a983dad7bc1408aac1ff1dbee7 --- /dev/null +++ b/authentication/admin.py @@ -0,0 +1,12 @@ +from django.contrib import admin + +from authentication.models import User,UserActivationCode + +# Register your models here. +@admin.register(User,) +class UserAdmin(admin.ModelAdmin): + pass + +@admin.register(UserActivationCode) +class UserActivationCodeAdmin(admin.ModelAdmin): + pass \ No newline at end of file diff --git a/authentication/apps.py b/authentication/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..8bab8df091c23d664d4845f875475cb8752e4ea2 --- /dev/null +++ b/authentication/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AuthenticationConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'authentication' diff --git a/authentication/migrations/0001_initial.py b/authentication/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..8a152a7d3c2b246779b568829fc3f90e8c7cadf4 --- /dev/null +++ b/authentication/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.5 on 2023-09-15 21:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('email', models.EmailField(max_length=255, unique=True)), + ('first_name', models.CharField(max_length=255, null=True)), + ('last_name', models.CharField(max_length=255, null=True)), + ('image', models.FileField(max_length=250, null=True, upload_to='')), + ('is_active', models.BooleanField(default=True)), + ('staff', models.BooleanField(default=False)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/authentication/migrations/0002_useractivationcode.py b/authentication/migrations/0002_useractivationcode.py new file mode 100644 index 0000000000000000000000000000000000000000..1ff725092dfae824b39f7abee6fd1b395b8286c8 --- /dev/null +++ b/authentication/migrations/0002_useractivationcode.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.5 on 2023-09-15 21:53 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='UserActivationCode', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('activation_code', models.CharField(max_length=20, null=True)), + ('usable', models.BooleanField(default=True)), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/authentication/migrations/__init__.py b/authentication/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/authentication/migrations/__pycache__/0001_initial.cpython-310.pyc b/authentication/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..814be0687494cd4bd2e780e78ede7b8ee4d8a99f Binary files /dev/null and b/authentication/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/authentication/migrations/__pycache__/0002_useractivationcode.cpython-310.pyc b/authentication/migrations/__pycache__/0002_useractivationcode.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d049c6481cb87cfdb2115291515565c5323b8a7 Binary files /dev/null and b/authentication/migrations/__pycache__/0002_useractivationcode.cpython-310.pyc differ diff --git a/authentication/migrations/__pycache__/__init__.cpython-310.pyc b/authentication/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..03e2025fd901571c3cd9e0974de12f30a650ec79 Binary files /dev/null and b/authentication/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/authentication/models.py b/authentication/models.py new file mode 100644 index 0000000000000000000000000000000000000000..f1ea972007817afef68f1625bb8e173ffa7dd102 --- /dev/null +++ b/authentication/models.py @@ -0,0 +1,100 @@ +from django.db import models + +# Create your models here. +from django.db import models +from django.contrib.auth.models import BaseUserManager, AbstractBaseUser + + +DEFAULT_PROFILE_IMAGE_LINK = 'https://firebasestorage.googleapis.com/v0/b/deaf-traductor.appspot.com/o/profile_deaf.png?alt=media&token=d03df52d-7191-43a6-b6d2-1d6fc66c6845' + +class UserManager(BaseUserManager): + def create_user(self,email, password): + """ + Creates and saves a User with the given email and password. + """ + + if not email: + raise ValueError('Users must have email address') + + user = self.model( + email=self.normalize_email(email), + ) + + user.set_password(password) + user.save(using=self._db) + return user + + def create_staffuser(self, email, password): + """user + Creates and saves a staff user with the given email and password. + """ + user = self.create_user( + email = email, + password=password, + ) + user.staff = True + user.save(using=self._db) + return user + + def create_superuser(self, email, password): + """ + Creates and saves a superuser with the given email and password. + """ + user = self.create_user( + email = email, + password=password, + ) + user.staff = True + user.admin = True + user.is_active = True + user.save(using=self._db) + return user + +class User(AbstractBaseUser): + email = models.EmailField(max_length=255, unique=True) + first_name = models.CharField(max_length=255, null=True) + last_name = models.CharField(max_length=255, null=True) + image = models.FileField(max_length=250, null=True) + is_active = models.BooleanField(default=True) + staff = models.BooleanField(default=False) + + objects = UserManager() + + USERNAME_FIELD = 'email' + + def get_full_name(self): + return f"{self.email}" + + def get_short_name(self): + return self.email + + def __str__(self): + return self.email + + def has_perm(self, perm, obj=None): + "Does the user have a specific permission?" + # Simplest possible answer: Yes, always + return True + + def has_module_perms(self, app_label): + "Does the user have permissions to view the app `app_label`?" + # Simplest possible answer: Yes, always + return True + + @property + def is_staff(self): + "Is the user a member of staff?" + return self.staff + + @property + def is_admin(self): + "Is the user a admin member?" + return self.admin + +class UserActivationCode(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE, null=True) + activation_code = models.CharField(max_length=20, null=True) + usable = models.BooleanField(default=True) + + def __str__(self) -> str: + return self.user.email + " : " + self.activation_code diff --git a/authentication/serializers.py b/authentication/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..2178190b64838ab83b79d195103be35272f5c52d --- /dev/null +++ b/authentication/serializers.py @@ -0,0 +1,34 @@ +from djoser.serializers import UserCreateSerializer +from django.contrib.auth import get_user_model +from rest_framework_simplejwt.tokens import RefreshToken, TokenError +from rest_framework import serializers +from .utils.account_send_email import send_email_to_user +from .utils.generate_password import random_pass_generator + + +User = get_user_model() + +class UserSerializer(UserCreateSerializer): + class Meta(UserCreateSerializer.Meta): + model = User + fields = ('id', 'email', 'first_name','last_name', 'image', 'is_active', 'password',) + extra_kwargs = {'password': {'write_only': True}, 'is_active': {'read_only': True}} + depth = 1 + +class LogoutSerializer(serializers.Serializer): + refresh = serializers.CharField() + + default_error_message = { + 'bad_token': ('Token is expired or invalid') + } + + def validate(self, attrs): + self.refresh_token = attrs['refresh'] + return attrs + + def save(self, **kwargs): + + try: + RefreshToken(self.refresh_token).blacklist() + except TokenError: + self.fail('bad_token') diff --git a/authentication/tests.py b/authentication/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6 --- /dev/null +++ b/authentication/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/authentication/urls.py b/authentication/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..f5a80d695c55762f53c218073da20264dbe7753d --- /dev/null +++ b/authentication/urls.py @@ -0,0 +1,15 @@ +from django.urls import path, include, re_path +from rest_framework.routers import DefaultRouter +from authentication.views import LogoutAPIView, UserActivationView, CustomUserViewset, AccountUserViewset + +router = DefaultRouter() +router.register('auth', AccountUserViewset) + +urlpatterns = [ + # path('auth/', include('djoser.urls')), + path('', include(router.urls)), + path('auth/', include('djoser.urls.jwt')), + path('auth/logout/', LogoutAPIView.as_view(), name="logout"), + path('auth/user-me/update/', CustomUserViewset.as_view(), name='patch_user'), + path('auth/users/activation///', UserActivationView.as_view()), +] \ No newline at end of file diff --git a/authentication/utils/__pycache__/account_send_email.cpython-310.pyc b/authentication/utils/__pycache__/account_send_email.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c713b3df0fe8e5447f8c132c8534544d37a18ab Binary files /dev/null and b/authentication/utils/__pycache__/account_send_email.cpython-310.pyc differ diff --git a/authentication/utils/__pycache__/generate_password.cpython-310.pyc b/authentication/utils/__pycache__/generate_password.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..011a40be6192743926a2a7a3a61809a51d325cf9 Binary files /dev/null and b/authentication/utils/__pycache__/generate_password.cpython-310.pyc differ diff --git a/authentication/utils/account_send_email.py b/authentication/utils/account_send_email.py new file mode 100644 index 0000000000000000000000000000000000000000..a3ef2df379cc2d4372b34c3d3b2796286ae24cf9 --- /dev/null +++ b/authentication/utils/account_send_email.py @@ -0,0 +1,13 @@ +from django.core.mail import send_mail + +def send_email_to_user(subject, message, email): + """ + Sert à envoyer de mails aux utilisateurs + """ + send_mail( + f'{subject} from Deaf Traductor', + f'{message}', + 'deaftraductorapp@gmail.com', + [email], + fail_silently=False, + ) \ No newline at end of file diff --git a/authentication/utils/generate_password.py b/authentication/utils/generate_password.py new file mode 100644 index 0000000000000000000000000000000000000000..9a1fc72997039917985619a4a8629ab3afab0a61 --- /dev/null +++ b/authentication/utils/generate_password.py @@ -0,0 +1,6 @@ +import random +import string + +def random_pass_generator(length=4): + password = ''.join(random.choice(string.digits) for i in range(length)) + return password \ No newline at end of file diff --git a/authentication/views.py b/authentication/views.py new file mode 100644 index 0000000000000000000000000000000000000000..cd939aa38366e4013e31263519ee43ef67dce75e --- /dev/null +++ b/authentication/views.py @@ -0,0 +1,117 @@ +from email import message +from django.shortcuts import render +from rest_framework import generics, status, permissions +from rest_framework.response import Response +from authentication.models import User, UserActivationCode +from rest_framework.views import APIView +from djoser.views import UserViewSet +from authentication.serializers import LogoutSerializer,UserSerializer + +from .utils.account_send_email import send_email_to_user +from .utils.generate_password import random_pass_generator +from rest_framework_simplejwt.views import TokenObtainPairView + +# Create your views here. + +class AccountUserViewset(UserViewSet): + queryset = User.objects.all() + serializer_class = UserSerializer + + def perform_create(self, serializer): + user = serializer.save() + activation_code = random_pass_generator() + + user_activation_code = UserActivationCode.objects.create(user=user, activation_code=activation_code) + user_activation_code.save() + + activation_message = f"Hello dear user.\n\nYou have just created your account on lambda elearning platform and you are asked to activate your account with the following password:\n\n{activation_code}" + send_email_to_user("Account activation code", activation_message, user.email) + + # super(AccountUserViewset, self).perform_create(serializer) + # user = serializer.save() + # signals.user_registered.send( + # sender=self.__class__, user=user, request=self.request + # ) + + # context = {"user": user} + # to = [get_user_email(user)] + # if settings.SEND_ACTIVATION_EMAIL: + # settings.EMAIL.activation(self.request, context).send(to) + # elif settings.SEND_CONFIRMATION_EMAIL: + # settings.EMAIL.confirmation(self.request, context).send(to) + + + +class CustomUserViewset(generics.UpdateAPIView): + queryset = User.objects.all() + serializer_class = UserSerializer + + permission_classes = (permissions.IsAuthenticated,) + + def get_serializer_context(self): + context = super(CustomUserViewset, self).get_serializer_context() + context.update({"request": self.request}) + return context + + def patch(self, request): + data = request.data + user = request.user + print(user) + print(data) + for key, value in data.items(): + if key!='password': + setattr(user,key,value) + + print(request) + user.save() + + data = UserSerializer(user, context=self.get_serializer_context()).data + + return Response(data, status=status.HTTP_200_OK) + +class UserActivationView(APIView): + + def get_permissions(self): + """method = self.request.method + if method in ('POST', 'PUT', 'PATCH'): + return [IsAdminUser()] + else: + """ + return [] + + def get (self, request, email, activation_code): + print(email) + print(activation_code) + user = User.objects.filter(email=email).first() + if not user: + return Response({'message': "User not found"}) + + user_activation = UserActivationCode.objects.filter(user=user, usable=True).first() + if not user_activation: + return Response({'message': "User activation code not found"}) + + if user_activation.activation_code == activation_code: + user.is_active = True + user.save() + user_activation.usable=False + user_activation.save() + + activation_message = f"Hello dear user.\n\nYour account has been activated succcessfully on the Deaf Traductor application." + send_email_to_user("Account Activated", activation_message, user.email) + return Response({'message': 'Account activted successfully'}) + else: + return Response({'message':'Invalid activation code'}) + + +class LogoutAPIView(generics.GenericAPIView): + serializer_class = LogoutSerializer + + permission_classes = (permissions.IsAuthenticated,) + + def post(self, request): + + serializer = self.serializer_class(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save() + + return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..844d993f98869413851016901d2075a76e7b05dd Binary files /dev/null and b/db.sqlite3 differ diff --git a/formations/__init__.py b/formations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/formations/__pycache__/__init__.cpython-310.pyc b/formations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ce11b1b54855c4a25f039b6d8d536cd7303871e Binary files /dev/null and b/formations/__pycache__/__init__.cpython-310.pyc differ diff --git a/formations/__pycache__/admin.cpython-310.pyc b/formations/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38c457b4fcc258a2f7c770cc41e0b4421c215212 Binary files /dev/null and b/formations/__pycache__/admin.cpython-310.pyc differ diff --git a/formations/__pycache__/apps.cpython-310.pyc b/formations/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ad124cea054b251dcc203b1c75d942e3c52da4d Binary files /dev/null and b/formations/__pycache__/apps.cpython-310.pyc differ diff --git a/formations/__pycache__/models.cpython-310.pyc b/formations/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d1abc70cd52088986395a9d1b91d6e864b97f53 Binary files /dev/null and b/formations/__pycache__/models.cpython-310.pyc differ diff --git a/formations/__pycache__/serializers.cpython-310.pyc b/formations/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a495b1d2da198845a9d2fbebdafe01e9951b67f6 Binary files /dev/null and b/formations/__pycache__/serializers.cpython-310.pyc differ diff --git a/formations/__pycache__/urls.cpython-310.pyc b/formations/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f649ce751dc32302f73f4cf0278959dbc65d84bb Binary files /dev/null and b/formations/__pycache__/urls.cpython-310.pyc differ diff --git a/formations/__pycache__/views.cpython-310.pyc b/formations/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04822b3f613b6205906c1dae1aea4cb1348668fc Binary files /dev/null and b/formations/__pycache__/views.cpython-310.pyc differ diff --git a/formations/admin.py b/formations/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e --- /dev/null +++ b/formations/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/formations/apps.py b/formations/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..0d012946133651e4e153aa96af44bd6f460adb11 --- /dev/null +++ b/formations/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FormationsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'formations' diff --git a/formations/migrations/0001_initial.py b/formations/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..b0bbea3d6bae35725f9e09baf50e922faf5851e6 --- /dev/null +++ b/formations/migrations/0001_initial.py @@ -0,0 +1,125 @@ +# Generated by Django 4.2.5 on 2023-10-11 17:13 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='CategorieFormation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('titre', models.CharField(max_length=255)), + ('tag', models.CharField(max_length=255)), + ('icone', models.CharField(max_length=255)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + ), + migrations.CreateModel( + name='Formation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.CharField(max_length=1024)), + ('titre', models.CharField(max_length=255)), + ('image', models.FileField(max_length=1024, upload_to='')), + ('prerequis', models.CharField(max_length=1024)), + ('montant', models.DecimalField(decimal_places=2, default=0, max_digits=16)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('author', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ('categorie', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.categorieformation')), + ], + ), + migrations.CreateModel( + name='UserFormation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('formation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.formation')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='PanierUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('formation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.formation')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='PaiementUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('formation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.formation')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='ListSouhaitFormation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('formation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.formation')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='FavorisFormation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('formation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.formation')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Cours', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('titre', models.CharField(max_length=255)), + ('duree', models.IntegerField()), + ('video', models.FileField(max_length=1024, upload_to='')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('formation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.formation')), + ], + ), + migrations.CreateModel( + name='AvisFormation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('formation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.formation')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='ArchiveFormation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('formation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='formations.formation')), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/formations/migrations/__init__.py b/formations/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/formations/migrations/__pycache__/0001_initial.cpython-310.pyc b/formations/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d5fefe814277ac1134fbe8ce8c6e41d147edf11 Binary files /dev/null and b/formations/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/formations/migrations/__pycache__/__init__.cpython-310.pyc b/formations/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..290406434d7e513fc9a6b72c917078183e1c396b Binary files /dev/null and b/formations/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/formations/models.py b/formations/models.py new file mode 100644 index 0000000000000000000000000000000000000000..0282c3f4cca52cc37e8d7013f0dc49e936d8dd56 --- /dev/null +++ b/formations/models.py @@ -0,0 +1,88 @@ +from django.db import models + +# Create your models here. +from authentication.models import User + +class CategorieFormation(models.Model): + titre = models.CharField(max_length=255) + tag = models.CharField(max_length=255) + icone = models.CharField(max_length=255) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + + +class Formation(models.Model): + + description = models.CharField(max_length=1024) + titre = models.CharField(max_length=255) + image = models.FileField(max_length=1024) + prerequis = models.CharField(max_length=1024) + author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + montant = models.DecimalField(default=0, max_digits=16, decimal_places= 2) + categorie = models.ForeignKey(CategorieFormation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + + +class UserFormation(models.Model): + + user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + formation = models.ForeignKey(Formation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + + +class Cours(models.Model): + + titre = models.CharField(max_length=255) + duree = models.IntegerField() + video = models.FileField(max_length=1024) + formation = models.ForeignKey(Formation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + +# -------------------- + +class ArchiveFormation(models.Model): + + user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + formation = models.ForeignKey(Formation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + + +class ListSouhaitFormation(models.Model): + + user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + formation = models.ForeignKey(Formation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + +class FavorisFormation(models.Model): + + user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + formation = models.ForeignKey(Formation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + +class PanierUser(models.Model): + + user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + formation = models.ForeignKey(Formation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + +class AvisFormation(models.Model): + + user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + formation = models.ForeignKey(Formation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + +class PaiementUser(models.Model): + + user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) + formation = models.ForeignKey(Formation, on_delete=models.SET_NULL, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now = True) + diff --git a/formations/serializers.py b/formations/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..efc5104d2bec3ac685b2fb182499ef2bcbcd56ac --- /dev/null +++ b/formations/serializers.py @@ -0,0 +1,67 @@ + +from rest_framework import serializers +from django.core.exceptions import ValidationError +from .models import CategorieFormation,Formation,UserFormation,Cours,ArchiveFormation,ListSouhaitFormation,FavorisFormation, PanierUser,AvisFormation,PaiementUser + +class CategorieFormationSerializer(serializers.ModelSerializer): + + class Meta: + model = CategorieFormation + fields = ('__all__') + + +class FormationSerializer(serializers.ModelSerializer): + + class Meta: + model = Formation + fields = ('__all__') + + +class UserFormationSerializer(serializers.ModelSerializer): + + class Meta: + model = UserFormation + fields = ('__all__') + +class CoursSerializer(serializers.ModelSerializer): + + class Meta: + model = Cours + fields = ('__all__') + + +class ListSouhaitFormationSerializer(serializers.ModelSerializer): + + class Meta: + model = ListSouhaitFormation + fields = ('__all__') + +class ArchiveFormationSerializer(serializers.ModelSerializer): + + class Meta: + model = ArchiveFormation + fields = ('__all__') + +class FavorisFormationSerializer(serializers.ModelSerializer): + + class Meta: + model = FavorisFormation + fields = ('__all__') + +class PanierUserSerializer(serializers.ModelSerializer): + + class Meta: + model = PanierUser + fields = ('__all__') + +class AvisFormationSerializer(serializers.ModelSerializer): + + class Meta: + model = AvisFormation + fields = ('__all__') + +class PaiementUserSerializer(serializers.ModelSerializer): + + class Meta: + model = PaiementUser + fields = ('__all__') diff --git a/formations/tests.py b/formations/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6 --- /dev/null +++ b/formations/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/formations/urls.py b/formations/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..901d724ea639dee7de57ffa872b6328cda318177 --- /dev/null +++ b/formations/urls.py @@ -0,0 +1,23 @@ +from django.urls import path, include +from .views import * + +from rest_framework import routers + +routes = routers.DefaultRouter() + +routes.register(r'categorie_formations', CategorieFormationViews) +routes.register(r'formations',FormationViews) +routes.register(r'user_formations',UserFormationViews) +routes.register(r'cours',CoursViews) +routes.register(r'formations_archives',ArchiveFormationViews) +routes.register(r'list_souhait_formations',ListSouhaitFormationViews) +routes.register(r'favoris_formations',FavorisFormationViews) +routes.register(r'user_panier',PanierUserViews) +routes.register(r'avis_formation',AvisFormationViews) +routes.register(r'panier_user',PaiementUserViews) + + +# routes.register(r'type_roles',TypeRoleViews) +urlpatterns = [ + path('',include(routes.urls)), +] \ No newline at end of file diff --git a/formations/views.py b/formations/views.py new file mode 100644 index 0000000000000000000000000000000000000000..d9e9f3083a35e56db491455d07a6eec4a0f2eaf3 --- /dev/null +++ b/formations/views.py @@ -0,0 +1,135 @@ +from rest_framework.response import Response +from rest_framework import viewsets +from rest_framework.permissions import IsAuthenticated,AllowAny +from .models import CategorieFormation,Formation,UserFormation,Cours,ArchiveFormation,ListSouhaitFormation,FavorisFormation, PanierUser,AvisFormation,PaiementUser +from .serializers import ArchiveFormationSerializer, AvisFormationSerializer, CategorieFormationSerializer, CoursSerializer, FavorisFormationSerializer, FormationSerializer, ListSouhaitFormationSerializer, PaiementUserSerializer, PanierUserSerializer , UserFormationSerializer + + +# Create your views here. +class CategorieFormationViews(viewsets.ModelViewSet): + serializer_class = CategorieFormationSerializer + queryset = CategorieFormation.objects.all().order_by('-id') + + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(CategorieFormationViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + + +class FormationViews(viewsets.ModelViewSet): + serializer_class = FormationSerializer + queryset = Formation.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(FormationViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + + +class UserFormationViews(viewsets.ModelViewSet): + serializer_class = UserFormationSerializer + queryset = UserFormation.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(UserFormationViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + + +class CoursViews(viewsets.ModelViewSet): + serializer_class = CoursSerializer + queryset = Cours.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(CoursViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + + +class ArchiveFormationViews(viewsets.ModelViewSet): + serializer_class = ArchiveFormationSerializer + queryset = ArchiveFormation.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(ArchiveFormationViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + + +class ListSouhaitFormationViews(viewsets.ModelViewSet): + serializer_class = ListSouhaitFormationSerializer + queryset = ListSouhaitFormation.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(ListSouhaitFormationViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + + +class FavorisFormationViews(viewsets.ModelViewSet): + serializer_class = FavorisFormationSerializer + queryset = FavorisFormation.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(FavorisFormationViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + + +class PanierUserViews(viewsets.ModelViewSet): + serializer_class = PanierUserSerializer + queryset = PanierUser.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(PanierUserViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + +class AvisFormationViews(viewsets.ModelViewSet): + serializer_class = AvisFormationSerializer + queryset = AvisFormation.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(AvisFormationViews, self).get_serializer_context() + context.update({"request": self.request}) + return context + +class PaiementUserViews(viewsets.ModelViewSet): + serializer_class = PaiementUserSerializer + queryset = PaiementUser.objects.all().order_by('-id') + + def get_permissions(self): + return [AllowAny()] + + def get_serializer_context(self): + context = super(PaiementUserViews, self).get_serializer_context() + context.update({"request": self.request}) + return context diff --git a/lambdaAPI/__init__.py b/lambdaAPI/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lambdaAPI/__pycache__/__init__.cpython-310.pyc b/lambdaAPI/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fcb5f0e2a55b35e7e5285df2f6e42582c97ab236 Binary files /dev/null and b/lambdaAPI/__pycache__/__init__.cpython-310.pyc differ diff --git a/lambdaAPI/__pycache__/settings.cpython-310.pyc b/lambdaAPI/__pycache__/settings.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9135b6f1585c82c7060e9f6d68663020694d6e3b Binary files /dev/null and b/lambdaAPI/__pycache__/settings.cpython-310.pyc differ diff --git a/lambdaAPI/__pycache__/urls.cpython-310.pyc b/lambdaAPI/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f26bb61b74c5dc357e23812096b2002a57d3d9f Binary files /dev/null and b/lambdaAPI/__pycache__/urls.cpython-310.pyc differ diff --git a/lambdaAPI/__pycache__/wsgi.cpython-310.pyc b/lambdaAPI/__pycache__/wsgi.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3723547dae0409abf73ff0e754586adbbea5c3a Binary files /dev/null and b/lambdaAPI/__pycache__/wsgi.cpython-310.pyc differ diff --git a/lambdaAPI/asgi.py b/lambdaAPI/asgi.py new file mode 100644 index 0000000000000000000000000000000000000000..85772810425bd3145d8fa5cdea653fef89d3745e --- /dev/null +++ b/lambdaAPI/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for lambdaAPI 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/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lambdaAPI.settings') + +application = get_asgi_application() diff --git a/lambdaAPI/settings.py b/lambdaAPI/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..3ac30431caad9ea90caab5ebcb7187d6461e1fe1 --- /dev/null +++ b/lambdaAPI/settings.py @@ -0,0 +1,214 @@ +""" +Django settings for lambdaAPI project. + +Generated by 'django-admin startproject' using Django 4.2.5. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" +import os +from pathlib import Path +from datetime import timedelta + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-@+xrq$v0iii&b$az^pve=_d)2tf@(m6p7r$ceh2&3(2#k9y+3x' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + + # + 'drf_yasg', + 'rest_framework', + 'djoser', + 'rest_framework_simplejwt', + 'rest_framework_simplejwt.token_blacklist', + 'fairseq', + # + 'authentication', + 'translations', + 'formations', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'lambdaAPI.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'lambdaAPI.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'fr-FR' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +AUTH_USER_MODEL = 'authentication.User' + +SWAGGER_SETTINGS = { + 'USE_SESSION_AUTH': False, + 'SECURITY_DEFINITIONS': { + 'Bearer': { + 'type': 'apiKey', + 'name': 'Authorization', + 'in': 'header' + } + } +} + +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_PORT = 587 +EMAIL_HOST_USER = 'lambda.elearningplatform@gmail.com' +EMAIL_HOST_PASSWORD = 'daah zxaf tina efxk' +EMAIL_USE_TLS = True + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + ], + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ), +} + +SIMPLE_JWT = { + 'AUTH_HEADER_TYPES': 'Bearer', + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=1), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=3), #days=1, + 'ROTATE_REFRESH_TOKENS': True, + 'BLACKLIST_AFTER_ROTATION': True, + 'AUTH_TOKEN_CLASSES': ( + 'rest_framework_simplejwt.tokens.RefreshToken', + ) +} + +NAME = "Lambda" +DJOSER = { + 'LOGIN_FIELD': 'email', + 'USER_CREATE_PASSWORD_RETYPE': True, + 'USERNAME_CHANGED_EMAIL_CONFIRMATION': True, + 'PASSWORD_CHANGED_EMAIL_CONFIRMATION': True, + 'SEND_CONFIRMATION_EMAIL': True, + 'SET_USERNAME_RETYPE': True, + 'SET_PASSWORD_RETYPE': True, + 'PASSWORD_RESET_CONFIRM_URL': 'password/reset/confirm/{uid}/{token}', + 'USERNAME_RESET_CONFIRM_URL': 'email/reset/confirm/{uid}/{token}', + 'ACTIVATION_URL': 'authentication/auth/users/activation/{uid}/{token}', + 'SEND_ACTIVATION_EMAIL': True, + 'SERIALIZERS': { + 'user_create': 'authentication.serializers.UserSerializer', + 'user': 'authentication.serializers.UserSerializer', + 'current_user': 'authentication.serializers.UserSerializer', + 'user_delete': 'djoser.serializers.UserDeleteSerializer', + } +} + +# AWS_ACCESS_KEY_ID = "AKIA6HV3LEA7AYSJHZTV" +# AWS_SECRET_ACCESS_KEY = "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" +# AWS_STORAGE_BUCKET_NAME = "deafapi" +# AWS_S3_SIGNATURE_VERSION = 's3v4' +# AWS_S3_REGION_NAME = "us-east-2" +# AWS_S3_FILE_OVERWRITE = False +# AWS_DEFAULT_ACL = None +# AWS_S3_VERIFY = True +# AWS_QUERYSTRING_EXPIRE = 604800 # 1 week for the url to expire +# DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' + + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'static') +MEDIA_URL = '/media/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') diff --git a/lambdaAPI/urls.py b/lambdaAPI/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..fd9075eaa0959866e9ed1537167370884a38be7a --- /dev/null +++ b/lambdaAPI/urls.py @@ -0,0 +1,31 @@ + +from django.contrib import admin +from django.urls import include, path, re_path + +from rest_framework import permissions +from drf_yasg.views import get_schema_view +from drf_yasg import openapi + + +schema_view = get_schema_view( + openapi.Info( + title="Lambda", + default_version='v1', + description="API for lambdaAPI elearning platform", + terms_of_service="https://www.google.com/policies/terms/", + contact=openapi.Contact(email="contact@snippets.local"), + license=openapi.License(name="BSD License"), + ), + public=True, + permission_classes=[permissions.AllowAny], +) + +urlpatterns = [ + re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), + re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), + re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), + path('accounts/', include('authentication.urls')), + path('translations/', include('translations.urls')), + path('formations/', include('formations.urls')), + path('admin/', admin.site.urls), +] diff --git a/lambdaAPI/wsgi.py b/lambdaAPI/wsgi.py new file mode 100644 index 0000000000000000000000000000000000000000..fb19830e308cd049c9766d6a86e235ce840ee39b --- /dev/null +++ b/lambdaAPI/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for lambdaAPI project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lambdaAPI.settings') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000000000000000000000000000000000000..af80bd7d063be572c4a07a6fadf3ca9b9a8d49d4 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lambdaAPI.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab8f5535db9e73ba60972664871d781328644d75 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,72 @@ +antlr4-python3-runtime==4.8 +asgiref==3.7.2 +bitarray==2.9.2 +certifi==2023.7.22 +cffi==1.15.1 +charset-normalizer==3.2.0 +click==8.1.7 +colorama==0.4.6 +cryptography==41.0.3 +Cython==3.0.8 +defusedxml==0.7.1 +Django==4.2.5 +django-storages==1.14.1 +django-templated-mail==1.1.1 +djangorestframework==3.14.0 +djangorestframework-simplejwt==5.3.0 +djoser==2.2.0 +drf-yasg==1.21.7 +fairseq==0.12.2 +filelock==3.13.1 +fsspec==2023.12.2 +hydra-core==1.0.7 +idna==3.4 +inflection==0.5.1 +Jinja2==3.1.3 +joblib==1.3.2 +lxml==5.1.0 +MarkupSafe==2.1.3 +mpmath==1.3.0 +networkx==3.2.1 +numpy==1.26.3 +nvidia-cublas-cu12==12.1.3.1 +nvidia-cuda-cupti-cu12==12.1.105 +nvidia-cuda-nvrtc-cu12==12.1.105 +nvidia-cuda-runtime-cu12==12.1.105 +nvidia-cudnn-cu12==8.9.2.26 +nvidia-cufft-cu12==11.0.2.54 +nvidia-curand-cu12==10.3.2.106 +nvidia-cusolver-cu12==11.4.5.107 +nvidia-cusparse-cu12==12.1.0.106 +nvidia-nccl-cu12==2.18.1 +nvidia-nvjitlink-cu12==12.3.101 +nvidia-nvtx-cu12==12.1.105 +oauthlib==3.2.2 +omegaconf==2.0.6 +packaging==23.1 +portalocker==2.8.2 +protobuf==4.25.2 +pycparser==2.21 +PyJWT==2.8.0 +python3-openid==3.2.0 +pytz==2023.3.post1 +PyYAML==6.0.1 +regex==2023.12.25 +requests==2.31.0 +requests-oauthlib==1.3.1 +sacrebleu==2.4.0 +sacremoses==0.1.1 +social-auth-app-django==5.3.0 +social-auth-core==4.4.2 +SpeechRecognition==3.10.0 +sqlparse==0.4.4 +sympy==1.12 +tabulate==0.9.0 +tensorboardX==2.6.2.2 +torch==2.1.2 +torchaudio==2.1.2 +tqdm==4.66.1 +triton==2.1.0 +typing_extensions==4.7.1 +uritemplate==4.1.1 +urllib3==2.0.4 diff --git a/translations/__init__.py b/translations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/translations/__pycache__/__init__.cpython-310.pyc b/translations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..753fd3bb0485cc9a669f7611655a2fb7130a7e24 Binary files /dev/null and b/translations/__pycache__/__init__.cpython-310.pyc differ diff --git a/translations/__pycache__/admin.cpython-310.pyc b/translations/__pycache__/admin.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c614abb0c9d7443eb65a35f7ff5dea0bd4a637b Binary files /dev/null and b/translations/__pycache__/admin.cpython-310.pyc differ diff --git a/translations/__pycache__/apps.cpython-310.pyc b/translations/__pycache__/apps.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a9b2c771c13031fe035617cfc3d3c31fb28a3743 Binary files /dev/null and b/translations/__pycache__/apps.cpython-310.pyc differ diff --git a/translations/__pycache__/models.cpython-310.pyc b/translations/__pycache__/models.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f140c0856ce044787c0537afa5d0b6f88e27773b Binary files /dev/null and b/translations/__pycache__/models.cpython-310.pyc differ diff --git a/translations/__pycache__/serializers.cpython-310.pyc b/translations/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5770409ad959e60c474240091a3b515a001d7664 Binary files /dev/null and b/translations/__pycache__/serializers.cpython-310.pyc differ diff --git a/translations/__pycache__/urls.cpython-310.pyc b/translations/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..47cb9dfada98653b5d3fb6f519ec8f6a3a4512b4 Binary files /dev/null and b/translations/__pycache__/urls.cpython-310.pyc differ diff --git a/translations/__pycache__/views.cpython-310.pyc b/translations/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..695ce4ccf12de6ac8bfba9c54eed9e94154f1124 Binary files /dev/null and b/translations/__pycache__/views.cpython-310.pyc differ diff --git a/translations/admin.py b/translations/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..8c38f3f3dad51e4585f3984282c2a4bec5349c1e --- /dev/null +++ b/translations/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/translations/apps.py b/translations/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..cfd4a9e515906e997608697f778756f9da6f7d24 --- /dev/null +++ b/translations/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TranslationsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'translations' diff --git a/translations/management/commands/__pycache__/renameproject.cpython-310.pyc b/translations/management/commands/__pycache__/renameproject.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc0a99a7e3d5dc17e3904d246d7f3ba553cbc0dc Binary files /dev/null and b/translations/management/commands/__pycache__/renameproject.cpython-310.pyc differ diff --git a/translations/management/commands/renameproject.py b/translations/management/commands/renameproject.py new file mode 100644 index 0000000000000000000000000000000000000000..484b6d42b1e19684f64889aa1da450bbccbed57d --- /dev/null +++ b/translations/management/commands/renameproject.py @@ -0,0 +1,34 @@ +# app/management/commands/renameproject.py + +import os +import glob +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError + + +class Command(BaseCommand): + help = 'Renames the Project' + + def add_arguments(self, parser): + parser.add_argument('old', nargs='+', type=str, help="lambda") + parser.add_argument('new', nargs='+', type=str, help="lambdaAPI") + + def handle(self, *args, **options): + old = options["old"][0] + new = options["new"][0] + + base = str(settings.BASE_DIR) + projectfiles = [] + managefile = os.path.join(base, "manage.py") + projectfiles.append(managefile) + projectfiles += glob.glob(os.path.join(base, old, "*.py")) + projectfiles += glob.glob(os.path.join(base, old, "**", "*.py")) + for pythonfile in projectfiles: + with open(pythonfile, 'r') as file: + filedata = file.read() + + filedata = filedata.replace(old, new) + + with open(pythonfile, 'w') as file: + file.write(filedata) + os.rename(os.path.join(base, old), os.path.join(base, new)) \ No newline at end of file diff --git a/translations/migrations/__init__.py b/translations/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/translations/migrations/__pycache__/__init__.cpython-310.pyc b/translations/migrations/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7f9b6d26e0c0f37cb9b791846dd6da95ac2a567 Binary files /dev/null and b/translations/migrations/__pycache__/__init__.cpython-310.pyc differ diff --git a/translations/models.py b/translations/models.py new file mode 100644 index 0000000000000000000000000000000000000000..b4fcf273294bd47b80348483a5e833257310613d --- /dev/null +++ b/translations/models.py @@ -0,0 +1,5 @@ +from django.db import models + +# Create your models here. +from authentication.models import User + diff --git a/translations/serializers.py b/translations/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..09a01b399e7d1bb487f1189c9d2ef30ac4bef8da --- /dev/null +++ b/translations/serializers.py @@ -0,0 +1,12 @@ +from rest_framework import serializers + +class TextToText(serializers.Serializer): + text = serializers.CharField(max_length=1024) + sourceCode = serializers.CharField(max_length=3) + targetCode = serializers.CharField(max_length=3) + + +class AudioToAudioSerializer(serializers.Serializer): + audio = serializers.FileField() + sourceCode = serializers.CharField(max_length=3) + targetCode = serializers.CharField(max_length=3) diff --git a/translations/tests.py b/translations/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6 --- /dev/null +++ b/translations/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/translations/urls.py b/translations/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..1a20f55d362ae7c0124019dbccab9a92ad3099f6 --- /dev/null +++ b/translations/urls.py @@ -0,0 +1,13 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from .views import AudioToText, FongbeToFrancaisText + + +urlpatterns = [ + # path('', include(router.urls)), + # path('UserTranslations/', TranslationListViewSet.as_view(), name="translations"), + # path('TextToDeafSign/', TextToDeafSignViewSet.as_view(), name="text_to_deaf_sign"), + # path('AudioToDeafSign/', AudioToDeafSignViewSet.as_view(), name="audio_to_deaf_sign"), + path('AudioToText/', AudioToText.as_view(), name="audio_to_text"), + path('FongbeToFrText/', FongbeToFrancaisText.as_view(), name="fongbe_to_french_text") +] \ No newline at end of file diff --git a/translations/utils/__pycache__/utils_functions.cpython-310.pyc b/translations/utils/__pycache__/utils_functions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fb56ac9ea0c0f8a0b2220af57f846dd1778f0ae Binary files /dev/null and b/translations/utils/__pycache__/utils_functions.cpython-310.pyc differ diff --git a/translations/utils/utils_functions.py b/translations/utils/utils_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..5f32cafa58a089ccf3be931ff28313acbfea425a --- /dev/null +++ b/translations/utils/utils_functions.py @@ -0,0 +1,16 @@ +import speech_recognition as sr + +def startConvertion(path = 'ml.wav',lang = 'fr-FR'): + r = sr.Recognizer() + text = '' + with sr.AudioFile(path) as source: + print('Fetching File') + audio_text = r.listen(source) + try: + print('Converting audio transcripts into text ...') + text = r.recognize_google(audio_text, language = lang) + print(text) + except: + pass + + return text diff --git a/translations/views.py b/translations/views.py new file mode 100644 index 0000000000000000000000000000000000000000..21705d1df6babdf9c9e2d7c5f5fef878980bbe90 --- /dev/null +++ b/translations/views.py @@ -0,0 +1,73 @@ +import django +from rest_framework import viewsets, generics, mixins + +from utils.utils_function import Translator +from .serializers import TextToText,AudioToAudioSerializer +from rest_framework.permissions import IsAdminUser, IsAuthenticated,AllowAny +from rest_framework.response import Response +from rest_framework.parsers import MultiPartParser +import string +from django.core.files import File +from django.core.files.storage import default_storage +from django.core.files.base import ContentFile +import os +from lambdaAPI.settings import MEDIA_ROOT +from .utils.utils_functions import startConvertion +from django.conf import settings + +# Create your views here. + +class AudioToText(mixins.CreateModelMixin, generics.GenericAPIView): + parser_classes = (MultiPartParser,) + serializer_class = AudioToAudioSerializer + + def get_permissions(self): + return [AllowAny()] + + def post(self, request, *args, **kwargs): + data = request.FILES + user = request.user + datas = request.data + + print('*'*100) + audio_file = data['audio'] + + audio_text = startConvertion(audio_file) + + if audio_text.strip() == "": + return Response(data={'error': 'You audio file dont say anything'}, status=400) + else: + return Response(data={'text': audio_text.strip()}, status = 200) + + +class FongbeToFrancaisText(mixins.CreateModelMixin, generics.GenericAPIView): + + serializer_class = TextToText + + def get_permissions(self): + return [AllowAny()] + + def post(self, request, *args, **kwargs): + + datas = request.data + + print('*'*100) + + texte = datas['text'] + sourceCode = datas['sourceCode'] + + isFon : bool = True + if sourceCode == "Fr": + isFon = False + + # Création d'une instance de Translator avec le chemin vers le modèle + translator = Translator(isFon=isFon) + + # Appel de la méthode translate avec un texte à traduire + translation_result = translator.translate(texte) + + + if translation_result.strip() == "": + return Response(data={'text': 'Pas de traduction disponible'}, status=200) + else: + return Response(data={'text': translation_result.strip()}, status = 200) diff --git a/utils/__pycache__/utils_function.cpython-310.pyc b/utils/__pycache__/utils_function.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d7a158372dc99a9d047db4d8281770ec5a5b0b9 Binary files /dev/null and b/utils/__pycache__/utils_function.cpython-310.pyc differ diff --git a/utils/checkpoints/fon_fr/checkpoint_best.pt b/utils/checkpoints/fon_fr/checkpoint_best.pt new file mode 100644 index 0000000000000000000000000000000000000000..1bcc873b86f6cbfd91356b64bac09f06ca362af4 --- /dev/null +++ b/utils/checkpoints/fon_fr/checkpoint_best.pt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:465b409482118eaa87105d1582b8a7b03f2469667551fead123a24448092e745 +size 778848987 diff --git a/utils/checkpoints/fr_fon/checkpoint_best.pt b/utils/checkpoints/fr_fon/checkpoint_best.pt new file mode 100644 index 0000000000000000000000000000000000000000..b826c8004b4a9a2c5b685904740adaf5884390cf --- /dev/null +++ b/utils/checkpoints/fr_fon/checkpoint_best.pt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1df118cf17a79af78c4a9cf96ff2c7f6feb0235acc4f08dfc68baee72745a567 +size 781043931 diff --git a/utils/utils_function.py b/utils/utils_function.py new file mode 100644 index 0000000000000000000000000000000000000000..b75a2d00c20ae2204ce4fe2d6d5ee64b0021dab1 --- /dev/null +++ b/utils/utils_function.py @@ -0,0 +1,36 @@ +from fairseq.models.transformer import TransformerModel +import os +import torch + +class Translator: + def __init__(self, isFon:bool, device='cuda' if torch.cuda.is_available() else 'cpu'): + + # Charger le modèle pré-entraîné avec Fairseq + inner = "fon_fr" if isFon else "fr_fon" + + self.model = TransformerModel.from_pretrained( + './utils/checkpoints/fon_fr', + #utils/checkpoints/fon_fr + checkpoint_file='checkpoint_best.pt', # Nom du fichier de point de contrôle du modèle + data_name_or_path='utils/data_prepared/', # Chemin vers le dossier contenant les données du modèle + source_lang='fon', + target_lang='fr' + ) + + print("#########################") + print(type(self.model)) + print("#########################") + # Définir le périphérique sur lequel exécuter le modèle (par défaut sur 'cuda' si disponible) + self.model.to(device) + + # Mettre le modèle en mode évaluation (pas de mise à jour des poids) + self.model.eval() + + def translate(self, text): + # Encodage du texte en tokens + tokens = self.model.encode(text) + + # Décodage des tokens en traduction + translation = self.model.decode(tokens) + + return translation