This commit is contained in:
Ahmed Nagi 2025-01-22 11:23:14 +00:00
parent d24197b6c9
commit 7ac0b3f8ee
198 changed files with 15864 additions and 186 deletions

21
LICENSE Normal file
View 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
View file

@ -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.
![Image](image.jpg)
## 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.
- **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.
- **Interactive Frontend**: A Vue.js-powered frontend for seamless interaction with the backend API, including real-time updates and dynamic views.
## Technologies Used
- **Backend**: Django, Django Rest Framework (DRF)
### Backend
- **Framework**: Django, Django Rest Framework (DRF)
- **Authentication**: dj-rest-auth & django-alluth
- **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/)
## Local Development
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]
```
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.
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.
## 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.
* ReDoc Interface: Professionally styled documentation for better readabi* lity.
* Auto-generated: No need to write documentation manually; drf_yasg extracts t* he information from DRF views and serializers.
- **Interactive Swagger UI**: Test API endpoints directly within the browser.
- **MkDocs Material Interface**: A clean and customizable documentation tool with a modern Material Design theme.
- **Auto-generated**: No need to write documentation manually; drf-spectacularyasg extracts the information from DRF views and serializers.
## Contributing
@ -59,106 +57,7 @@ Contributions are welcome! If youd like to contribute, please follow these st
This project is licensed under the MIT License. See the LICENSE file for details.
## Acknowledgments
---
- Built with ❤️ using Django and Django Rest Framework.
- Inspired by the need for scalable and secure e-learning solutions.
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!
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.
[![Built with Cookiecutter Django](https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg?logo=cookiecutter)](https://github.com/cookiecutter/cookiecutter-django/)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](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).

View file

91
backend/README.md Normal file
View file

@ -0,0 +1,91 @@
[![Built with Cookiecutter Django](https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg?logo=cookiecutter)](https://github.com/cookiecutter/cookiecutter-django/)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](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).

View file

@ -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
# See https://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
# LOGGING = {
# "version": 1,
# "disable_existing_loggers": False,
# "formatters": {
# "verbose": {
# "format": "%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s",
# },
# },
# "handlers": {
# "console": {
# "level": "DEBUG",
# "class": "logging.StreamHandler",
# "formatter": "verbose",
# },
# },
# "root": {"level": "INFO", "handlers": ["console"]},
# }
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"verbose": {
"format": "%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s",
},
},
"handlers": {
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "verbose",
},
},
"root": {"level": "INFO", "handlers": ["console"]},
}
REDIS_URL = env("REDIS_URL", default="redis://redis:6379/0")
REDIS_SSL = REDIS_URL.startswith("rediss://")
@ -339,9 +339,7 @@ ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = None
HEADLESS_FRONTEND_URLS = {
"account_signup":"http://localhost:3000/account/signup",
"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}",
"account_reset_password": "https://app.project.org/account/password/reset",
"account_reset_password_from_key": "https://app.project.org/account/password/reset/key/{key}",
@ -414,11 +412,3 @@ SPECTACULAR_SETTINGS = {
}
# 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

View file

@ -16,13 +16,13 @@ SECRET_KEY = env(
)
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
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 = [
'http://localhost: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_ALLOW_CREDENTIALS = False

View file

@ -23,7 +23,7 @@ urlpatterns = [
# Django Admin, use {% url 'admin:index' %}
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
# ...
# Media files

View file

@ -92,9 +92,6 @@ class CustomRegisterSerializer(RegisterSerializer):
class ChangeEmailSerializer(serializers.Serializer):
email = serializers.EmailField()

View file

@ -42,7 +42,6 @@ class UserView(APIView):
class ChangeEmailView(APIView):
def post(self, request, *args, **kwargs):

View 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