update
This commit is contained in:
parent
d24197b6c9
commit
7ac0b3f8ee
198 changed files with 15864 additions and 186 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Ahmed Nagi
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
151
README.md
151
README.md
|
|
@ -1,6 +1,8 @@
|
||||||
# Learning Management System (LMS) API
|
# Learning Management System (LMS) API with Vue.js
|
||||||
|
|
||||||
Welcome to the Learning Management System (LMS) API! This project is a robust and scalable backend solution built with Django and Django Rest Framework (DRF). It is designed to manage courses and their associated modules, providing a structured and secure platform for educational content delivery.
|
Welcome to the Learning Management System (LMS) API! This project is a robust, scalable backend solution built with Django and Django Rest Framework (DRF), coupled with a modern and responsive frontend using Vue.js. It is designed to manage courses and their associated modules, providing a structured and secure platform for educational content delivery.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
|
@ -9,42 +11,38 @@ Welcome to the Learning Management System (LMS) API! This project is a robust an
|
||||||
- **Authentication & Permissions**: Secure access using Token Authentication and IsAuthenticated permissions.
|
- **Authentication & Permissions**: Secure access using Token Authentication and IsAuthenticated permissions.
|
||||||
- **RESTful API Design**: Follows REST principles with hyperlinked relationships for intuitive navigation.
|
- **RESTful API Design**: Follows REST principles with hyperlinked relationships for intuitive navigation.
|
||||||
- **Custom Query Logic**: Retrieve modules filtered by course ID for efficient data access.
|
- **Custom Query Logic**: Retrieve modules filtered by course ID for efficient data access.
|
||||||
|
- **Interactive Frontend**: A Vue.js-powered frontend for seamless interaction with the backend API, including real-time updates and dynamic views.
|
||||||
|
|
||||||
## Technologies Used
|
## Technologies Used
|
||||||
|
|
||||||
- **Backend**: Django, Django Rest Framework (DRF)
|
### Backend
|
||||||
|
- **Framework**: Django, Django Rest Framework (DRF)
|
||||||
- **Authentication**: dj-rest-auth & django-alluth
|
- **Authentication**: dj-rest-auth & django-alluth
|
||||||
- **Database**: PostgreSQL
|
- **Database**: PostgreSQL
|
||||||
- **API Documentation**: Auto-generated using drf_yasg browsable API.
|
- **API Documentation**: Auto-generated using drf-spectacular browsable API.
|
||||||
|
- **Project Scaffold**: Cookiecutter Django
|
||||||
|
|
||||||
## Getting Started
|
### Frontend
|
||||||
|
- **Framework**: Vue.js 3
|
||||||
|
- **Routing**: Vue Router
|
||||||
|
- **UI Framework**: Tailwind CSS, DaisyUI
|
||||||
|
|
||||||
|
|
||||||
# Prerequisites
|
### Integration
|
||||||
|
|
||||||
- [Docker](https://docs.docker.com/docker-for-mac/install/)
|
1. **API Consumption**: Use Axios or Fetch API in Vue.js to interact with the backend API endpoints.
|
||||||
|
2. **Authentication**: Implement login and token storage using Vuex/Pinia or localStorage.
|
||||||
## Local Development
|
3. **Components**: Create reusable Vue components for courses, modules, authentication, and navigation.
|
||||||
|
4. **Routing**: Use Vue Router to manage navigation between pages like course lists, module details, and user authentication.
|
||||||
Start the dev server for local development:
|
|
||||||
```bash
|
|
||||||
docker-compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
Run a command inside the docker container:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose run --rm web [command]
|
|
||||||
```
|
|
||||||
|
|
||||||
## API Endpoints
|
## API Endpoints
|
||||||
|
This project includes a fully interactive API documentation powered by drf-spectacular, a library for generating Swagger and ReDoc documentation for Django REST Framework (DRF).
|
||||||
|
|
||||||
This project includes a fully interactive API documentation powered by drf_yasg, a library for generating Swagger and ReDoc documentation for Django REST Framework (DRF).
|
### Features
|
||||||
Features
|
|
||||||
|
|
||||||
* Interactive Swagger UI: Test API endpoints directly within the browser.
|
- **Interactive Swagger UI**: Test API endpoints directly within the browser.
|
||||||
* ReDoc Interface: Professionally styled documentation for better readabi* lity.
|
- **MkDocs Material Interface**: A clean and customizable documentation tool with a modern Material Design theme.
|
||||||
* Auto-generated: No need to write documentation manually; drf_yasg extracts t* he information from DRF views and serializers.
|
- **Auto-generated**: No need to write documentation manually; drf-spectacularyasg extracts the information from DRF views and serializers.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
@ -59,106 +57,7 @@ Contributions are welcome! If you’d like to contribute, please follow these st
|
||||||
|
|
||||||
This project is licensed under the MIT License. See the LICENSE file for details.
|
This project is licensed under the MIT License. See the LICENSE file for details.
|
||||||
|
|
||||||
## Acknowledgments
|
---
|
||||||
|
|
||||||
- Built with ❤️ using Django and Django Rest Framework.
|
By combining the power of Django and Vue.js, this LMS API provides a full-stack solution for managing and delivering educational content effectively. Happy coding!
|
||||||
- Inspired by the need for scalable and secure e-learning solutions.
|
|
||||||
|
|
||||||
Feel free to explore the API and contribute to its development. For any questions or feedback, please open an issue or contact the maintainers. Happy coding! 🚀
|
|
||||||
|
|
||||||
This README is clear, concise, and provides all the necessary information for users and contributors.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/cookiecutter/cookiecutter-django/)
|
|
||||||
[](https://github.com/astral-sh/ruff)
|
|
||||||
|
|
||||||
## Settings
|
|
||||||
|
|
||||||
Moved to [settings](https://cookiecutter-django.readthedocs.io/en/latest/1-getting-started/settings.html).
|
|
||||||
|
|
||||||
## Basic Commands
|
|
||||||
|
|
||||||
### Setting Up Your Users
|
|
||||||
|
|
||||||
- To create a **normal user account**, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go.
|
|
||||||
|
|
||||||
- To create a **superuser account**, use this command:
|
|
||||||
|
|
||||||
$ python manage.py createsuperuser
|
|
||||||
|
|
||||||
For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users.
|
|
||||||
|
|
||||||
### Type checks
|
|
||||||
|
|
||||||
Running type checks with mypy:
|
|
||||||
|
|
||||||
$ mypy lms
|
|
||||||
|
|
||||||
### Test coverage
|
|
||||||
|
|
||||||
To run the tests, check your test coverage, and generate an HTML coverage report:
|
|
||||||
|
|
||||||
$ coverage run -m pytest
|
|
||||||
$ coverage html
|
|
||||||
$ open htmlcov/index.html
|
|
||||||
|
|
||||||
#### Running tests with pytest
|
|
||||||
|
|
||||||
$ pytest
|
|
||||||
|
|
||||||
### Live reloading and Sass CSS compilation
|
|
||||||
|
|
||||||
Moved to [Live reloading and SASS compilation](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally.html#using-webpack-or-gulp).
|
|
||||||
|
|
||||||
### Celery
|
|
||||||
|
|
||||||
This app comes with Celery.
|
|
||||||
|
|
||||||
To run a celery worker:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd lms
|
|
||||||
celery -A config.celery_app worker -l info
|
|
||||||
```
|
|
||||||
|
|
||||||
Please note: For Celery's import magic to work, it is important _where_ the celery commands are run. If you are in the same folder with _manage.py_, you should be right.
|
|
||||||
|
|
||||||
To run [periodic tasks](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html), you'll need to start the celery beat scheduler service. You can start it as a standalone process:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd lms
|
|
||||||
celery -A config.celery_app beat
|
|
||||||
```
|
|
||||||
|
|
||||||
or you can embed the beat service inside a worker with the `-B` option (not recommended for production use):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd lms
|
|
||||||
celery -A config.celery_app worker -B -l info
|
|
||||||
```
|
|
||||||
|
|
||||||
### Email Server
|
|
||||||
|
|
||||||
In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server [Mailpit](https://github.com/axllent/mailpit) with a web interface is available as docker container.
|
|
||||||
|
|
||||||
Container mailpit will start automatically when you will run all docker containers.
|
|
||||||
Please check [cookiecutter-django Docker documentation](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally-docker.html) for more details how to start all containers.
|
|
||||||
|
|
||||||
With Mailpit running, to view messages that are sent by your application, open your browser and go to `http://127.0.0.1:8025`
|
|
||||||
|
|
||||||
### Sentry
|
|
||||||
|
|
||||||
Sentry is an error logging aggregator service. You can sign up for a free account at <https://sentry.io/signup/?code=cookiecutter> or download and host it yourself.
|
|
||||||
The system is set up with reasonable defaults, including 404 logging and integration with the WSGI application.
|
|
||||||
|
|
||||||
You must set the DSN url in production.
|
|
||||||
|
|
||||||
## Deployment
|
|
||||||
|
|
||||||
The following details how to deploy this application.
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
See detailed [cookiecutter-django Docker documentation](https://cookiecutter-django.readthedocs.io/en/latest/3-deployment/deployment-with-docker.html).
|
|
||||||
|
|
|
||||||
0
.gitattributes → backend/.gitattributes
vendored
0
.gitattributes → backend/.gitattributes
vendored
0
.gitignore → backend/.gitignore
vendored
0
.gitignore → backend/.gitignore
vendored
91
backend/README.md
Normal file
91
backend/README.md
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
[](https://github.com/cookiecutter/cookiecutter-django/)
|
||||||
|
[](https://github.com/astral-sh/ruff)
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
Moved to [settings](https://cookiecutter-django.readthedocs.io/en/latest/1-getting-started/settings.html).
|
||||||
|
|
||||||
|
## Basic Commands
|
||||||
|
|
||||||
|
### Setting Up Your Users
|
||||||
|
|
||||||
|
- To create a **normal user account**, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go.
|
||||||
|
|
||||||
|
- To create a **superuser account**, use this command:
|
||||||
|
|
||||||
|
$ python manage.py createsuperuser
|
||||||
|
|
||||||
|
For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users.
|
||||||
|
|
||||||
|
### Type checks
|
||||||
|
|
||||||
|
Running type checks with mypy:
|
||||||
|
|
||||||
|
$ mypy lms
|
||||||
|
|
||||||
|
### Test coverage
|
||||||
|
|
||||||
|
To run the tests, check your test coverage, and generate an HTML coverage report:
|
||||||
|
|
||||||
|
$ coverage run -m pytest
|
||||||
|
$ coverage html
|
||||||
|
$ open htmlcov/index.html
|
||||||
|
|
||||||
|
#### Running tests with pytest
|
||||||
|
|
||||||
|
$ pytest
|
||||||
|
|
||||||
|
### Live reloading and Sass CSS compilation
|
||||||
|
|
||||||
|
Moved to [Live reloading and SASS compilation](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally.html#using-webpack-or-gulp).
|
||||||
|
|
||||||
|
### Celery
|
||||||
|
|
||||||
|
This app comes with Celery.
|
||||||
|
|
||||||
|
To run a celery worker:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd lms
|
||||||
|
celery -A config.celery_app worker -l info
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note: For Celery's import magic to work, it is important _where_ the celery commands are run. If you are in the same folder with _manage.py_, you should be right.
|
||||||
|
|
||||||
|
To run [periodic tasks](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html), you'll need to start the celery beat scheduler service. You can start it as a standalone process:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd lms
|
||||||
|
celery -A config.celery_app beat
|
||||||
|
```
|
||||||
|
|
||||||
|
or you can embed the beat service inside a worker with the `-B` option (not recommended for production use):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd lms
|
||||||
|
celery -A config.celery_app worker -B -l info
|
||||||
|
```
|
||||||
|
|
||||||
|
### Email Server
|
||||||
|
|
||||||
|
In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server [Mailpit](https://github.com/axllent/mailpit) with a web interface is available as docker container.
|
||||||
|
|
||||||
|
Container mailpit will start automatically when you will run all docker containers.
|
||||||
|
Please check [cookiecutter-django Docker documentation](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally-docker.html) for more details how to start all containers.
|
||||||
|
|
||||||
|
With Mailpit running, to view messages that are sent by your application, open your browser and go to `http://127.0.0.1:8025`
|
||||||
|
|
||||||
|
### Sentry
|
||||||
|
|
||||||
|
Sentry is an error logging aggregator service. You can sign up for a free account at <https://sentry.io/signup/?code=cookiecutter> or download and host it yourself.
|
||||||
|
The system is set up with reasonable defaults, including 404 logging and integration with the WSGI application.
|
||||||
|
|
||||||
|
You must set the DSN url in production.
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
The following details how to deploy this application.
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
See detailed [cookiecutter-django Docker documentation](https://cookiecutter-django.readthedocs.io/en/latest/3-deployment/deployment-with-docker.html).
|
||||||
|
|
@ -246,23 +246,23 @@ DJANGO_ADMIN_FORCE_ALLAUTH = env.bool("DJANGO_ADMIN_FORCE_ALLAUTH", default=Fals
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#logging
|
# https://docs.djangoproject.com/en/dev/ref/settings/#logging
|
||||||
# See https://docs.djangoproject.com/en/dev/topics/logging for
|
# See https://docs.djangoproject.com/en/dev/topics/logging for
|
||||||
# more details on how to customize your logging configuration.
|
# more details on how to customize your logging configuration.
|
||||||
# LOGGING = {
|
LOGGING = {
|
||||||
# "version": 1,
|
"version": 1,
|
||||||
# "disable_existing_loggers": False,
|
"disable_existing_loggers": False,
|
||||||
# "formatters": {
|
"formatters": {
|
||||||
# "verbose": {
|
"verbose": {
|
||||||
# "format": "%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s",
|
"format": "%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s",
|
||||||
# },
|
},
|
||||||
# },
|
},
|
||||||
# "handlers": {
|
"handlers": {
|
||||||
# "console": {
|
"console": {
|
||||||
# "level": "DEBUG",
|
"level": "DEBUG",
|
||||||
# "class": "logging.StreamHandler",
|
"class": "logging.StreamHandler",
|
||||||
# "formatter": "verbose",
|
"formatter": "verbose",
|
||||||
# },
|
},
|
||||||
# },
|
},
|
||||||
# "root": {"level": "INFO", "handlers": ["console"]},
|
"root": {"level": "INFO", "handlers": ["console"]},
|
||||||
# }
|
}
|
||||||
|
|
||||||
REDIS_URL = env("REDIS_URL", default="redis://redis:6379/0")
|
REDIS_URL = env("REDIS_URL", default="redis://redis:6379/0")
|
||||||
REDIS_SSL = REDIS_URL.startswith("rediss://")
|
REDIS_SSL = REDIS_URL.startswith("rediss://")
|
||||||
|
|
@ -339,9 +339,7 @@ ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = None
|
||||||
HEADLESS_FRONTEND_URLS = {
|
HEADLESS_FRONTEND_URLS = {
|
||||||
"account_signup":"http://localhost:3000/account/signup",
|
"account_signup":"http://localhost:3000/account/signup",
|
||||||
"account_confirm_email": "http://127.0.0.1:3000/account/email-confirmation/{key}/",
|
"account_confirm_email": "http://127.0.0.1:3000/account/email-confirmation/{key}/",
|
||||||
# Key placeholders are automatically populated. You are free to adjust this
|
|
||||||
# to your own needs, e.g.
|
|
||||||
#
|
|
||||||
# "https://app.project.org/account/email/verify-email?token={key}",
|
# "https://app.project.org/account/email/verify-email?token={key}",
|
||||||
"account_reset_password": "https://app.project.org/account/password/reset",
|
"account_reset_password": "https://app.project.org/account/password/reset",
|
||||||
"account_reset_password_from_key": "https://app.project.org/account/password/reset/key/{key}",
|
"account_reset_password_from_key": "https://app.project.org/account/password/reset/key/{key}",
|
||||||
|
|
@ -414,11 +412,3 @@ SPECTACULAR_SETTINGS = {
|
||||||
}
|
}
|
||||||
# Your stuff...
|
# Your stuff...
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# CSRF_COOKIE_SECURE = False # لأنك لا تستخدم HTTPS محليًا
|
|
||||||
# CSRF_COOKIE_SAMESITE = 'None' # للسماح بالطلبات عبر النطاقات
|
|
||||||
# CSRF_COOKIE_HTTPONLY = False # للسماح للـ JavaScript بالوصول إذا لزم الأمر
|
|
||||||
|
|
||||||
# SESSION_COOKIE_SECURE = False
|
|
||||||
# SESSION_COOKIE_SAMESITE = 'None'
|
|
||||||
# SESSION_COOKIE_HTTPONLY = True
|
|
||||||
|
|
||||||
|
|
@ -16,13 +16,13 @@ SECRET_KEY = env(
|
||||||
)
|
)
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
||||||
ALLOWED_HOSTS = ["127.0.0.1", "localhost",
|
ALLOWED_HOSTS = ["127.0.0.1", "localhost",
|
||||||
"8000-idx-lms-1736953337728.cluster-p6qcyjpiljdwusmrjxdspyb5m2.cloudworkstations.dev"
|
"8000-idx-learning-management-systemgit-1737467650700.cluster-y34ecccqenfhcuavp7vbnxv7zk.cloudworkstations.dev"
|
||||||
] # حدد المضيفين المسموح بهم
|
] # حدد المضيفين المسموح بهم
|
||||||
|
|
||||||
CSRF_TRUSTED_ORIGINS = [
|
CSRF_TRUSTED_ORIGINS = [
|
||||||
'http://localhost:3000',
|
'http://localhost:3000',
|
||||||
'http://127.0.0.1:3000',
|
'http://127.0.0.1:3000',
|
||||||
'https://8000-idx-lms-1736953337728.cluster-p6qcyjpiljdwusmrjxdspyb5m2.cloudworkstations.dev'
|
'https://8000-idx-learning-management-systemgit-1737467650700.cluster-y34ecccqenfhcuavp7vbnxv7zk.cloudworkstations.dev'
|
||||||
]
|
]
|
||||||
CORS_ORIGIN_ALLOW_ALL = True
|
CORS_ORIGIN_ALLOW_ALL = True
|
||||||
CORS_ALLOW_CREDENTIALS = False
|
CORS_ALLOW_CREDENTIALS = False
|
||||||
|
|
@ -23,7 +23,7 @@ urlpatterns = [
|
||||||
# Django Admin, use {% url 'admin:index' %}
|
# Django Admin, use {% url 'admin:index' %}
|
||||||
path(settings.ADMIN_URL, admin.site.urls),
|
path(settings.ADMIN_URL, admin.site.urls),
|
||||||
|
|
||||||
# path("auth/", include("allauth.headless.urls")),
|
path("authwed/", include("allauth.urls")),
|
||||||
# Your stuff: custom urls includes go here
|
# Your stuff: custom urls includes go here
|
||||||
# ...
|
# ...
|
||||||
# Media files
|
# Media files
|
||||||
|
|
@ -92,9 +92,6 @@ class CustomRegisterSerializer(RegisterSerializer):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ChangeEmailSerializer(serializers.Serializer):
|
class ChangeEmailSerializer(serializers.Serializer):
|
||||||
email = serializers.EmailField()
|
email = serializers.EmailField()
|
||||||
|
|
||||||
|
|
@ -42,7 +42,6 @@ class UserView(APIView):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ChangeEmailView(APIView):
|
class ChangeEmailView(APIView):
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
107
backend/lms/app/tests/test_models.py
Normal file
107
backend/lms/app/tests/test_models.py
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from rest_framework.test import APIClient
|
||||||
|
from rest_framework.exceptions import ValidationError
|
||||||
|
from lms.app.models import Course, Module, Lesson, Enrollment, Certificate, AD
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
class ModelsTestCase(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Create test user
|
||||||
|
self.user = User.objects.create_user(email='testuser@email.com', password='password')
|
||||||
|
self.client = APIClient()
|
||||||
|
self.client.force_authenticate(user=self.user)
|
||||||
|
|
||||||
|
# Create a test course
|
||||||
|
self.course = Course.objects.create(
|
||||||
|
title="Test Course",
|
||||||
|
description="A test course description",
|
||||||
|
is_paid=True,
|
||||||
|
price=100.00,
|
||||||
|
owner=self.user
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_course_creation(self):
|
||||||
|
"""Test creating a course"""
|
||||||
|
self.assertEqual(Course.objects.count(), 1)
|
||||||
|
self.assertEqual(self.course.title, "Test Course")
|
||||||
|
self.assertTrue(self.course.is_paid)
|
||||||
|
self.assertEqual(self.course.price, 100.00)
|
||||||
|
|
||||||
|
def test_course_validation(self):
|
||||||
|
"""Test course validation logic"""
|
||||||
|
course = Course(
|
||||||
|
title="Invalid Course",
|
||||||
|
description="Should fail validation",
|
||||||
|
is_paid=True,
|
||||||
|
price=None, # Invalid case
|
||||||
|
owner=self.user
|
||||||
|
)
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
course.clean()
|
||||||
|
|
||||||
|
def test_module_creation(self):
|
||||||
|
"""Test creating a module"""
|
||||||
|
module = Module.objects.create(
|
||||||
|
title="Test Module",
|
||||||
|
description="A test module description",
|
||||||
|
course=self.course,
|
||||||
|
created_by=self.user
|
||||||
|
)
|
||||||
|
self.assertEqual(Module.objects.count(), 1)
|
||||||
|
self.assertEqual(module.title, "Test Module")
|
||||||
|
|
||||||
|
def test_lesson_creation(self):
|
||||||
|
"""Test creating a lesson"""
|
||||||
|
module = Module.objects.create(
|
||||||
|
title="Test Module",
|
||||||
|
course=self.course,
|
||||||
|
created_by=self.user
|
||||||
|
)
|
||||||
|
lesson = Lesson.objects.create(
|
||||||
|
title="Test Lesson",
|
||||||
|
description="A test lesson description",
|
||||||
|
content="Lesson content here",
|
||||||
|
module=module,
|
||||||
|
created_by=self.user
|
||||||
|
)
|
||||||
|
self.assertEqual(Lesson.objects.count(), 1)
|
||||||
|
self.assertEqual(lesson.title, "Test Lesson")
|
||||||
|
self.assertEqual(lesson.module, module)
|
||||||
|
|
||||||
|
def test_enrollment_creation(self):
|
||||||
|
"""Test creating an enrollment"""
|
||||||
|
enrollment = Enrollment.objects.create(
|
||||||
|
student=self.user,
|
||||||
|
course=self.course,
|
||||||
|
completed=False
|
||||||
|
)
|
||||||
|
self.assertEqual(Enrollment.objects.count(), 1)
|
||||||
|
self.assertEqual(enrollment.student, self.user)
|
||||||
|
self.assertEqual(enrollment.course, self.course)
|
||||||
|
|
||||||
|
def test_certificate_creation(self):
|
||||||
|
"""Test creating a certificate"""
|
||||||
|
certificate = Certificate.objects.create(
|
||||||
|
student=self.user,
|
||||||
|
course=self.course,
|
||||||
|
certificate_file='path/to/certificate.pdf'
|
||||||
|
)
|
||||||
|
self.assertEqual(Certificate.objects.count(), 1)
|
||||||
|
self.assertEqual(certificate.student, self.user)
|
||||||
|
self.assertEqual(certificate.course, self.course)
|
||||||
|
|
||||||
|
def test_ad_creation(self):
|
||||||
|
"""Test creating an ad"""
|
||||||
|
ad = AD.objects.create(
|
||||||
|
title="Test Ad",
|
||||||
|
description="This is a test ad",
|
||||||
|
image=None
|
||||||
|
)
|
||||||
|
self.assertEqual(AD.objects.count(), 1)
|
||||||
|
self.assertEqual(ad.title, "Test Ad")
|
||||||
|
self.assertEqual(ad.description, "This is a test ad")
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue