Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Muqadim/celery redis features #11

Open
wants to merge 4 commits into
base: muqadim/user_project_app_styling
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 89 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ A Django-based project management system that provides functionalities for proje
- [Features App Wise](#features-app-wise)
- [Management Commands](#management-commands)
- [Django Admin Enhancements](#django-admin-enhancements)
- [Celery Tasks](#celery-tasks)
- [Unit Tests](#unit-test)
- [How to Use](#how-to-use)
- [Dependencies](#dependencies)
- [Future Enhancements](#future-enhancements)
Expand Down Expand Up @@ -37,6 +39,12 @@ muqadim_basic_user_app_django/
│ │ ├── projects_list.html
│ │ ├── supervisor_login.html
│ │ └── view_comments.html
│ ├── 📁 static/
│ │ └── css/
│ │ ├── create_project.css
│ │ ├── projects_list.css
│ │ ├── supervisor_login.css
│ │ └── view_comments.css
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
Expand All @@ -53,6 +61,7 @@ muqadim_basic_user_app_django/
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
│ ├── celery.py
├── 📁 user/
│ ├── 📁 management/
Expand All @@ -70,6 +79,13 @@ muqadim_basic_user_app_django/
│ │ ├── home.html
│ │ ├── login.html
│ │ └── signup.html
│ ├── 📁 static/
│ │ └── css/
│ │ ├── change_password.css
│ │ ├── edit_profile.css
│ │ ├── home.css
│ │ ├── login.css
│ │ └── signup.css
│ ├── __init__.py
│ ├── admin.py
│ ├── admin_forms.py
Expand All @@ -82,6 +98,7 @@ muqadim_basic_user_app_django/
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ ├── tasks.py
│ └── views.py
├── 📁 utils/
Expand Down Expand Up @@ -328,8 +345,62 @@ The app's URL blueprint provides paths for both conventional web views and API a

Models like `CustomUser`, `DateTimeRecord`,`PROJECT`,`SUPERVISOR`,`COMMENTS` etc are registered. Customizations include field rearrangements, list displays, and filters.

## How to Use
## Celery-Tasks
1. Whenever a user signs up a welcome mail is sent to him ,MailTral service is being used for this purpose,you need to run redis server on one terminal and celery server in other as well for this purpose
#### For starting redis
```bash
redis server
```

### in other terminal
#### For starting the celery
```bash
celery -A UniManage worker --loglevel=info
```
2. A reminder mail to get back to platform is sent to the user ,the period upon which this reminder mail is to be sent is decided in model reminder setting you can edit that value in the django admin,MailTral service is being used for this purpose,you need to run redis server ion one terminal and celery server in other and celery beat server on another terminal as well for this purpose
#### For starting redis
```bash
redis server
```

### in other terminal
#### For starting the celery
```bash
celery -A UniManage worker --loglevel=info
```

### in another terminal
#### For starting the celery beat
```bash
celery -A UniManage beat --loglevel=info
```

## Unit-Test
Unit Tests have been deployed for both models ,unit tests dont cover the whole project, total coverage of unit test for this whole project is 42% .
### You can run the unit tests through following commands
#### For User app
```bash
python3 manage.py test user
```
#### For Project app
```bash
python3 manage.py test project
```
#### For whole project
```bash
python3 manage.py test
```
#### For Unit Test Coverage
```bash
coverage run manage.py test
```
```bash
coverage report
```



## How to Use
1. Set up a Django project.
2. Ensure Django's authentication system is set up.
3. Include the URL patterns in your project's configuration.
Expand Down Expand Up @@ -393,10 +464,26 @@ python manage.py runserver

Yet another Swagger generator. It's a great tool for creating API documentation with OpenAPI and Swagger.

- **redis**

Redis is an open-source, in-memory data structure store, used as a database, cache, and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, and geospatial indexes with radius queries.

- **celery**

Celery is an asynchronous task queue/job queue based on distributed message passing. It is focused on real-time operation but supports scheduling as well.

- **celery[beat]**

Celery Beat is a scheduler that integrates with Celery. It allows you to run tasks at regular intervals, similar to cron jobs in Unix systems.

- **django-countries**

A Django application that provides a country field for models and forms. It allows you to easily add drop-downs in forms to select a country, and it includes a list of all countries with their names, ISO codes, and more.

To install all the dependencies, use the following pip command:

```bash
pip install django==4.2.3 djangorestframework django-rest-framework-simplejwt djoser drf-yasg
pip install django==4.2.3 djangorestframework django-rest-framework-simplejwt djoser drf-yasg redis celery celery[beat] django-countries
```


Expand Down
5 changes: 5 additions & 0 deletions UniManage/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# __init__.py

from .celery import app as celery_app

__all__ = ('celery_app',)
20 changes: 20 additions & 0 deletions UniManage/celery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# celery.py

import os
from celery import Celery
from django.conf import settings


# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'UniManage.settings')

app = Celery('UniManage')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

# celery.py (or wherever your Celery configurations are)
42 changes: 41 additions & 1 deletion UniManage/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pathlib import Path
import datetime
import os
from datetime import timedelta

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
Expand All @@ -39,6 +40,7 @@
'rest_framework',
'djoser',
'drf_yasg',
'model_utils',
]

REST_FRAMEWORK = {
Expand Down Expand Up @@ -132,7 +134,7 @@
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'user.middleware.CustomAuthenticationMiddleware',
]
]

AUTH_USER_MODEL = 'user.CustomUser'

Expand All @@ -144,3 +146,41 @@
os.path.join(BASE_DIR, "project/static"),
os.path.join(BASE_DIR, "user/static")
]

# settings.py

# Celery configurations
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'UTC'

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

# SMTP configuration
EMAIL_HOST = 'sandbox.smtp.mailtrap.io'
EMAIL_PORT = 587 # You can choose any of the provided ports, but 587 is commonly used for STARTTLS
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '6bd0f1298b89cb'
EMAIL_HOST_PASSWORD = '75848b7312e651'

CELERY_BEAT_SCHEDULE = {
'check-login': {
'task': 'user.tasks.check_last_login_and_send_email',
'schedule': timedelta(minutes=1), # Run daily
},
}

CELERY_BEAT_MAX_LOOP_INTERVAL = 25 # Time in seconds. 600 seconds is 10 minutes.

CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
Binary file modified db.sqlite3
Binary file not shown.
2 changes: 1 addition & 1 deletion project/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.3 on 2023-08-29 07:32
# Generated by Django 4.2.3 on 2023-09-04 07:14

from django.db import migrations, models

Expand Down
4 changes: 2 additions & 2 deletions project/migrations/0002_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.3 on 2023-08-29 07:32
# Generated by Django 4.2.3 on 2023-09-04 07:14

from django.conf import settings
from django.db import migrations, models
Expand All @@ -10,8 +10,8 @@ class Migration(migrations.Migration):
initial = True

dependencies = [
('project', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('project', '0001_initial'),
]

operations = [
Expand Down
19 changes: 11 additions & 8 deletions project/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def setUp(self):
"""Setup test data for Supervisor login tests."""
self.client = APIClient()
self.user = CustomUser.objects.create_user(email='[email protected]', password='testpassword', username='test',
father_name='father', description='hell no')
father_name='father', description='hell no', country="Algeria")
self.supervisor = Supervisor.objects.create(user=self.user, expertise="Testing")

def test_supervisor_login(self):
Expand All @@ -44,7 +44,8 @@ def setUp(self):
"""Setup test data for Comment view set tests."""
self.client = APIClient()
self.user = CustomUser.objects.create_user(email='[email protected]', password='testpassword', username='test3',
father_name='father3', description='description 3')
father_name='father3', description='description 3',
country="Algeria")
self.supervisor = Supervisor.objects.create(user=self.user, expertise="QA")
self.project = Project.objects.create(name="Test Project 2", description="A second test project",
start_date="2023-01-02", end_date="2023-12-31",
Expand Down Expand Up @@ -72,7 +73,7 @@ class ProjectSerializerTestCase(TestCase):
def setUp(self):
"""Setup test data for Project serializer tests."""
self.user = CustomUser.objects.create(email="[email protected]", password="testpassword", username="testuser",
father_name="testfather", description="testdesc")
father_name="testfather", description="testdesc", country="Algeria")
self.supervisor = Supervisor.objects.create(user=self.user)
self.project_data = {
'name': 'Test Project',
Expand Down Expand Up @@ -121,7 +122,7 @@ class CommentSerializerTestCase(TestCase):
def setUp(self):
"""Setup test data for Comment serializer tests."""
self.user = CustomUser.objects.create(email="[email protected]", password="testpassword2", username="testuser2",
father_name="testfather2", description="testdesc2")
father_name="testfather2", description="testdesc2", country="Algeria")
self.supervisor = Supervisor.objects.create(user=self.user)
self.project = Project.objects.create(name='Test Project', description='Test', start_date='2023-01-01',
end_date='2023-12-31', supervisor=self.supervisor)
Expand Down Expand Up @@ -159,7 +160,7 @@ def setUp(self):
"""Setup test data for Supervisor login serializer tests."""
self.user = CustomUser.objects.create_user(email="[email protected]", password="supervisorpassword",
username="supervisoruser", father_name="supervisorfather",
description="supervisordesc")
description="supervisordesc", country="Algeria")
self.supervisor = Supervisor.objects.create(user=self.user)

def test_valid_login(self):
Expand All @@ -183,7 +184,7 @@ def test_invalid_login(self):
def test_non_supervisor_login(self):
user = CustomUser.objects.create_user(email="[email protected]", password="testpassword3",
username="nonsupervisoruser", father_name="nonsupervisorfather",
description="nonsupervisordesc")
description="nonsupervisordesc", country='Algeria')
data = {
'email': '[email protected]',
'password': 'testpassword3'
Expand All @@ -201,7 +202,7 @@ class ProjectsListViewTestCase(TestCase):
def setUp(self):
"""Setup test data for ProjectsListView tests."""
self.user = CustomUser.objects.create_user(email='[email protected]', password='testpassword', username='test',
father_name='father', description='description')
father_name='father', description='description', country='Algeria')
self.supervisor = Supervisor.objects.create(user=self.user, expertise="Testing")
self.project1 = Project.objects.create(name="Test Project 1", supervisor=self.supervisor,
start_date=date.today(), end_date=date.today() + timedelta(days=10))
Expand Down Expand Up @@ -229,7 +230,9 @@ def setUp(self):
"""Setup test data for ViewCommentsView tests."""
self.user = CustomUser.objects.create_user(email='[email protected]', password='testpassword',
username='commenter',
father_name='father_commenter', description='description_commenter')
father_name='father_commenter', description='description_commenter',
country='Algeria'
)
self.supervisor = Supervisor.objects.create(user=self.user, expertise="QA")
self.project = Project.objects.create(name="Test Project", supervisor=self.supervisor, start_date=date.today(),
end_date=date.today() + timedelta(days=10))
Expand Down
32 changes: 26 additions & 6 deletions user/admin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser, DateTimeRecord
from .admin_site import admin_site
from django.contrib import admin
from .models import CustomUser, DateTimeRecord
from .models import CustomUser, DateTimeRecord, ReminderSetting


def make_active(modeladmin, request, queryset):
Expand Down Expand Up @@ -43,13 +42,13 @@ class CustomUserAdmin(UserAdmin):

fieldsets = (
(None, {'fields': (
'username', 'email', 'description', 'father_name', 'password', 'software_engineering_experience',
'last_profile_update', 'is_active', 'is_staff')}),
'username', 'email', 'description', 'father_name', 'password', 'software_engineering_experience',
'last_profile_update', 'is_active', 'is_staff')}),
)

list_display = (
'email', 'description', 'username', 'father_name', 'first_name', 'last_name', 'software_engineering_experience',
'last_profile_update')
'email', 'description', 'username', 'father_name', 'first_name', 'last_name', 'software_engineering_experience',
'last_profile_update')
search_fields = ('email', 'first_name', 'last_name', 'father_name')
list_filter = ('is_active', 'is_staff', 'software_engineering_experience')
actions = [make_active, make_inactive]
Expand All @@ -72,3 +71,24 @@ class DateTimeRecordAdmin(admin.ModelAdmin):


admin_site.register(DateTimeRecord, DateTimeRecordAdmin)


class ReminderSettingAdmin(admin.ModelAdmin):
list_display = ['duration']

def has_add_permission(self, request):
# Disable addition if a ReminderSetting instance already exists
return not ReminderSetting.objects.exists()

def has_delete_permission(self, request, obj=None):
# Disable deletion
return False

# Hide the delete action
def get_actions(self, request):
actions = super().get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions

admin_site.register(ReminderSetting, ReminderSettingAdmin)
Loading