first commit
This commit is contained in:
147
.gitignore
vendored
Normal file
147
.gitignore
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
media
|
||||
logs
|
||||
|
||||
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
nifty11appvenv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
# cython_debug/
|
||||
# Footer
|
||||
# © 2022 GitHub, Inc.
|
||||
# Footer navigation
|
||||
# Terms
|
||||
# Privacy
|
||||
# Security
|
||||
# Status
|
||||
# Docs
|
||||
# Contact GitHub
|
||||
# Pricing
|
||||
# # API
|
||||
# Training
|
||||
# Blog
|
||||
# About
|
||||
38
env.example
Normal file
38
env.example
Normal file
@@ -0,0 +1,38 @@
|
||||
# ENV_NAME options are Production, Staging and Development
|
||||
ENV_NAME=
|
||||
|
||||
SECRET_KEY=
|
||||
|
||||
DJANGO_DEBUG=True
|
||||
|
||||
LOG_LEVEL=INFO
|
||||
|
||||
DB_DATABASE=niftyll
|
||||
DB_HOST=127.0.0.1
|
||||
DB_USERNAME=
|
||||
DB_PASSWORD=
|
||||
DB_PORT=3306
|
||||
|
||||
CELERY_BROKER_URL=redis://localhost:6379
|
||||
|
||||
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
|
||||
EMAIL_HOST=smtp.gmail.com
|
||||
EMAIL_PORT=587
|
||||
EMAIL_HOST_USER=
|
||||
EMAIL_HOST_PASSWORD=
|
||||
EMAIL_USE_TLS=True
|
||||
|
||||
TWILIO_ACCOUNT_SID=
|
||||
TWILIO_AUTH_TOKEN=
|
||||
MY_TWILIO_NUMBER=
|
||||
|
||||
STRIPE_SECRET_KEY=
|
||||
|
||||
ALPHA_VANTAGE=
|
||||
|
||||
PAYTM_MER_ID=
|
||||
PAYTM_MER_KEY=
|
||||
PAYTM_WEBSITE=
|
||||
PAYTM_IND_TYPE=
|
||||
PAYTM_CHANL_ID_WEB=
|
||||
PAYTM_CHANL_ID_APP=
|
||||
22
manage.py
Normal file
22
manage.py
Normal file
@@ -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', 'module_project.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()
|
||||
0
module_activity/__init__.py
Normal file
0
module_activity/__init__.py
Normal file
3
module_activity/admin.py
Normal file
3
module_activity/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
346
module_activity/api/serializers.py
Normal file
346
module_activity/api/serializers.py
Normal file
@@ -0,0 +1,346 @@
|
||||
from rest_framework import serializers
|
||||
from django.utils import timezone
|
||||
from datetime import datetime
|
||||
from module_iam.models import IAmPrincipal
|
||||
from ..models import (
|
||||
PrincipalHealthData,
|
||||
Intolerance,
|
||||
Symptoms,
|
||||
PastTreatment,
|
||||
ChronicCondition,
|
||||
Medicine,
|
||||
Medication,
|
||||
Bowel,
|
||||
SymptomTypeAfterMeal,
|
||||
SymptomTypeBeforeMeal,
|
||||
MealSymptomRecord,
|
||||
FoodIngredientRecord,
|
||||
FoodRecord,
|
||||
BeverageRecord,
|
||||
MealRecord,
|
||||
)
|
||||
|
||||
class IAmPrincipalSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = IAmPrincipal
|
||||
fields = [
|
||||
# "profile_photo",
|
||||
"first_name",
|
||||
"date_of_birth",
|
||||
"gender",
|
||||
"phone_no",
|
||||
]
|
||||
|
||||
class PrincipalHealthDataSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = PrincipalHealthData
|
||||
fields = [
|
||||
"ethenicity",
|
||||
"weight",
|
||||
"height",
|
||||
"gastrointestinal_health",
|
||||
"exercise_frequency",
|
||||
"sleep_duration",
|
||||
"eat_frequency",
|
||||
]
|
||||
|
||||
class PrincipalAndHealthSerializer(serializers.ModelSerializer):
|
||||
ethenicity = serializers.CharField(read_only=True)
|
||||
weight = serializers.DecimalField(max_digits=5, decimal_places=2, read_only=True)
|
||||
height = serializers.DecimalField(max_digits=6, decimal_places=2, read_only=True)
|
||||
gastrointestinal_health = serializers.CharField(read_only=True)
|
||||
exercise_frequency = serializers.CharField(read_only=True)
|
||||
sleep_duration = serializers.CharField(read_only=True)
|
||||
eat_frequency = serializers.CharField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = IAmPrincipal
|
||||
fields = [
|
||||
"profile_photo",
|
||||
"first_name",
|
||||
"email",
|
||||
"date_of_birth",
|
||||
"gender",
|
||||
"phone_no",
|
||||
"phone_verified",
|
||||
"email_verified",
|
||||
"ethenicity",
|
||||
"weight",
|
||||
"height",
|
||||
"gastrointestinal_health",
|
||||
"exercise_frequency",
|
||||
"sleep_duration",
|
||||
"eat_frequency",
|
||||
]
|
||||
|
||||
def get_image_url(self, obj, field_name, request):
|
||||
image_field = getattr(obj, field_name)
|
||||
if image_field:
|
||||
return request.build_absolute_uri(image_field.url)
|
||||
return ""
|
||||
|
||||
def to_representation(self, instance):
|
||||
data = super().to_representation(instance)
|
||||
request = self.context.get("request")
|
||||
data["profile_photo"] = self.get_image_url(instance, "profile_photo", request)
|
||||
health_data = instance.health_data_principal
|
||||
if health_data:
|
||||
data['ethenicity'] = health_data.ethenicity
|
||||
data['weight'] = health_data.weight
|
||||
data['height'] = health_data.height
|
||||
data['gastrointestinal_health'] = health_data.gastrointestinal_health
|
||||
data['exercise_frequency'] = health_data.exercise_frequency
|
||||
data['sleep_duration'] = health_data.sleep_duration
|
||||
data['eat_frequency'] = health_data.eat_frequency
|
||||
return data
|
||||
|
||||
|
||||
class IntoleranceSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Intolerance
|
||||
fields = ["id", "name", "duration"]
|
||||
|
||||
class SymptomsSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Symptoms
|
||||
fields = ["id", "name", "duration"]
|
||||
|
||||
|
||||
class PastTreatmentSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = PastTreatment
|
||||
fields = ["id", "name", "duration"]
|
||||
|
||||
|
||||
class ChronicConditionSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ChronicCondition
|
||||
fields = ["id", "name", "duration"]
|
||||
|
||||
|
||||
class FoodIngredientRecordSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = FoodIngredientRecord
|
||||
fields = ["name"]
|
||||
|
||||
|
||||
class FoodRecordSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = FoodRecord
|
||||
fields = ["name", "quantity"]
|
||||
|
||||
|
||||
class BeverageRecordSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = BeverageRecord
|
||||
fields = [
|
||||
"beverage_type",
|
||||
"glass_type",
|
||||
"glass_count",
|
||||
"quantity",
|
||||
"quantity_measure",
|
||||
]
|
||||
|
||||
class MealRecordSerializer(serializers.ModelSerializer):
|
||||
food_records = FoodRecordSerializer(many=True)
|
||||
beverage_records = BeverageRecordSerializer(many=True)
|
||||
food_ingredient_records = FoodIngredientRecordSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = MealRecord
|
||||
fields = ['id', 'date', 'time', 'meal_type', 'food_records', 'food_ingredient_records', 'beverage_records']
|
||||
|
||||
def create(self, validated_data):
|
||||
food_record_data = validated_data.pop("food_records", [])
|
||||
beverage_record_data = validated_data.pop("beverage_records", [])
|
||||
food_ingredient_record_data = validated_data.pop("food_ingredient_records", [])
|
||||
|
||||
meal_record = self.Meta.model.objects.create(**validated_data)
|
||||
|
||||
food_record_list = []
|
||||
for data in food_record_data:
|
||||
obj, _ = FoodRecord.objects.get_or_create(**data)
|
||||
food_record_list.append(obj)
|
||||
|
||||
food_ingredient_list = []
|
||||
for data in food_ingredient_record_data:
|
||||
obj, _ = FoodIngredientRecord.objects.get_or_create(**data)
|
||||
food_ingredient_list.append(obj)
|
||||
|
||||
beverage_record_list = []
|
||||
for data in beverage_record_data:
|
||||
obj, _ = BeverageRecord.objects.get_or_create(**data)
|
||||
beverage_record_list.append(obj)
|
||||
|
||||
meal_record.food_records.set(food_record_list)
|
||||
meal_record.food_ingredient_records.set(food_ingredient_list)
|
||||
meal_record.beverage_records.set(beverage_record_list)
|
||||
|
||||
return meal_record
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
instance.date = validated_data.get("date", instance.date)
|
||||
instance.time = validated_data.get("time", instance.time)
|
||||
instance.meal_type = validated_data.get("meal_type", instance.meal_type)
|
||||
instance.save()
|
||||
|
||||
food_record_data = validated_data.pop("food_records", [])
|
||||
beverage_record_data = validated_data.pop("beverage_records", [])
|
||||
food_ingredient_record_data = validated_data.pop("food_ingredient_records", [])
|
||||
|
||||
food_record_list = []
|
||||
for data in food_record_data:
|
||||
obj, _ = FoodRecord.objects.get_or_create(**data)
|
||||
food_record_list.append(obj)
|
||||
|
||||
food_ingredient_list = []
|
||||
for data in food_ingredient_record_data:
|
||||
obj, _ = FoodIngredientRecord.objects.get_or_create(**data)
|
||||
food_ingredient_list.append(obj)
|
||||
|
||||
beverage_record_list = []
|
||||
for data in beverage_record_data:
|
||||
obj, _ = BeverageRecord.objects.get_or_create(**data)
|
||||
beverage_record_list.append(obj)
|
||||
|
||||
instance.food_records.set(food_record_list)
|
||||
instance.food_ingredient_records.set(food_ingredient_list)
|
||||
instance.beverage_records.set(beverage_record_list)
|
||||
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
class MedicineSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Medicine
|
||||
fields = ["name", "quantity", "type"]
|
||||
|
||||
|
||||
class MedicationSerializer(serializers.ModelSerializer):
|
||||
medicines = MedicineSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Medication
|
||||
fields = ["id", "date", "time", "medicines"]
|
||||
|
||||
def create(self, validated_data):
|
||||
medicines_data = validated_data.pop("medicines")
|
||||
medication = self.Meta.model.objects.create(**validated_data)
|
||||
for medicine_data in medicines_data:
|
||||
medicine = Medicine.objects.create(**medicine_data)
|
||||
medication.medicines.add(medicine)
|
||||
return medication
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
instance.date = validated_data.get("date", instance.date)
|
||||
instance.time = validated_data.get("time", instance.time)
|
||||
instance.save()
|
||||
|
||||
medicines_data = validated_data.get("medicines", [])
|
||||
instance.medicines.clear()
|
||||
for medicine_data in medicines_data:
|
||||
medicine = Medicine.objects.create(**medicine_data)
|
||||
instance.medicines.add(medicine)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
class BowelSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Bowel
|
||||
fields = [
|
||||
"id",
|
||||
"date",
|
||||
"time",
|
||||
"stool_type",
|
||||
"duration",
|
||||
"completeness_of_evacuation",
|
||||
"urgency",
|
||||
"smellness",
|
||||
"pain_level",
|
||||
"volume",
|
||||
"color",
|
||||
"excessive_flatulence",
|
||||
]
|
||||
|
||||
|
||||
class SymptomTypeBeforeMealSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SymptomTypeBeforeMeal
|
||||
fields = ["name"]
|
||||
|
||||
|
||||
class SymptomTypeAfterMealSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SymptomTypeAfterMeal
|
||||
fields = ["name"]
|
||||
|
||||
|
||||
class MealSymptomRecordSerializer(serializers.ModelSerializer):
|
||||
symptoms_before_meal = SymptomTypeBeforeMealSerializer(many=True)
|
||||
symptoms_after_meal = SymptomTypeAfterMealSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = MealSymptomRecord
|
||||
fields = [
|
||||
"id",
|
||||
"date",
|
||||
"time",
|
||||
"symptoms_description",
|
||||
"interval",
|
||||
"symptoms_before_meal",
|
||||
"symptoms_after_meal",
|
||||
]
|
||||
|
||||
def create(self, validated_data):
|
||||
before_meal_data = validated_data.pop("symptoms_before_meal")
|
||||
after_meal_data = validated_data.pop("symptoms_after_meal")
|
||||
|
||||
meal_symptom_record = MealSymptomRecord.objects.create(**validated_data)
|
||||
|
||||
before_meal_list = []
|
||||
for data in before_meal_data:
|
||||
obj, _ = SymptomTypeBeforeMeal.objects.get_or_create(**data)
|
||||
before_meal_list.append(obj)
|
||||
|
||||
after_meal_list = []
|
||||
for data in after_meal_data:
|
||||
obj, _ = SymptomTypeAfterMeal.objects.get_or_create(**data)
|
||||
after_meal_list.append(obj)
|
||||
|
||||
meal_symptom_record.symptoms_before_meal.set(before_meal_list)
|
||||
meal_symptom_record.symptoms_after_meal.set(after_meal_list)
|
||||
|
||||
return meal_symptom_record
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
instance.date = validated_data.get(
|
||||
"date", instance.date
|
||||
)
|
||||
instance.time = validated_data.get(
|
||||
"time", instance.time
|
||||
)
|
||||
instance.symptoms_description = validated_data.get(
|
||||
"symptoms_description", instance.symptoms_description
|
||||
)
|
||||
instance.interval = validated_data.get("interval", instance.interval)
|
||||
|
||||
before_meal_data = validated_data.pop("symptoms_before_meal", [])
|
||||
after_meal_data = validated_data.pop("symptoms_after_meal", [])
|
||||
|
||||
before_meal_instances = []
|
||||
for data in before_meal_data:
|
||||
obj, _ = SymptomTypeBeforeMeal.objects.get_or_create(**data)
|
||||
before_meal_instances.append(obj)
|
||||
|
||||
after_meal_instances = []
|
||||
for data in after_meal_data:
|
||||
obj, _ = SymptomTypeAfterMeal.objects.get_or_create(**data)
|
||||
after_meal_instances.append(obj)
|
||||
|
||||
instance.symptoms_before_meal.set(before_meal_instances)
|
||||
instance.symptoms_after_meal.set(after_meal_instances)
|
||||
|
||||
instance.save()
|
||||
|
||||
return instance
|
||||
29
module_activity/api/urls.py
Normal file
29
module_activity/api/urls.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
path("profile/", views.ProfileAPIView.as_view()),
|
||||
|
||||
path("daily-records/", views.DailyRecordAPIView.as_view()),
|
||||
|
||||
path("intolerance/", views.IntoleranceListCreateAPIView.as_view()),
|
||||
# path("intolerance/<int:pk>/", views.IntoleranceRetrieveUpdateDestroyAPIView.as_view()),
|
||||
path("symptoms/", views.SymptomsListCreateAPIView.as_view()),
|
||||
path("past-treatment/", views.PastTreatmentListCreateAPIView.as_view()),
|
||||
path("chronic-condition/", views.ChronicConditionListCreateAPIView.as_view()),
|
||||
|
||||
path("medication/", views.MedicationAPIView.as_view()),
|
||||
path("medication/<int:pk>/", views.MedicationAPIView.as_view()),
|
||||
|
||||
path("bowel/", views.BowelAPIView.as_view()),
|
||||
path("bowel/<int:pk>/", views.BowelAPIView.as_view()),
|
||||
|
||||
path("meal-symptoms/", views.MealSymptomAPIView.as_view()),
|
||||
path("meal-symptoms/<int:pk>/", views.MealSymptomAPIView.as_view()),
|
||||
|
||||
path("meal/", views.MealAPIView.as_view()),
|
||||
path("meal/<int:pk>/", views.MealAPIView.as_view()),
|
||||
|
||||
]
|
||||
617
module_activity/api/views.py
Normal file
617
module_activity/api/views.py
Normal file
@@ -0,0 +1,617 @@
|
||||
from datetime import datetime
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||
from django.db.models import Prefetch
|
||||
from module_project import constants
|
||||
from module_project.utils import ApiResponse
|
||||
from module_iam.models import IAmPrincipal
|
||||
from ..models import (
|
||||
PrincipalHealthData,
|
||||
Intolerance,
|
||||
Symptoms,
|
||||
PastTreatment,
|
||||
ChronicCondition,
|
||||
Medication,
|
||||
Bowel,
|
||||
MealSymptomRecord,
|
||||
MealRecord,
|
||||
)
|
||||
from .serializers import (
|
||||
IntoleranceSerializer,
|
||||
SymptomsSerializer,
|
||||
PastTreatmentSerializer,
|
||||
ChronicConditionSerializer,
|
||||
MedicationSerializer,
|
||||
BowelSerializer,
|
||||
MealSymptomRecordSerializer,
|
||||
MealRecordSerializer,
|
||||
IAmPrincipalSerializer,
|
||||
PrincipalHealthDataSerializer,
|
||||
PrincipalAndHealthSerializer,
|
||||
)
|
||||
|
||||
|
||||
class ProfileAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
post_serializer_class = IAmPrincipalSerializer
|
||||
get_serializer_class = PrincipalAndHealthSerializer
|
||||
model = IAmPrincipal
|
||||
|
||||
def get(self, request):
|
||||
try:
|
||||
obj = self.model.objects.prefetch_related("health_data_principal").get(
|
||||
pk=request.user.pk
|
||||
)
|
||||
serializer = self.get_serializer_class(obj, context={"request": request})
|
||||
except self.model.DoesNotExist:
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND
|
||||
)
|
||||
print(f"object data is {obj}")
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
data = request.data.copy()
|
||||
|
||||
# Separate principal and health data
|
||||
principal_data = {}
|
||||
health_data = {}
|
||||
for key, value in data.items():
|
||||
if key in self.post_serializer_class.Meta.fields:
|
||||
principal_data[key] = value
|
||||
else:
|
||||
health_data[key] = value
|
||||
|
||||
principal_serializer = self.post_serializer_class(
|
||||
instance=request.user, data=principal_data
|
||||
)
|
||||
health_serializer = PrincipalHealthDataSerializer(data=health_data)
|
||||
if not principal_serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=principal_serializer.errors
|
||||
)
|
||||
|
||||
if not health_serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=health_serializer.errors
|
||||
)
|
||||
|
||||
try:
|
||||
# with transaction.atomic(): # Ensure atomicity of database operations
|
||||
principal_instance = principal_serializer.save()
|
||||
|
||||
# Check if health data already exists for the principal
|
||||
health_data_instance, created = PrincipalHealthData.objects.get_or_create(
|
||||
principal=principal_instance
|
||||
)
|
||||
health_serializer.update(health_data_instance, health_data)
|
||||
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(message=constants.SUCCESS)
|
||||
|
||||
|
||||
class DailyRecordAPIView(APIView):
|
||||
|
||||
def serialize_record(self, record):
|
||||
time_obj = datetime.strptime(str(record.time), '%H:%M:%S')
|
||||
return {
|
||||
"id": record.id,
|
||||
"date": record.date,
|
||||
"time": time_obj.strftime('%I:%M %p'),
|
||||
# Add other fields as needed
|
||||
}
|
||||
|
||||
def get(self, request):
|
||||
date = request.GET.get("date")
|
||||
# date = datetime.now().date()
|
||||
|
||||
if not date:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors="Date parameter is missing")
|
||||
|
||||
try:
|
||||
# Convert the date string to a datetime object
|
||||
date_obj = datetime.strptime(date, "%Y-%m-%d").date()
|
||||
except ValueError:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors="Invalid date format")
|
||||
|
||||
# Define prefetch related queries for filtering the record of paticular date of all related models
|
||||
meal_records_prefetch = Prefetch(
|
||||
"meal_principal",
|
||||
queryset=MealRecord.objects.filter(date=date),
|
||||
to_attr="filtered_meal_record",
|
||||
)
|
||||
|
||||
medication_prefetch = Prefetch(
|
||||
"medication_principal",
|
||||
queryset=Medication.objects.filter(date=date),
|
||||
to_attr="filtered_medication",
|
||||
)
|
||||
|
||||
bowel_prefetch = Prefetch(
|
||||
"bowel_principal",
|
||||
queryset=Bowel.objects.filter(date=date),
|
||||
to_attr="filtered_bowel",
|
||||
)
|
||||
|
||||
meal_symptom_prefetch = Prefetch(
|
||||
"meal_symptom_principal",
|
||||
queryset=MealSymptomRecord.objects.filter(date=date),
|
||||
to_attr="filtered_meal_symptom",
|
||||
)
|
||||
|
||||
# Query the IAmPrincipal table of principal with prefetch_related to retrieve related records
|
||||
principal = IAmPrincipal.objects.prefetch_related(
|
||||
meal_records_prefetch,
|
||||
medication_prefetch,
|
||||
bowel_prefetch,
|
||||
meal_symptom_prefetch,
|
||||
).get(id=request.user.id)
|
||||
|
||||
serialized_meal_records = [
|
||||
{"type": "Meal", **self.serialize_record(record)}
|
||||
for record in principal.filtered_meal_record
|
||||
]
|
||||
|
||||
serialized_medication = [
|
||||
{"type": "Medication", **self.serialize_record(record)}
|
||||
for record in principal.filtered_medication
|
||||
]
|
||||
|
||||
serialized_bowel = [
|
||||
{"type": "Bowel Movements", **self.serialize_record(record)}
|
||||
for record in principal.filtered_bowel
|
||||
]
|
||||
|
||||
serialized_symptom = [
|
||||
{"type": "Symptom - Meal", **self.serialize_record(record)}
|
||||
for record in principal.filtered_meal_symptom
|
||||
]
|
||||
|
||||
all_records = (serialized_symptom + serialized_meal_records + serialized_medication + serialized_bowel)
|
||||
|
||||
# all_records_sorted = sorted(all_records, key=lambda x: x["time"], reverse=True)
|
||||
all_records_sorted = sorted(
|
||||
all_records,
|
||||
key=lambda x: x["time"],
|
||||
reverse=True
|
||||
)
|
||||
|
||||
|
||||
return ApiResponse.success(
|
||||
message=constants.SUCCESS, data=all_records_sorted
|
||||
)
|
||||
|
||||
|
||||
class IntoleranceListCreateAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = IntoleranceSerializer
|
||||
model = Intolerance
|
||||
|
||||
def get(self, request):
|
||||
obj = self.model.objects.filter(principal=request.user)
|
||||
serializer = self.serializer_class(obj, many=True)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
print(f"request data for intolerance is {request.data}")
|
||||
|
||||
serializer = self.serializer_class(data=request.data, many=True)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=serializer.errors
|
||||
)
|
||||
|
||||
try:
|
||||
self.model.objects.filter(principal=request.user).delete()
|
||||
instance = serializer.save(principal=request.user)
|
||||
saved_data_serializer = self.serializer_class(instance, many=True)
|
||||
return ApiResponse.success(
|
||||
message=constants.SUCCESS, data=saved_data_serializer.data
|
||||
)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
|
||||
class SymptomsListCreateAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = SymptomsSerializer
|
||||
model = Symptoms
|
||||
|
||||
def get(self, request):
|
||||
obj = self.model.objects.filter(principal=request.user)
|
||||
serializer = self.serializer_class(obj, many=True)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
print(f"request data for Symptoms is {request.data}")
|
||||
|
||||
serializer = self.serializer_class(data=request.data, many=True)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=serializer.errors
|
||||
)
|
||||
|
||||
try:
|
||||
self.model.objects.filter(principal=request.user).delete()
|
||||
instance = serializer.save(principal=request.user)
|
||||
saved_data_serializer = self.serializer_class(instance, many=True)
|
||||
return ApiResponse.success(
|
||||
message=constants.SUCCESS, data=saved_data_serializer.data
|
||||
)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
|
||||
class PastTreatmentListCreateAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = PastTreatmentSerializer
|
||||
model = PastTreatment
|
||||
|
||||
def get(self, request):
|
||||
obj = self.model.objects.filter(principal=request.user)
|
||||
serializer = self.serializer_class(obj, many=True)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
print(f"request data for PastTreatment is {request.data}")
|
||||
|
||||
serializer = self.serializer_class(data=request.data, many=True)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=serializer.errors
|
||||
)
|
||||
|
||||
try:
|
||||
self.model.objects.filter(principal=request.user).delete()
|
||||
instance = serializer.save(principal=request.user)
|
||||
saved_data_serializer = self.serializer_class(instance, many=True)
|
||||
return ApiResponse.success(
|
||||
message=constants.SUCCESS, data=saved_data_serializer.data
|
||||
)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
|
||||
class ChronicConditionListCreateAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = ChronicConditionSerializer
|
||||
model = ChronicCondition
|
||||
|
||||
def get(self, request):
|
||||
obj = self.model.objects.filter(principal=request.user)
|
||||
serializer = self.serializer_class(obj, many=True)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
print(f"request data for PastTreatment is {request.data}")
|
||||
|
||||
serializer = self.serializer_class(data=request.data, many=True)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=serializer.errors
|
||||
)
|
||||
|
||||
try:
|
||||
self.model.objects.filter(principal=request.user).delete()
|
||||
instance = serializer.save(principal=request.user)
|
||||
saved_data_serializer = self.serializer_class(instance, many=True)
|
||||
return ApiResponse.success(
|
||||
message=constants.SUCCESS, data=saved_data_serializer.data
|
||||
)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
|
||||
class MedicationAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = MedicationSerializer
|
||||
model = Medication
|
||||
|
||||
def get_objects(self, pk):
|
||||
try:
|
||||
return self.model.objects.get(pk=pk)
|
||||
except self.model.DoesNotExist:
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND
|
||||
)
|
||||
|
||||
def get(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
serializer = self.serializer_class(obj)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=serializer.errors
|
||||
)
|
||||
|
||||
try:
|
||||
serializer.save(principal=request.user)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_201_CREATED,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
def put(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
serializer = self.serializer_class(obj, data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=serializer.data)
|
||||
|
||||
try:
|
||||
serializer.save()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_201_CREATED,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
def delete(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
try:
|
||||
obj.delete()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
return ApiResponse.success(
|
||||
message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT
|
||||
)
|
||||
|
||||
|
||||
class BowelAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = BowelSerializer
|
||||
model = Bowel
|
||||
|
||||
def get_objects(self, pk):
|
||||
try:
|
||||
return self.model.objects.get(pk=pk)
|
||||
except self.model.DoesNotExist:
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND
|
||||
)
|
||||
|
||||
def get(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
serializer = self.serializer_class(obj)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=serializer.errors
|
||||
)
|
||||
try:
|
||||
serializer.save(principal=request.user)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_201_CREATED,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
def put(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
serializer = self.serializer_class(obj, data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=serializer.data)
|
||||
|
||||
try:
|
||||
serializer.save()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_201_CREATED,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
def delete(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
try:
|
||||
obj.delete()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
return ApiResponse.success(
|
||||
message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT
|
||||
)
|
||||
|
||||
|
||||
class MealSymptomAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = MealSymptomRecordSerializer
|
||||
model = MealSymptomRecord
|
||||
|
||||
def get_objects(self, pk):
|
||||
try:
|
||||
return self.model.objects.get(pk=pk)
|
||||
except self.model.DoesNotExist:
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND
|
||||
)
|
||||
|
||||
def get(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
serializer = self.serializer_class(obj)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=serializer.errors
|
||||
)
|
||||
try:
|
||||
serializer.save(principal=request.user)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_201_CREATED,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
def put(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
serializer = self.serializer_class(obj, data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=serializer.data)
|
||||
|
||||
try:
|
||||
serializer.save()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_201_CREATED,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
def delete(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
try:
|
||||
obj.delete()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
return ApiResponse.success(
|
||||
message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT
|
||||
)
|
||||
|
||||
|
||||
class MealAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = MealRecordSerializer
|
||||
model = MealRecord
|
||||
|
||||
def get_objects(self, pk):
|
||||
try:
|
||||
return self.model.objects.get(pk=pk)
|
||||
except self.model.DoesNotExist:
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND
|
||||
)
|
||||
|
||||
def get(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
serializer = self.serializer_class(obj)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(
|
||||
message=constants.FAILURE, errors=serializer.errors
|
||||
)
|
||||
try:
|
||||
serializer.save(principal=request.user)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_201_CREATED,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
def put(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
serializer = self.serializer_class(obj, data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=serializer.data)
|
||||
|
||||
try:
|
||||
serializer.save()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_201_CREATED,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
def delete(self, request, pk):
|
||||
obj = self.get_objects(pk)
|
||||
|
||||
if isinstance(obj, Response):
|
||||
return obj
|
||||
|
||||
try:
|
||||
obj.delete()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
return ApiResponse.success(
|
||||
message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT
|
||||
)
|
||||
6
module_activity/apps.py
Normal file
6
module_activity/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ModuleActivityConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'module_activity'
|
||||
333
module_activity/migrations/0001_initial.py
Normal file
333
module_activity/migrations/0001_initial.py
Normal file
@@ -0,0 +1,333 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-16 17:40
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BeverageRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('beverage_type', models.CharField(max_length=100)),
|
||||
('glass_type', models.CharField(max_length=100)),
|
||||
('glass_count', models.IntegerField()),
|
||||
('quantity', models.IntegerField()),
|
||||
('quantity_measure', models.CharField(max_length=100)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'beverage_record',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FoodIngredientRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'food_ingredient_record',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FoodRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('quantity', models.IntegerField()),
|
||||
],
|
||||
options={
|
||||
'db_table': 'food_record',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MealRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('meal_date', models.DateField()),
|
||||
('meal_time', models.TimeField()),
|
||||
],
|
||||
options={
|
||||
'db_table': 'meal_record',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Medicine',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('quantity', models.IntegerField(default=0)),
|
||||
('type', models.CharField(blank=True, max_length=100, null=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'medicine',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SymptomTypeAfterMeal',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'symptom_type_after_meal',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SymptomTypeBeforeMeal',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'symptom_type_before_meal',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Bowel',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('bowel_date', models.DateField()),
|
||||
('bowel_time', models.TimeField()),
|
||||
('stool_type', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('duration', models.DurationField(blank=True, null=True)),
|
||||
('completeness_of_evacuation', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('urgency', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('smellness', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('pain_level', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('volume', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('color', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('excessive_flatulence', models.BooleanField(default=False)),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bowel_principal', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'bowel',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ChronicCondition',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('duration', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chronic_principal', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'chronic_condition',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Intolerance',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('duration', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='intolerance_principal', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'intolerance',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MealRecordBeverageRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('beverage_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.beveragerecord')),
|
||||
('meal_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.mealrecord')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'meal_record_beverage_record',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mealrecord',
|
||||
name='beverage_records',
|
||||
field=models.ManyToManyField(through='module_activity.MealRecordBeverageRecord', to='module_activity.beveragerecord'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MealRecordFoodIngredientRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('food_ingredient_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.foodingredientrecord')),
|
||||
('meal_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.mealrecord')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'meal_record_food_ingredient_record',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mealrecord',
|
||||
name='food_ingredient_records',
|
||||
field=models.ManyToManyField(through='module_activity.MealRecordFoodIngredientRecord', to='module_activity.foodingredientrecord'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MealRecordFoodRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('food_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.foodrecord')),
|
||||
('meal_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.mealrecord')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'meal_record_food_record',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mealrecord',
|
||||
name='food_records',
|
||||
field=models.ManyToManyField(through='module_activity.MealRecordFoodRecord', to='module_activity.foodrecord'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MealSymptomRecord',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('symptoms_date', models.DateField()),
|
||||
('symptoms_time', models.TimeField()),
|
||||
('symptoms_description', models.TextField(blank=True, null=True)),
|
||||
('interval', models.DurationField()),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='meal_symptom_principal', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'meal_symptom_record',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Medication',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('date', models.DateField()),
|
||||
('time', models.TimeField()),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='medication_principal', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'medication',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MedicationMedicine',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('medication', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='medication_medicines', to='module_activity.medication')),
|
||||
('medicine', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='medication_medicines', to='module_activity.medicine')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'medication_medicine',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='medication',
|
||||
name='medicines',
|
||||
field=models.ManyToManyField(related_name='medications', through='module_activity.MedicationMedicine', to='module_activity.medicine'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PastTreatment',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('duration', models.DateField()),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pasttreatment_principal', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'past_treatment',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PrincipalHealthData',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('gastrointestinal_health', models.CharField(blank=True, help_text='Describe your gastrointestinal health (e.g., best, average, poor, etc.)', max_length=255, null=True, verbose_name='Gastrointestinal Health')),
|
||||
('exercise_frequency', models.CharField(blank=True, help_text='Describe your exercise frequency (e.g., Less than equal to 3 days, 2 days, Greater than 3 days, etc.)', max_length=255, null=True, verbose_name='Exercise Frequency')),
|
||||
('sleep_duration', models.CharField(blank=True, help_text='Enter your average sleep duration in hours per night.', max_length=255, null=True, verbose_name='Sleep Duration (hours)')),
|
||||
('ethenicity', models.CharField(blank=True, help_text='Select your ethnicity.', max_length=255, null=True, verbose_name='Ethnicity')),
|
||||
('weight', models.DecimalField(blank=True, decimal_places=2, help_text='Enter your weight in kilograms.', max_digits=5, null=True, verbose_name='Weight (kg)')),
|
||||
('height', models.DecimalField(blank=True, decimal_places=2, help_text='Enter your height in centimeters.', max_digits=4, null=True, verbose_name='Height (cm)')),
|
||||
('eat_frequency', models.CharField(blank=True, help_text='Describe your eating frequency (e.g., 3 meals per day, frequent snacking, etc.)', max_length=255, null=True, verbose_name='Eating Frequency')),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='health_data_principal', to=settings.AUTH_USER_MODEL, verbose_name='Principal')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'princpal_health_data',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Symptoms',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('duration', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='symptoms_principal', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'symptoms',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SymptomRecordAfterMeal',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('symptom_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.mealsymptomrecord')),
|
||||
('symptom_type_after_meal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.symptomtypeaftermeal')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'symptom_record_after_meal',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mealsymptomrecord',
|
||||
name='symptoms_after_meal',
|
||||
field=models.ManyToManyField(through='module_activity.SymptomRecordAfterMeal', to='module_activity.symptomtypeaftermeal'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SymptomRecordBeforeMeal',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('symptom_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.mealsymptomrecord')),
|
||||
('symptom_type_before_meal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='module_activity.symptomtypebeforemeal')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'symptom_record_before_meal',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mealsymptomrecord',
|
||||
name='symptoms_before_meal',
|
||||
field=models.ManyToManyField(through='module_activity.SymptomRecordBeforeMeal', to='module_activity.symptomtypebeforemeal'),
|
||||
),
|
||||
]
|
||||
22
module_activity/migrations/0002_mealrecord_principal.py
Normal file
22
module_activity/migrations/0002_mealrecord_principal.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-16 17:42
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_activity', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mealrecord',
|
||||
name='principal',
|
||||
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='meal_principal', to=settings.AUTH_USER_MODEL),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-17 06:29
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_activity', '0002_mealrecord_principal'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='principalhealthdata',
|
||||
name='height',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, help_text='Enter your height in centimeters.', max_digits=6, null=True, verbose_name='Height (cm)'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-17 07:12
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_activity', '0003_alter_principalhealthdata_height'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='principalhealthdata',
|
||||
name='principal',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='health_data_principal', to=settings.AUTH_USER_MODEL, verbose_name='Principal'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,43 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-17 14:44
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_activity', '0004_alter_principalhealthdata_principal'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='bowel',
|
||||
old_name='bowel_date',
|
||||
new_name='date',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='bowel',
|
||||
old_name='bowel_time',
|
||||
new_name='time',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='mealrecord',
|
||||
old_name='meal_date',
|
||||
new_name='date',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='mealrecord',
|
||||
old_name='meal_time',
|
||||
new_name='time',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='mealsymptomrecord',
|
||||
old_name='symptoms_date',
|
||||
new_name='date',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='mealsymptomrecord',
|
||||
old_name='symptoms_time',
|
||||
new_name='time',
|
||||
),
|
||||
]
|
||||
18
module_activity/migrations/0006_mealrecord_meal_type.py
Normal file
18
module_activity/migrations/0006_mealrecord_meal_type.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-21 13:18
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_activity', '0005_rename_bowel_date_bowel_date_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mealrecord',
|
||||
name='meal_type',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
]
|
||||
0
module_activity/migrations/__init__.py
Normal file
0
module_activity/migrations/__init__.py
Normal file
299
module_activity/models.py
Normal file
299
module_activity/models.py
Normal file
@@ -0,0 +1,299 @@
|
||||
from django.db import models
|
||||
from module_iam.models import BaseModel, IAmPrincipal
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class PrincipalHealthData(BaseModel):
|
||||
principal = models.OneToOneField(
|
||||
IAmPrincipal,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="health_data_principal",
|
||||
verbose_name="Principal",
|
||||
db_index=True,
|
||||
)
|
||||
# Gastrointestinal health (choices if applicable)
|
||||
gastrointestinal_health = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Gastrointestinal Health",
|
||||
help_text="Describe your gastrointestinal health (e.g., best, average, poor, etc.)",
|
||||
)
|
||||
|
||||
# Exercise frequency (choices if applicable)
|
||||
exercise_frequency = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Exercise Frequency",
|
||||
help_text="Describe your exercise frequency (e.g., Less than equal to 3 days, 2 days, Greater than 3 days, etc.)",
|
||||
)
|
||||
|
||||
sleep_duration = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Sleep Duration (hours)",
|
||||
help_text="Enter your average sleep duration in hours per night.",
|
||||
)
|
||||
|
||||
# Ethnicity (choices if applicable)
|
||||
ethenicity = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Ethnicity",
|
||||
help_text="Select your ethnicity.",
|
||||
)
|
||||
|
||||
weight = models.DecimalField(
|
||||
max_digits=5,
|
||||
decimal_places=2,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Weight (kg)",
|
||||
help_text="Enter your weight in kilograms.",
|
||||
)
|
||||
|
||||
height = models.DecimalField(
|
||||
max_digits=6,
|
||||
decimal_places=2,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Height (cm)",
|
||||
help_text="Enter your height in centimeters.",
|
||||
)
|
||||
|
||||
# Eat frequency (choices if applicable)
|
||||
eat_frequency = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Eating Frequency",
|
||||
help_text="Describe your eating frequency (e.g., 3 meals per day, frequent snacking, etc.)",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "princpal_health_data"
|
||||
|
||||
def __str__(self):
|
||||
return f"Health Data for {self.principal}"
|
||||
|
||||
|
||||
class Intolerance(BaseModel):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="intolerance_principal",
|
||||
db_index=True,
|
||||
)
|
||||
name = models.CharField(max_length=255, blank=True, null=True)
|
||||
duration = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "intolerance"
|
||||
|
||||
def __str__(self):
|
||||
return f"intolerance of {self.principal}"
|
||||
|
||||
|
||||
class Symptoms(BaseModel):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="symptoms_principal",
|
||||
db_index=True,
|
||||
)
|
||||
name = models.CharField(max_length=255, blank=True, null=True)
|
||||
duration = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "symptoms"
|
||||
|
||||
def __str__(self):
|
||||
return f"symptoms of {self.principal}"
|
||||
|
||||
|
||||
class PastTreatment(BaseModel):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="pasttreatment_principal",
|
||||
db_index=True,
|
||||
)
|
||||
name = models.CharField(max_length=255, blank=True, null=True)
|
||||
duration = models.DateField()
|
||||
|
||||
class Meta:
|
||||
db_table = "past_treatment"
|
||||
|
||||
def __str__(self):
|
||||
return f"past treatment of {self.principal}"
|
||||
|
||||
|
||||
class ChronicCondition(BaseModel):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="chronic_principal",
|
||||
db_index=True,
|
||||
)
|
||||
name = models.CharField(max_length=255, blank=True, null=True)
|
||||
duration = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "chronic_condition"
|
||||
|
||||
def __str__(self):
|
||||
return f"chronic condition of {self.principal}"
|
||||
|
||||
|
||||
class FoodIngredientRecord(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
class Meta:
|
||||
db_table = "food_ingredient_record"
|
||||
|
||||
class FoodRecord(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
quantity = models.IntegerField()
|
||||
|
||||
class Meta:
|
||||
db_table = "food_record"
|
||||
|
||||
class BeverageRecord(models.Model):
|
||||
beverage_type = models.CharField(max_length=100)
|
||||
glass_type = models.CharField(max_length=100)
|
||||
glass_count = models.IntegerField()
|
||||
quantity = models.IntegerField()
|
||||
quantity_measure = models.CharField(max_length=100)
|
||||
|
||||
class Meta:
|
||||
db_table = "beverage_record"
|
||||
|
||||
class MealRecord(models.Model):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal, related_name="meal_principal", on_delete=models.CASCADE
|
||||
)
|
||||
date = models.DateField()
|
||||
time = models.TimeField()
|
||||
meal_type = models.CharField(max_length=100, blank=True, null=True)
|
||||
food_records = models.ManyToManyField(FoodRecord, through='MealRecordFoodRecord')
|
||||
beverage_records = models.ManyToManyField(BeverageRecord, through='MealRecordBeverageRecord')
|
||||
food_ingredient_records = models.ManyToManyField(FoodIngredientRecord, through='MealRecordFoodIngredientRecord')
|
||||
|
||||
class Meta:
|
||||
db_table = "meal_record"
|
||||
|
||||
class MealRecordFoodRecord(models.Model):
|
||||
meal_record = models.ForeignKey(MealRecord, on_delete=models.CASCADE)
|
||||
food_record = models.ForeignKey(FoodRecord, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
db_table = "meal_record_food_record"
|
||||
|
||||
class MealRecordBeverageRecord(models.Model):
|
||||
meal_record = models.ForeignKey(MealRecord, on_delete=models.CASCADE)
|
||||
beverage_record = models.ForeignKey(BeverageRecord, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
db_table = "meal_record_beverage_record"
|
||||
|
||||
class MealRecordFoodIngredientRecord(models.Model):
|
||||
meal_record = models.ForeignKey(MealRecord, on_delete=models.CASCADE)
|
||||
food_ingredient_record = models.ForeignKey(FoodIngredientRecord, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
db_table = "meal_record_food_ingredient_record"
|
||||
|
||||
class Medicine(models.Model):
|
||||
name = models.CharField(max_length=255, blank=True, null=True)
|
||||
quantity = models.IntegerField(default=0)
|
||||
type = models.CharField(max_length=100, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "medicine"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} Medicine"
|
||||
|
||||
class Medication(models.Model):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal, related_name="medication_principal", on_delete=models.CASCADE
|
||||
)
|
||||
date = models.DateField()
|
||||
time = models.TimeField()
|
||||
medicines = models.ManyToManyField(
|
||||
Medicine,
|
||||
through="MedicationMedicine",
|
||||
related_name="medications"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "medication"
|
||||
|
||||
class MedicationMedicine(models.Model):
|
||||
medication = models.ForeignKey(Medication, related_name="medication_medicines", on_delete=models.CASCADE)
|
||||
medicine = models.ForeignKey(Medicine, related_name="medication_medicines", on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
db_table = "medication_medicine"
|
||||
|
||||
|
||||
class Bowel(models.Model):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal, related_name="bowel_principal", on_delete=models.CASCADE
|
||||
)
|
||||
date = models.DateField()
|
||||
time = models.TimeField()
|
||||
stool_type = models.CharField(max_length=100, blank=True, null=True)
|
||||
duration = models.DurationField(blank=True, null=True)
|
||||
completeness_of_evacuation = models.CharField(max_length=100, blank=True, null=True)
|
||||
urgency = models.CharField(max_length=100, blank=True, null=True)
|
||||
smellness = models.CharField(max_length=100, blank=True, null=True)
|
||||
pain_level = models.CharField(max_length=100, blank=True, null=True)
|
||||
volume = models.CharField(max_length=100, blank=True, null=True)
|
||||
color = models.CharField(max_length=100, blank=True, null=True)
|
||||
excessive_flatulence = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
db_table = "bowel"
|
||||
|
||||
|
||||
class SymptomTypeBeforeMeal(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
class Meta:
|
||||
db_table = "symptom_type_before_meal"
|
||||
|
||||
class SymptomTypeAfterMeal(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
class Meta:
|
||||
db_table = "symptom_type_after_meal"
|
||||
|
||||
class MealSymptomRecord(models.Model):
|
||||
principal = models.ForeignKey(IAmPrincipal, related_name="meal_symptom_principal", on_delete=models.CASCADE)
|
||||
date = models.DateField()
|
||||
time = models.TimeField()
|
||||
symptoms_description = models.TextField(blank=True, null=True)
|
||||
interval = models.DurationField()
|
||||
symptoms_before_meal = models.ManyToManyField(SymptomTypeBeforeMeal, through='SymptomRecordBeforeMeal')
|
||||
symptoms_after_meal = models.ManyToManyField(SymptomTypeAfterMeal, through='SymptomRecordAfterMeal')
|
||||
|
||||
class Meta:
|
||||
db_table = "meal_symptom_record"
|
||||
|
||||
class SymptomRecordBeforeMeal(models.Model):
|
||||
symptom_record = models.ForeignKey(MealSymptomRecord, on_delete=models.CASCADE)
|
||||
symptom_type_before_meal = models.ForeignKey(SymptomTypeBeforeMeal, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
db_table = "symptom_record_before_meal"
|
||||
|
||||
class SymptomRecordAfterMeal(models.Model):
|
||||
symptom_record = models.ForeignKey(MealSymptomRecord, on_delete=models.CASCADE)
|
||||
symptom_type_after_meal = models.ForeignKey(SymptomTypeAfterMeal, on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
db_table = "symptom_record_after_meal"
|
||||
3
module_activity/tests.py
Normal file
3
module_activity/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
31
module_activity/urls.py
Normal file
31
module_activity/urls.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = "module_activity"
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
|
||||
path('intolerance/<int:principal_id>/', views.IntoleranceView.as_view(), name='intolerance'),
|
||||
path('intolerance/list/<int:principal_id>/', views.IntoleranceListJson.as_view(), name='intolerance_list'),
|
||||
path('intolerance/action/', views.IntoleranceActionView.as_view(), name='intolerance_action'),
|
||||
|
||||
path('symptoms/<int:principal_id>/', views.SymptomsView.as_view(), name='symptoms'),
|
||||
path('symptoms/list/<int:principal_id>/', views.SymptomsListJson.as_view(), name='symptoms_list'),
|
||||
path('symptoms/action/', views.SymptomsActionView.as_view(), name='symptoms_action'),
|
||||
|
||||
path('past_treatment/<int:principal_id>/', views.PastTreatmentView.as_view(), name='past_treatment'),
|
||||
path('past_treatment/list/<int:principal_id>/', views.PastTreatmentListJson.as_view(), name='past_treatment_list'),
|
||||
path('past_treatment/action/', views.PastTreatmentActionView.as_view(), name='past_treatment_action'),
|
||||
|
||||
path('chronic_condition/<int:principal_id>/', views.ChronicConditionView.as_view(), name='chronic_condition'),
|
||||
path('chronic_condition/list/<int:principal_id>/', views.ChronicConditionListJson.as_view(), name='chronic_condition_list'),
|
||||
path('chronic_condition/action/', views.ChronicConditionActionView.as_view(), name='chronic_condition_action'),
|
||||
|
||||
path('user_activity/<int:principal_id>/', views.UserActivityRecordView.as_view(), name='activity_list'),
|
||||
path('meal_detail/<int:pk>/', views.MealDetialView.as_view(), name='meal_detail'),
|
||||
path('medication_detail/<int:pk>/', views.MedicationDetailView.as_view(), name='medication_detail'),
|
||||
path('bowel_detail/<int:pk>/', views.BowelDetailView.as_view(), name='bowel_detail'),
|
||||
path('meal_symptom_detail/<int:pk>/', views.MealSymptomDetailView.as_view(), name='meal_symptom_detail'),
|
||||
|
||||
]
|
||||
247
module_activity/views.py
Normal file
247
module_activity/views.py
Normal file
@@ -0,0 +1,247 @@
|
||||
import logging
|
||||
|
||||
from datetime import datetime
|
||||
from django.shortcuts import get_object_or_404, render, redirect
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse_lazy
|
||||
from django.views import generic
|
||||
from django.db.models import Q, Prefetch
|
||||
from .models import Intolerance, Symptoms, ChronicCondition, PastTreatment, MealRecord, Bowel, MealSymptomRecord, Medication
|
||||
from django_datatables_view.base_datatable_view import BaseDatatableView
|
||||
from module_iam.models import IAmPrincipal
|
||||
from module_project import constants
|
||||
from module_project.utils import JsonResponseUtil
|
||||
from django.http import JsonResponse
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class BaseView(generic.TemplateView):
|
||||
page_name = None
|
||||
resource = None
|
||||
action = None
|
||||
template_name = None
|
||||
model = Intolerance
|
||||
context_objext_name = "obj"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
context["principal_id"] = self.kwargs.get('principal_id')
|
||||
return context
|
||||
|
||||
class BaseListJson(BaseDatatableView):
|
||||
model = Intolerance
|
||||
columns = ["id", "name", "duration", "active", "deleted"]
|
||||
order_columns = ["id", "name", "duration", "active", "deleted"]
|
||||
|
||||
def get_initial_queryset(self):
|
||||
principal_id = self.kwargs.get('principal_id')
|
||||
deleted_flag = self.request.GET.get('deleted_flag', None)
|
||||
|
||||
if deleted_flag == 'true':
|
||||
# Show only deleted records
|
||||
return self.model.objects.filter(principal=principal_id, deleted=True)
|
||||
else:
|
||||
# Show all records except deleted ones
|
||||
return self.model.objects.filter(principal=principal_id, deleted=False)
|
||||
|
||||
def filter_queryset(self, qs):
|
||||
search_value = self.request.GET.get("search[value]", None)
|
||||
if search_value:
|
||||
qs = qs.filter(
|
||||
Q(name__icontains=search_value) |
|
||||
Q(duration__icontains=search_value)
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
class BaseActionView(generic.View):
|
||||
model = Intolerance
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
action = request.POST.get('action') # 'archive', 'active', or 'unarchive'
|
||||
ids = request.POST.getlist('ids[]') # List of user IDs to perform action on
|
||||
active = request.POST.get('active')
|
||||
print(f"arhive action {action} and id is {ids} and active data is {active}")
|
||||
if action == 'archive':
|
||||
# Update 'deleted' field to True for the selected users
|
||||
self.model.objects.filter(id__in=ids).update(deleted=True, active=False)
|
||||
message = 'Record archived successfully.'
|
||||
elif action == 'active':
|
||||
# Update 'active' field to True for the selected users
|
||||
self.model.objects.filter(id__in=ids).update(active=active.capitalize())
|
||||
message = 'Record activated successfully.'
|
||||
elif action == 'unarchive':
|
||||
# Update 'deleted' field to False for the selected users
|
||||
self.model.objects.filter(id__in=ids).update(deleted=False)
|
||||
message = 'Record unarchived successfully.'
|
||||
else:
|
||||
return JsonResponseUtil.error(message="Invalid Action")
|
||||
|
||||
return JsonResponseUtil.success(message=message)
|
||||
|
||||
|
||||
class IntoleranceView(BaseView):
|
||||
model = Intolerance
|
||||
template_name = "module_activity/intolerance_list.html"
|
||||
|
||||
class IntoleranceListJson(BaseListJson):
|
||||
model = Intolerance
|
||||
|
||||
class IntoleranceActionView(BaseActionView):
|
||||
model = Intolerance
|
||||
|
||||
class SymptomsView(BaseView):
|
||||
model = Symptoms
|
||||
template_name = "module_activity/symptoms_list.html"
|
||||
|
||||
class SymptomsListJson(BaseListJson):
|
||||
model = Symptoms
|
||||
|
||||
class SymptomsActionView(BaseActionView):
|
||||
model = Symptoms
|
||||
|
||||
class PastTreatmentView(BaseView):
|
||||
model = PastTreatment
|
||||
template_name = "module_activity/past_treatment_list.html"
|
||||
|
||||
class PastTreatmentListJson(BaseListJson):
|
||||
model = PastTreatment
|
||||
|
||||
class PastTreatmentActionView(BaseActionView):
|
||||
model = PastTreatment
|
||||
|
||||
class ChronicConditionView(BaseView):
|
||||
model = ChronicCondition
|
||||
template_name = "module_activity/chronic_conditon_list.html"
|
||||
|
||||
class ChronicConditionListJson(BaseListJson):
|
||||
model = ChronicCondition
|
||||
|
||||
class ChronicConditionActionView(BaseActionView):
|
||||
model = ChronicCondition
|
||||
|
||||
class UserActivityRecordView(generic.View):
|
||||
def serialize_record(self, record):
|
||||
time_obj = datetime.strptime(str(record.time), '%H:%M:%S')
|
||||
return {
|
||||
"id": record.id,
|
||||
"date": record.date,
|
||||
"time": time_obj.strftime('%I:%M %p'),
|
||||
}
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
try:
|
||||
principal_id = self.kwargs.get('principal_id')
|
||||
date = request.GET.get("date")
|
||||
print(f"principal_id is {principal_id} data is {date} and type is {type(date)}")
|
||||
if not date:
|
||||
return JsonResponseUtil.error(message="Date parameter is missing")
|
||||
|
||||
try:
|
||||
date_obj = datetime.strptime(date, "%Y-%m-%d").date()
|
||||
except ValueError:
|
||||
return JsonResponseUtil.error(message="Invalid date format")
|
||||
|
||||
# Retrieve data from different models
|
||||
meal_records = MealRecord.objects.filter(principal=principal_id, date=date_obj)
|
||||
medication_records = Medication.objects.filter(principal=principal_id, date=date_obj)
|
||||
bowel_records = Bowel.objects.filter(principal=principal_id, date=date_obj)
|
||||
meal_symptom_records = MealSymptomRecord.objects.filter(principal=principal_id, date=date_obj)
|
||||
print(f"==================meal record {meal_records}")
|
||||
# Prepare combined results
|
||||
data = []
|
||||
for record in meal_records:
|
||||
data.append({"type": "Meal", **self.serialize_record(record)})
|
||||
|
||||
for record in medication_records:
|
||||
data.append({"type": "Medication", **self.serialize_record(record)})
|
||||
|
||||
for record in bowel_records:
|
||||
data.append({"type": "Bowel", **self.serialize_record(record)})
|
||||
|
||||
for record in meal_symptom_records:
|
||||
data.append({"type": "Symptom", **self.serialize_record(record)})
|
||||
|
||||
all_records_sorted = sorted(data, key=lambda x: x["time"], reverse=True)
|
||||
|
||||
response_data = {
|
||||
"recordsTotal": len(all_records_sorted),
|
||||
"recordsFiltered": len(all_records_sorted),
|
||||
"data": all_records_sorted,
|
||||
}
|
||||
|
||||
return JsonResponse(response_data)
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponseUtil.error(message="Something went wrong", errors=str(e))
|
||||
|
||||
class MealDetialView(generic.TemplateView):
|
||||
template_name = "module_activity/meal_detail.html"
|
||||
model = MealRecord
|
||||
|
||||
def get_record(self):
|
||||
id = self.kwargs.get('pk')
|
||||
meal_record = get_object_or_404(
|
||||
self.model.objects.prefetch_related(
|
||||
'food_records', 'beverage_records', 'food_ingredient_records'
|
||||
),
|
||||
id=id
|
||||
)
|
||||
return meal_record
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['obj'] = self.get_record()
|
||||
return context
|
||||
|
||||
|
||||
class MedicationDetailView(generic.TemplateView):
|
||||
template_name = "module_activity/medication_detail.html"
|
||||
model = Medication
|
||||
|
||||
def get_record(self):
|
||||
id = self.kwargs.get('pk')
|
||||
obj = get_object_or_404(
|
||||
self.model.objects.prefetch_related('medicines'),
|
||||
id=id
|
||||
)
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['obj'] = self.get_record()
|
||||
return context
|
||||
|
||||
|
||||
class BowelDetailView(generic.TemplateView):
|
||||
template_name = "module_activity/bowel_detail.html"
|
||||
model = Bowel
|
||||
|
||||
def get_record(self):
|
||||
id = self.kwargs.get('pk')
|
||||
obj = get_object_or_404(self.model, id=id)
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['obj'] = self.get_record()
|
||||
return context
|
||||
|
||||
class MealSymptomDetailView(generic.TemplateView):
|
||||
template_name = "module_activity/meal_symptom_details.html"
|
||||
model = MealSymptomRecord
|
||||
|
||||
def get_record(self):
|
||||
pk = self.kwargs.get('pk')
|
||||
obj = get_object_or_404(
|
||||
MealSymptomRecord.objects.prefetch_related('symptoms_before_meal', 'symptoms_after_meal'),
|
||||
id=pk
|
||||
)
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['obj'] = self.get_record()
|
||||
return context
|
||||
0
module_auth/__init__.py
Normal file
0
module_auth/__init__.py
Normal file
3
module_auth/admin.py
Normal file
3
module_auth/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
103
module_auth/api/serializers.py
Normal file
103
module_auth/api/serializers.py
Normal file
@@ -0,0 +1,103 @@
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from rest_framework import serializers
|
||||
from module_iam.models import IAmPrincipal
|
||||
from module_project import constants
|
||||
from django.contrib.auth import authenticate
|
||||
|
||||
# class BasePasswordSerializer(serializers.Serializer):
|
||||
# confirm_password = serializers.CharField(write_only=True, required=True)
|
||||
|
||||
# def validate(self, attrs):
|
||||
# password = attrs.get("password")
|
||||
# confirm_password = attrs.pop("confirm_password")
|
||||
# if password != confirm_password:
|
||||
# raise serializers.ValidationError({'password': constants.PASSWORD_NOT_MATCH})
|
||||
# return super().validate(attrs)
|
||||
|
||||
# def update(self, instance, validate_data):
|
||||
# new_password = validate_data.get("password")
|
||||
# if new_password:
|
||||
# instance.password = make_password(new_password)
|
||||
# instance.save()
|
||||
# return instance
|
||||
|
||||
class RegistrationSerializer(serializers.ModelSerializer):
|
||||
password = serializers.CharField(write_only=True, required=True)
|
||||
confirm_password = serializers.CharField(write_only=True, required=True)
|
||||
|
||||
class Meta:
|
||||
model = IAmPrincipal
|
||||
fields = [
|
||||
"first_name",
|
||||
"email",
|
||||
"phone_no",
|
||||
"password",
|
||||
"confirm_password",
|
||||
"player_id",
|
||||
]
|
||||
|
||||
def validate(self, attrs):
|
||||
email = attrs.get("email")
|
||||
phone_no = attrs.get("phone_no")
|
||||
password = attrs.get("password")
|
||||
confirm_password = attrs.get("confirm_password")
|
||||
|
||||
if password != confirm_password:
|
||||
raise serializers.ValidationError({'password': constants.PASSWORD_NOT_MATCH})
|
||||
|
||||
obj = self.Meta.model.objects.filter(email=email).first()
|
||||
|
||||
if obj:
|
||||
raise serializers.ValidationError({"email": constants.EMAIL_EXISTS})
|
||||
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
del validated_data['confirm_password']
|
||||
validated_data["username"] = validated_data["email"]
|
||||
validated_data["password"] = make_password(validated_data["password"])
|
||||
principal = self.Meta.model.objects.create(**validated_data)
|
||||
return principal
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
# update prinicpal instance fiedls based on the validation data
|
||||
instance.first_name = validated_data.get("first_name", instance.first_name)
|
||||
instance.email = validated_data.get("email", instance.email)
|
||||
instance.username = validated_data.get("email", instance.email)
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
|
||||
class LoginSerializer(serializers.Serializer):
|
||||
email = serializers.EmailField(write_only=True, required=True)
|
||||
password = serializers.CharField(write_only=True, required=True)
|
||||
player_id = serializers.CharField(write_only=True, required=True)
|
||||
|
||||
class OtpVerificationSerializer(serializers.Serializer):
|
||||
email = serializers.EmailField(write_only=True, required=True)
|
||||
otp = serializers.IntegerField(write_only=True, required=True)
|
||||
|
||||
class PasswordResetSerializer(serializers.ModelSerializer):
|
||||
password = serializers.CharField(write_only=True, required=True)
|
||||
confirm_password = serializers.CharField(write_only=True, required=True)
|
||||
|
||||
class Meta:
|
||||
model = IAmPrincipal
|
||||
fields = [
|
||||
"password",
|
||||
"confirm_password"
|
||||
]
|
||||
|
||||
def validate(self, attrs):
|
||||
password = attrs.get("password")
|
||||
confirm_password = attrs.get("confirm_password")
|
||||
if password != confirm_password:
|
||||
raise serializers.ValidationError({'password': constants.PASSWORD_NOT_MATCH})
|
||||
return super().validate(attrs)
|
||||
|
||||
def update(self, instance, validate_data):
|
||||
new_password = validate_data.get("password")
|
||||
if new_password:
|
||||
instance.password = make_password(new_password)
|
||||
instance.save()
|
||||
return instance
|
||||
16
module_auth/api/urls.py
Normal file
16
module_auth/api/urls.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
from rest_framework_simplejwt.views import TokenRefreshView
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
||||
path("signup/", views.RegistrationView.as_view()),
|
||||
path("login/", views.LoginView.as_view()),
|
||||
|
||||
path("request-otp/", views.OtpRequestView.as_view()),
|
||||
path("verify-otp/", views.OTPVerificationView.as_view()),
|
||||
path("forget-password/", views.ForgetPasswordView.as_view()),
|
||||
|
||||
# path("profile/", views.Profile)
|
||||
]
|
||||
183
module_auth/api/utils.py
Normal file
183
module_auth/api/utils.py
Normal file
@@ -0,0 +1,183 @@
|
||||
from typing import Optional
|
||||
from module_project import constants
|
||||
from module_project.utils import ApiResponse
|
||||
from module_iam.models import IAmPrincipal, IAmPrincipalOtp
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
from django.core.exceptions import ValidationError
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def generate_token_and_user_data(principal):
|
||||
"""
|
||||
Generate a token and user data based on an 'IAmPrincipal' object.
|
||||
|
||||
Args:
|
||||
principal (IAmPrincipal): The user object.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing token data and user information.
|
||||
"""
|
||||
refresh = RefreshToken.for_user(principal)
|
||||
data = {
|
||||
"access": str(refresh.access_token),
|
||||
"refresh": str(refresh),
|
||||
"first_name": principal.first_name,
|
||||
"phone_no": str(principal.phone_no),
|
||||
"complete": principal.register_complete,
|
||||
}
|
||||
return data
|
||||
|
||||
class AuthService:
|
||||
"""
|
||||
Provides authentication services for IAmPrincipal users.
|
||||
"""
|
||||
|
||||
def __init__(self, principal_model, otp_model=None):
|
||||
self.principal_model = principal_model
|
||||
self.otp_model = otp_model
|
||||
|
||||
def authenticate(self, principal_id: str, otp: Optional[str] = None, password: Optional[str] = None) -> None:
|
||||
"""
|
||||
Authenticates a principal using OTP and/or password.
|
||||
|
||||
Raises:
|
||||
AuthenticationError: If authentication fails.
|
||||
"""
|
||||
try:
|
||||
principal = self.get_principal(principal_id)
|
||||
self.validate_principal_status(principal)
|
||||
self.validate_credentials_provided(otp, password)
|
||||
|
||||
if otp:
|
||||
self.authenticate_with_otp(principal, otp)
|
||||
else:
|
||||
self.authenticate_with_password(principal, password)
|
||||
except ValidationError as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logger.error(f"Authentication failed for principal {principal_id}: {str(e)}")
|
||||
raise ValidationError("Authentication failed") from e
|
||||
|
||||
def get_principal(self, principal_id: str) -> IAmPrincipal:
|
||||
"""Retrieves a principal instance by ID."""
|
||||
try:
|
||||
return self.principal_model.objects.get(pk=principal_id)
|
||||
except self.principal_model.DoesNotExist:
|
||||
raise ValidationError("Invalid principal ID")
|
||||
|
||||
def get_principal_by_email(self, email: str):
|
||||
"""Retrieves a principal instance by email."""
|
||||
try:
|
||||
return self.principal_model.objects.get(email=email)
|
||||
except self.principal_model.DoesNotExist:
|
||||
raise ValidationError(constants.EMAIL_NOT_REGISTERED)
|
||||
|
||||
def validate_principal_status(self, principal: IAmPrincipal) -> None:
|
||||
"""Validates that the principal is active."""
|
||||
if not principal.is_active:
|
||||
raise ValidationError(constants.ACCOUNT_DEACTIVATED)
|
||||
|
||||
def validate_credentials_provided(self, otp: Optional[str], password: Optional[str]) -> None:
|
||||
"""Ensures that at least one of OTP or password is provided."""
|
||||
if otp is None and password is None:
|
||||
raise ValidationError(constants.OTP_OR_PASSWORD_REQUIRED)
|
||||
|
||||
def authenticate_with_otp(self, principal: IAmPrincipal, otp: str) -> None:
|
||||
"""Authenticates using OTP."""
|
||||
if self.otp_model is None:
|
||||
raise ValidationError("OTP authentication is not supported")
|
||||
|
||||
otp_instance = self.otp_model.objects.filter(principal=principal, otp_code=otp).last()
|
||||
if not otp_instance:
|
||||
raise ValidationError(constants.OTP_INVALID)
|
||||
|
||||
if otp_instance.is_expired():
|
||||
raise ValidationError(constants.OTP_EXPIRED)
|
||||
|
||||
otp_instance.is_used = True
|
||||
otp_instance.save()
|
||||
|
||||
def authenticate_with_password(self, principal: IAmPrincipal, password: str) -> None:
|
||||
"""Authenticates using password."""
|
||||
if not principal.check_password(password):
|
||||
raise ValidationError(constants.INVALID_PASSWORD)
|
||||
|
||||
|
||||
def authticate_with_otp_and_passsword(principal: IAmPrincipal, otp=None, password=None):
|
||||
"""
|
||||
Authenticate a principal using OTP and/or Password.
|
||||
|
||||
Parameters:
|
||||
- principal (User): The principal object to authenticate.
|
||||
- otp (str, optional): One-Time Password (OTP). Default is None.
|
||||
- password (str, optional): User's password. Default is None.
|
||||
|
||||
Returns:
|
||||
None: Successful authentication.
|
||||
Response: Error response if authentication fails.
|
||||
|
||||
Example:
|
||||
```
|
||||
principal = User.objects.get(phone_no='8987546598')
|
||||
otp = request.data.get("otp")
|
||||
password = request.data.get("password")
|
||||
|
||||
result = authenticate_with_otp_and_password(principal, otp, password)
|
||||
if isinstance(result, Response):
|
||||
return result # Authentication failed, return error response
|
||||
else:
|
||||
# Authentication successful, proceed with authorized actions.
|
||||
```
|
||||
"""
|
||||
|
||||
if not principal.is_active:
|
||||
return ApiResponse.error(
|
||||
message=constants.ACCOUNT_DEACTIVATED, errors=constants.ACCOUNT_DEACTIVATED
|
||||
)
|
||||
|
||||
# Ensure that either OTP or password is provided
|
||||
if otp is None and password is None:
|
||||
return ApiResponse.error(
|
||||
message=constants.OTP_OR_PASSWORD_REQUIRED, errors=constants.OTP_OR_PASSWORD_REQUIRED
|
||||
)
|
||||
|
||||
if otp:
|
||||
otp_instance = IAmPrincipalOtp.objects.filter(
|
||||
principal=principal, otp_code=otp
|
||||
).last()
|
||||
|
||||
if not otp_instance:
|
||||
return ApiResponse.error(
|
||||
message=constants.OTP_INVALID, errors=constants.OTP_INVALID
|
||||
)
|
||||
|
||||
if otp_instance.is_expired():
|
||||
return ApiResponse.error(
|
||||
message=constants.OTP_EXPIRED, errors=constants.OTP_EXPIRED
|
||||
)
|
||||
|
||||
otp_instance.is_used = True
|
||||
otp_instance.save()
|
||||
|
||||
elif password:
|
||||
print(password)
|
||||
if not principal.check_password(password):
|
||||
return ApiResponse.error(
|
||||
message=constants.INVALID_PASSWORD, errors=constants.INVALID_PASSWORD
|
||||
)
|
||||
print("after passsowrd", password)
|
||||
|
||||
return None
|
||||
|
||||
def get_principal_by_email(email: str):
|
||||
try:
|
||||
principal = IAmPrincipal.objects.get(email=email)
|
||||
return principal
|
||||
except IAmPrincipal.DoesNotExist:
|
||||
error_response = {
|
||||
"message": constants.EMAIL_NOT_REGISTERED,
|
||||
"errors": constants.EMAIL_NOT_REGISTERED,
|
||||
}
|
||||
return ApiResponse.error(**error_response)
|
||||
217
module_auth/api/views.py
Normal file
217
module_auth/api/views.py
Normal file
@@ -0,0 +1,217 @@
|
||||
import datetime
|
||||
from rest_framework import status
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||
from module_project import constants
|
||||
from module_project.service import SMSService, EmailService
|
||||
from module_project.utils import ApiResponse
|
||||
from .utils import AuthService
|
||||
from module_iam.models import IAmPrincipal, IAmPrincipalOtp
|
||||
from .serializers import RegistrationSerializer, LoginSerializer, OtpVerificationSerializer, PasswordResetSerializer
|
||||
from django.conf import settings
|
||||
from rest_framework.response import Response
|
||||
|
||||
from .utils import (
|
||||
generate_token_and_user_data, get_principal_by_email, authticate_with_otp_and_passsword
|
||||
)
|
||||
|
||||
|
||||
class RegistrationView(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
model = IAmPrincipal
|
||||
serializer_class = RegistrationSerializer
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
print(f"request data is {request.data}")
|
||||
if not serializer.is_valid():
|
||||
error_response = {
|
||||
"status": status.HTTP_403_FORBIDDEN,
|
||||
"message": constants.REGISTRATION_FAIL,
|
||||
"errors": serializer.errors,
|
||||
}
|
||||
return ApiResponse.error(**error_response)
|
||||
|
||||
try:
|
||||
instance = serializer.save()
|
||||
principal = instance
|
||||
token_data = generate_token_and_user_data(principal)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_403_FORBIDDEN, message=str(e), errors=str(e)
|
||||
)
|
||||
|
||||
return ApiResponse.success(message=constants.REGISTRATION_SUCCESS, data=token_data)
|
||||
|
||||
|
||||
class LoginView(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
model = IAmPrincipal
|
||||
serializer_class = LoginSerializer
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
error_response = {
|
||||
"status": status.HTTP_403_FORBIDDEN,
|
||||
"message": constants.LOGIN_FAIL,
|
||||
"errors": serializer.errors,
|
||||
}
|
||||
return ApiResponse.error(**error_response)
|
||||
|
||||
email = request.data.get("email")
|
||||
otp = request.data.get("otp")
|
||||
password = request.data.get("password")
|
||||
player_id = request.data.get("player_id")
|
||||
|
||||
principal = get_principal_by_email(email=email)
|
||||
|
||||
if isinstance(principal, Response):
|
||||
return principal
|
||||
|
||||
validation_result = authticate_with_otp_and_passsword(
|
||||
principal, otp=otp, password=password
|
||||
)
|
||||
print("pasword instance ", validation_result)
|
||||
|
||||
if isinstance(validation_result, Response):
|
||||
print("Errror reponse")
|
||||
return validation_result # Return the error response if validation fails
|
||||
|
||||
|
||||
# auth_service = AuthService(principal_model=IAmPrincipal)
|
||||
|
||||
# try:
|
||||
# principal = self.model.objects.get(email=email)
|
||||
# except Exception as e:
|
||||
# error_response = {
|
||||
# "status": status.HTTP_403_FORBIDDEN,
|
||||
# "message": constants.INVALID_EMAIL_PASSWORD,
|
||||
# "errors": constants.INVALID_EMAIL_PASSWORD,
|
||||
# }
|
||||
# return ApiResponse.error(**error_response)
|
||||
|
||||
# try:
|
||||
# auth_service.authenticate(principal_id=principal.id, password=password)
|
||||
# except Exception as e:
|
||||
# error_response = {
|
||||
# "status": status.HTTP_403_FORBIDDEN,
|
||||
# "message": e,
|
||||
# "errors": e,
|
||||
# }
|
||||
# return ApiResponse.error(**error_response)
|
||||
|
||||
try:
|
||||
principal.player_id = player_id
|
||||
principal.last_login = datetime.datetime.now()
|
||||
principal.save()
|
||||
except Exception as e:
|
||||
error_response = {
|
||||
"status": status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
"message": constants.INTERNAL_SERVER_ERROR,
|
||||
"errors": str(e),
|
||||
}
|
||||
return ApiResponse.error(**error_response)
|
||||
|
||||
token_data = generate_token_and_user_data(principal)
|
||||
return ApiResponse.success(message=constants.LOGIN_SUCCESS, data=token_data)
|
||||
|
||||
|
||||
class OtpRequestView(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
|
||||
def post(self, request):
|
||||
if "email" not in request.data:
|
||||
return ApiResponse.error(message=constants.EMAIL_REQUIRED, errors=constants.EMAIL_REQUIRED)
|
||||
print(f"email auth username: {settings.EMAIL_HOST_USER}")
|
||||
email = request.data.get("email")
|
||||
|
||||
principal = get_principal_by_email(email=email)
|
||||
|
||||
if isinstance(principal, Response):
|
||||
return principal
|
||||
|
||||
try:
|
||||
# auth_service = AuthService(IAmPrincipal)
|
||||
# principal = auth_service.get_principal_by_email(request.data.get("email"))
|
||||
|
||||
otp_code = SMSService().create_otp(principal=principal, otp_purpose="Forget password")
|
||||
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=str(e), errors=str(e))
|
||||
|
||||
email_service = EmailService(
|
||||
subject="Forget Password",
|
||||
to=principal.email,
|
||||
from_email=settings.EMAIL_HOST_USER
|
||||
)
|
||||
|
||||
# Send the email
|
||||
try:
|
||||
email_service.load_template("module_auth/email_template.html", context={"code": otp_code} )
|
||||
email_service.send()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=f"Error sending email: {str(e)}", errors=str(e))
|
||||
|
||||
return ApiResponse.success(message=constants.SUCCESS)
|
||||
|
||||
class OTPVerificationView(APIView):
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
serializer_class = OtpVerificationSerializer
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
error_response = {
|
||||
"status": status.HTTP_403_FORBIDDEN,
|
||||
"message": constants.VALIDATION_ERROR,
|
||||
"errors": serializer.errors,
|
||||
}
|
||||
return ApiResponse.error(**error_response)
|
||||
|
||||
email = serializer.validated_data.get("email")
|
||||
otp = serializer.validated_data.get("otp")
|
||||
|
||||
principal = get_principal_by_email(email=email)
|
||||
|
||||
if isinstance(principal, Response):
|
||||
return principal
|
||||
|
||||
validation_result = authticate_with_otp_and_passsword(
|
||||
principal, otp=otp
|
||||
)
|
||||
print("pasword instance ", validation_result)
|
||||
|
||||
if isinstance(validation_result, Response):
|
||||
print("Errror reponse")
|
||||
return validation_result # Return the error response if validation fails
|
||||
|
||||
token_data = generate_token_and_user_data(principal)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=token_data)
|
||||
|
||||
class ForgetPasswordView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = PasswordResetSerializer
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(request.user, data=request.data)
|
||||
if not serializer.is_valid():
|
||||
error_response = {
|
||||
"status": status.HTTP_403_FORBIDDEN,
|
||||
"message": constants.VALIDATION_ERROR,
|
||||
"errors": serializer.errors,
|
||||
}
|
||||
return ApiResponse.error(**error_response)
|
||||
|
||||
try:
|
||||
serializer.save()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=str(e), errors=str(e))
|
||||
|
||||
return ApiResponse.success(message=constants.SUCCESS)
|
||||
6
module_auth/apps.py
Normal file
6
module_auth/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ModuleAuthConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'module_auth'
|
||||
15
module_auth/forms.py
Normal file
15
module_auth/forms.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django import forms
|
||||
from django.core import validators
|
||||
from module_project import constants
|
||||
|
||||
class LoginForm(forms.Form):
|
||||
email = forms.EmailField(
|
||||
max_length=254,
|
||||
widget=forms.TextInput(attrs={"autofocus": True}),
|
||||
label="Email",
|
||||
)
|
||||
password = forms.CharField(
|
||||
label="Password",
|
||||
strip=False,
|
||||
widget=forms.PasswordInput()
|
||||
)
|
||||
0
module_auth/migrations/__init__.py
Normal file
0
module_auth/migrations/__init__.py
Normal file
3
module_auth/models.py
Normal file
3
module_auth/models.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
module_auth/tests.py
Normal file
3
module_auth/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
17
module_auth/urls.py
Normal file
17
module_auth/urls.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = "module_auth"
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', views.AdminLoginView.as_view(), name="login"),
|
||||
path('logout/', views.AdminLogoutView.as_view(), name="logout"),
|
||||
path('password-reset/', views.CustomPasswordResetView.as_view(), name='password_reset'),
|
||||
path('password-reset/done/', views.CustomPasswordResetDoneView.as_view(), name='password_reset_done'),
|
||||
path('password-reset-confirm/<uidb64>/<token>/', views.CustomPasswordResetConfirmView.as_view(), name='password_reset_confirm'),
|
||||
path('password-reset-complete/', views.CustomPasswordResetCompleteView.as_view(), name='password_reset_complete'),
|
||||
path('users/', views.UserDashView.as_view(), name='users'),
|
||||
path('users/list/', views.UserListJson.as_view(), name='users_list'),
|
||||
path('user/view/<int:id>/', views.UserRecordView.as_view(), name='user_view'),
|
||||
|
||||
]
|
||||
203
module_auth/views.py
Normal file
203
module_auth/views.py
Normal file
@@ -0,0 +1,203 @@
|
||||
import logging
|
||||
|
||||
from django.db.models import Q, Prefetch
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import authenticate, login, logout
|
||||
from django.contrib.auth.views import LogoutView
|
||||
from django.contrib.auth.forms import PasswordResetForm
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.auth.views import (
|
||||
LoginView,
|
||||
PasswordResetCompleteView,
|
||||
PasswordResetConfirmView,
|
||||
PasswordResetDoneView,
|
||||
PasswordResetView,
|
||||
)
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.urls import reverse_lazy
|
||||
from django.views import generic
|
||||
from .forms import LoginForm
|
||||
from module_iam.models import IAmPrincipal
|
||||
from module_activity.models import PrincipalHealthData, Intolerance, Symptoms, PastTreatment, ChronicCondition
|
||||
from django_datatables_view.base_datatable_view import BaseDatatableView
|
||||
|
||||
from module_project import constants
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class AdminLoginView(generic.View):
|
||||
template_name = "module_auth/login.html"
|
||||
form_class = LoginForm
|
||||
success_url = reverse_lazy("module_iam:dashboard")
|
||||
error_url = reverse_lazy("module_auth:login")
|
||||
success_message = constants.LOGIN_SUCCESS
|
||||
error_message = constants.INVALID_EMAIL_PASSWORD
|
||||
|
||||
def get(self, request):
|
||||
form = self.form_class()
|
||||
|
||||
return render(request, self.template_name, context={"form": form})
|
||||
|
||||
def post(self, request):
|
||||
form = self.form_class(data=request.POST)
|
||||
context = {"form": form}
|
||||
if not form.is_valid():
|
||||
messages.error(request, constants.INVALID_EMAIL_PASSWORD)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
email = form.cleaned_data['email']
|
||||
password = form.cleaned_data['password']
|
||||
|
||||
user = authenticate(request, email=email, password=password)
|
||||
if user is None:
|
||||
messages.error(request, constants.INVALID_EMAIL_PASSWORD)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
login(request, user)
|
||||
logging.info(f"User {user.email} logged in.")
|
||||
|
||||
return redirect(self.success_url)
|
||||
|
||||
|
||||
class AdminLogoutView(LogoutView):
|
||||
next_page = reverse_lazy("module_auth:login")
|
||||
|
||||
class CustomPasswordResetView(PasswordResetView):
|
||||
form_class = PasswordResetForm
|
||||
template_name = "module_auth/password_reset_form.html"
|
||||
email_template_name = "module_auth/password_reset_email_template.html"
|
||||
success_url = reverse_lazy("module_auth:password_reset_done")
|
||||
|
||||
|
||||
class CustomPasswordResetDoneView(PasswordResetDoneView):
|
||||
template_name = "module_auth/password_reset_done.html"
|
||||
|
||||
|
||||
class UserDashView(LoginRequiredMixin, generic.TemplateView):
|
||||
page_name = None
|
||||
resource = None
|
||||
action = None
|
||||
template_name = "module_auth/users_list.html"
|
||||
model = IAmPrincipal
|
||||
context_objext_name = "obj"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
|
||||
class UserListJson(BaseDatatableView):
|
||||
model = IAmPrincipal
|
||||
columns = ["id", "first_name", "email", "phone_no", "date_of_birth", "is_active"]
|
||||
order_columns = ["id", "first_name", "email", "phone_no", "date_of_birth", "is_active"]
|
||||
|
||||
def filter_queryset(self, qs):
|
||||
print(f"request is {self.request.GET}")
|
||||
search_value = self.request.GET.get("search[value]", None)
|
||||
if search_value:
|
||||
# print(f"isdiget {search_value.isdigit()}")
|
||||
# if search_value.isdigit():
|
||||
# qs = qs.filter(Q(id=search_value))
|
||||
|
||||
qs = qs.filter(
|
||||
Q(id__icontains=search_value)
|
||||
| Q(first_name__icontains=search_value)
|
||||
| Q(email__icontains=search_value)
|
||||
| Q(date_of_birth__icontains=search_value)
|
||||
| Q(phone_no__icontains=search_value)
|
||||
)
|
||||
|
||||
for column in self.columns:
|
||||
search_value = self.request.GET.get(f'columns[{self.columns.index(column)}][search][value]', None)
|
||||
if search_value:
|
||||
qs = qs.filter(**{f"{column}__icontains": search_value})
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
class UserRecordView(LoginRequiredMixin, generic.View):
|
||||
page_name = None
|
||||
resource = None
|
||||
action = None
|
||||
model = IAmPrincipal
|
||||
template_name = "module_auth/user_view.html"
|
||||
|
||||
def get(self, request, id):
|
||||
# Retrieve the IAmPrincipal instance
|
||||
principal_instance = get_object_or_404(IAmPrincipal, id=id)
|
||||
|
||||
# Prefetch related Intolerance objects for the principal
|
||||
intolerance_prefetch = Prefetch(
|
||||
"intolerance_principal",
|
||||
queryset=Intolerance.objects.filter(principal=principal_instance),
|
||||
to_attr="intolerance_data",
|
||||
)
|
||||
|
||||
symptom_prefetch = Prefetch(
|
||||
"symptoms_principal",
|
||||
queryset=Symptoms.objects.filter(principal=principal_instance),
|
||||
to_attr="symptoms_data",
|
||||
)
|
||||
|
||||
pasttreatment_prefetch = Prefetch(
|
||||
"pasttreatment_principal",
|
||||
queryset=PastTreatment.objects.filter(principal=principal_instance),
|
||||
to_attr="pasttreatment_data",
|
||||
)
|
||||
|
||||
chronic_prefetch = Prefetch(
|
||||
"chronic_principal",
|
||||
queryset=ChronicCondition.objects.filter(principal=principal_instance),
|
||||
to_attr="chronic_data",
|
||||
)
|
||||
|
||||
# Now fetch the principal instance with prefetches
|
||||
obj = IAmPrincipal.objects.prefetch_related(
|
||||
intolerance_prefetch,
|
||||
symptom_prefetch,
|
||||
pasttreatment_prefetch,
|
||||
chronic_prefetch
|
||||
).get(id=id)
|
||||
|
||||
print(f"prefetch datatas")
|
||||
for data in obj.chronic_data:
|
||||
print(f"data is {data.name, data.duration}")
|
||||
|
||||
# Render the template with the principal instance and related data
|
||||
return render(request, self.template_name, {'obj': obj})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CustomPasswordResetConfirmView(PasswordResetConfirmView):
|
||||
template_name = "module_auth/password_reset_confirm.html"
|
||||
success_url = reverse_lazy("module_auth:password_reset_complete")
|
||||
|
||||
|
||||
class CustomPasswordResetCompleteView(PasswordResetCompleteView):
|
||||
template_name = "module_auth/password_reset_complete.html"
|
||||
0
module_cms/__init__.py
Normal file
0
module_cms/__init__.py
Normal file
6
module_cms/admin.py
Normal file
6
module_cms/admin.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.contrib import admin
|
||||
from .models import Faqs, Organization
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(Faqs)
|
||||
admin.site.register(Organization)
|
||||
40
module_cms/api/serializers.py
Normal file
40
module_cms/api/serializers.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from rest_framework import serializers
|
||||
from taggit.models import Tag
|
||||
from module_cms.models import Faqs, Organization
|
||||
|
||||
class FaqSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Faqs
|
||||
fields = ["id", "question", "answer"]
|
||||
|
||||
class FaqListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Faqs
|
||||
fields = "__all__"
|
||||
|
||||
class OrganizationSerializer(serializers.ModelSerializer):
|
||||
about_us = serializers.CharField(source='about_us.html', read_only=True)
|
||||
terms_condition = serializers.CharField(source='terms_condition.html', read_only=True)
|
||||
terms_condition_user = serializers.CharField(source='terms_condition_user.html', read_only=True)
|
||||
terms_condition_merchant = serializers.CharField(source='terms_condition_merchant.html', read_only=True)
|
||||
privacy_policy = serializers.CharField(source='privacy_policy.html', read_only=True)
|
||||
privacy_policy_user = serializers.CharField(source='privacy_policy_user.html', read_only=True)
|
||||
privacy_policy_merchant = serializers.CharField(source='privacy_policy_merchant.html', read_only=True)
|
||||
subscription_agreement = serializers.CharField(source='subscription_agreement.html', read_only=True)
|
||||
license_agreement_user = serializers.CharField(source='license_agreement_user.html', read_only=True)
|
||||
license_agreement_merchant = serializers.CharField(source='license_agreement_merchant.html', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Organization
|
||||
fields = [
|
||||
"about_us",
|
||||
"terms_condition",
|
||||
"terms_condition_user",
|
||||
"terms_condition_merchant",
|
||||
"privacy_policy",
|
||||
"privacy_policy_user",
|
||||
"privacy_policy_merchant",
|
||||
"subscription_agreement",
|
||||
"license_agreement_user",
|
||||
"license_agreement_merchant",
|
||||
]
|
||||
7
module_cms/api/urls.py
Normal file
7
module_cms/api/urls.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path("faq/", views.FaqListAPIView.as_view()),
|
||||
path("organization/", views.OrganizationAPIView.as_view())
|
||||
]
|
||||
30
module_cms/api/views.py
Normal file
30
module_cms/api/views.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||
from module_project import constants
|
||||
from module_project.utils import ApiResponse
|
||||
from .serializers import FaqSerializer, OrganizationSerializer
|
||||
from ..models import Faqs, Organization
|
||||
|
||||
|
||||
class FaqListAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = FaqSerializer
|
||||
model = Faqs
|
||||
|
||||
def get(self, request):
|
||||
queryset = self.model.objects.filter(active=True)
|
||||
serializer = self.serializer_class(queryset, many=True)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
class OrganizationAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = OrganizationSerializer
|
||||
model = Organization
|
||||
|
||||
def get(self, request):
|
||||
queryset = self.model.objects.filter(active=True).last()
|
||||
serializer = self.serializer_class(queryset)
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
6
module_cms/apps.py
Normal file
6
module_cms/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ModuleCmsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'module_cms'
|
||||
83
module_cms/forms.py
Normal file
83
module_cms/forms.py
Normal file
@@ -0,0 +1,83 @@
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core import validators
|
||||
from .models import (
|
||||
Organization,
|
||||
FaqCategory,
|
||||
Faqs,
|
||||
)
|
||||
|
||||
from module_project import constants
|
||||
|
||||
|
||||
class OrganizationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Organization
|
||||
fields = [
|
||||
"title",
|
||||
"contact_us_email",
|
||||
"instagram_handle",
|
||||
"facebook_handle",
|
||||
"linkedin_handle",
|
||||
"logo_image",
|
||||
"favicon_image",
|
||||
"website_url",
|
||||
]
|
||||
|
||||
labels = {
|
||||
"title": "Organization Title",
|
||||
"contact_us_email": "Contact Email",
|
||||
"instagram_handle": "Instagram URL",
|
||||
"facebook_handle": "Facebook URL",
|
||||
"linkedin_handle": "LinkedIn URL",
|
||||
"logo_image": "Organization Logo",
|
||||
"favicon_image": "Favicon",
|
||||
"website_url": "Website URL",
|
||||
}
|
||||
|
||||
class AboutUsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Organization
|
||||
fields = ["about_us"]
|
||||
labels = {"about_us": "Enter information about your organization:"}
|
||||
|
||||
class TermsAndConditionForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Organization
|
||||
fields = ["terms_condition"]
|
||||
labels = {"terms_condition": "Enter Terms and Conditions:"}
|
||||
|
||||
class PrivacyPolicyForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Organization
|
||||
fields = ["privacy_policy"]
|
||||
labels = {"privacy_policy": "Enter Privacy Police:"}
|
||||
|
||||
|
||||
class FaqCategoryFrom(forms.ModelForm):
|
||||
class Meta:
|
||||
model = FaqCategory
|
||||
fields = ["name"]
|
||||
labels = {"name": "Category name"}
|
||||
|
||||
|
||||
class FaqsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Faqs
|
||||
fields = [
|
||||
# "faq_category",
|
||||
"question",
|
||||
"answer",
|
||||
"active",
|
||||
]
|
||||
# labels = {"faq_category": "Category"}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get("instance")
|
||||
super().__init__(*args, **kwargs)
|
||||
# Fetch the choices for the faq_category field from the database
|
||||
# self.fields["faq_category"].queryset = FaqCategory.objects.all()
|
||||
|
||||
if instance is None:
|
||||
# This is an add operation, exclude the 'active' field
|
||||
self.fields.pop("active")
|
||||
81
module_cms/migrations/0001_initial.py
Normal file
81
module_cms/migrations/0001_initial.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-14 14:09
|
||||
|
||||
import django.db.models.deletion
|
||||
import django_quill.fields
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='FaqCategory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'faq_category',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Faqs',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('question', models.TextField(max_length=255)),
|
||||
('answer', models.TextField(blank=True, null=True)),
|
||||
('published', models.BooleanField(default=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('faq_category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='faqs_category', to='module_cms.faqcategory')),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'faq',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Organization',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('contact_us_email', models.EmailField(blank=True, max_length=254, null=True, unique=True)),
|
||||
('instagram_handle', models.URLField(blank=True, null=True)),
|
||||
('facebook_handle', models.URLField(blank=True, null=True)),
|
||||
('linkedin_handle', models.URLField(blank=True, null=True)),
|
||||
('logo_image', models.ImageField(blank=True, null=True, upload_to='organization/logo')),
|
||||
('favicon_image', models.ImageField(blank=True, null=True, upload_to='organization/favicon')),
|
||||
('website_url', models.URLField(blank=True, null=True)),
|
||||
('about_us', django_quill.fields.QuillField()),
|
||||
('terms_condition', django_quill.fields.QuillField()),
|
||||
('privacy_policy', django_quill.fields.QuillField()),
|
||||
('subscription_agreement', django_quill.fields.QuillField()),
|
||||
('license_agreement', django_quill.fields.QuillField()),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'organization',
|
||||
},
|
||||
),
|
||||
]
|
||||
17
module_cms/migrations/0002_remove_faqs_published.py
Normal file
17
module_cms/migrations/0002_remove_faqs_published.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-14 14:11
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_cms', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='faqs',
|
||||
name='published',
|
||||
),
|
||||
]
|
||||
19
module_cms/migrations/0003_alter_faqs_faq_category.py
Normal file
19
module_cms/migrations/0003_alter_faqs_faq_category.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-14 14:13
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_cms', '0002_remove_faqs_published'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='faqs',
|
||||
name='faq_category',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='faqs_category', to='module_cms.faqcategory'),
|
||||
),
|
||||
]
|
||||
0
module_cms/migrations/__init__.py
Normal file
0
module_cms/migrations/__init__.py
Normal file
51
module_cms/models.py
Normal file
51
module_cms/models.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from django.db import models
|
||||
from module_iam.models import BaseModel, IAmPrincipal
|
||||
from taggit.managers import TaggableManager
|
||||
from django_quill.fields import QuillField
|
||||
|
||||
# Create your models here.
|
||||
class Organization(BaseModel):
|
||||
title = models.CharField(max_length=255)
|
||||
contact_us_email = models.EmailField(unique=True, blank=True, null=True)
|
||||
instagram_handle = models.URLField(blank=True, null=True)
|
||||
facebook_handle = models.URLField(blank=True, null=True)
|
||||
linkedin_handle = models.URLField(blank=True, null=True)
|
||||
logo_image = models.ImageField(blank=True, null=True, upload_to="organization/logo")
|
||||
favicon_image = models.ImageField(
|
||||
blank=True, null=True, upload_to="organization/favicon"
|
||||
)
|
||||
website_url = models.URLField(blank=True, null=True)
|
||||
about_us = QuillField()
|
||||
terms_condition = QuillField()
|
||||
privacy_policy = QuillField()
|
||||
subscription_agreement = QuillField()
|
||||
license_agreement = QuillField()
|
||||
|
||||
class Meta:
|
||||
db_table = "organization"
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
class FaqCategory(BaseModel):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
class Meta:
|
||||
db_table = "faq_category"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Faqs(BaseModel):
|
||||
faq_category = models.ForeignKey(
|
||||
FaqCategory, related_name="faqs_category", blank=True, null=True, on_delete=models.SET_NULL
|
||||
)
|
||||
question = models.TextField(max_length=255)
|
||||
answer = models.TextField(blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "faq"
|
||||
|
||||
def __str__(self):
|
||||
return self.question
|
||||
3
module_cms/tests.py
Normal file
3
module_cms/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
19
module_cms/urls.py
Normal file
19
module_cms/urls.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = "module_cms"
|
||||
|
||||
urlpatterns = [
|
||||
path('faq/', views.FaqView.as_view(), name="faq"),
|
||||
path('faq/list/', views.FaqListJson.as_view(), name="faq_list"),
|
||||
path('faq/add/', views.FaqCreateOrUpdateView.as_view(), name='faq_add'),
|
||||
|
||||
path('about-us/', views.AboutUsView.as_view(), name='about_us'),
|
||||
path('about-us/edit/', views.AboutUsCreateOrUpdateView.as_view(), name='about_us_add'),
|
||||
|
||||
path('terms-condition/', views.TermsConditionView.as_view(), name='terms_and_condition'),
|
||||
path('terms-condition/edit/', views.TermsConditionCreateOrUpdateView.as_view(), name='terms_and_condition_edit'),
|
||||
|
||||
path('privacy-policy/', views.PrivacyPolicyView.as_view(), name='privacy_policy'),
|
||||
path('privacy-policy/edit/', views.PrivacyPolicyCreateOrUpdateView.as_view(), name='privacy_policy_edit'),
|
||||
]
|
||||
331
module_cms/views.py
Normal file
331
module_cms/views.py
Normal file
@@ -0,0 +1,331 @@
|
||||
import logging
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.urls import reverse_lazy
|
||||
from django.views import generic
|
||||
from module_iam.models import IAmPrincipal
|
||||
from .forms import AboutUsForm, TermsAndConditionForm, FaqCategoryFrom, PrivacyPolicyForm
|
||||
from .models import Faqs, Organization
|
||||
from .api.serializers import FaqListSerializer
|
||||
from module_project.mixins import DatatablesMixin
|
||||
from django_datatables_view.base_datatable_view import BaseDatatableView
|
||||
|
||||
from module_project import constants
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FaqView(LoginRequiredMixin, generic.TemplateView):
|
||||
page_name = None
|
||||
resource = None
|
||||
action = None
|
||||
template_name = "module_cms/faq.html"
|
||||
model = Faqs
|
||||
context_objext_name = "obj"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
|
||||
# class FaqDatatableView(DatatablesMixin, LoginRequiredMixin, generic.View):
|
||||
# model = Faqs
|
||||
|
||||
# def get_queryset(self):
|
||||
# return self.model.objects.filter(deleted=False)
|
||||
|
||||
# def get(self, request):
|
||||
# (
|
||||
# draw,
|
||||
# start,
|
||||
# length,
|
||||
# order_columns,
|
||||
# order_directions,
|
||||
# search_value,
|
||||
# ) = self.get_datatables_params(request)
|
||||
# queryset = self.get_queryset()
|
||||
|
||||
# page_obj, total_count, filtered_count = self.get_pagination(
|
||||
# queryset, start, length
|
||||
# )
|
||||
|
||||
# serializer = FaqListSerializer(
|
||||
# page_obj.object_list, many=True
|
||||
# )
|
||||
|
||||
# response = self.prepare_datatables_response(
|
||||
# draw, total_count, filtered_count, serializer.data
|
||||
# )
|
||||
|
||||
# return response
|
||||
|
||||
|
||||
class FaqListJson(BaseDatatableView):
|
||||
model = Faqs
|
||||
columns = ["id", "question", "answer", "active", "deleted"]
|
||||
order_columns = ["id", "question", "answer", "active", "deleted"]
|
||||
|
||||
def filter_queryset(self, qs):
|
||||
# Implement your custom filtering logic here
|
||||
print(f"request is {self.request.GET}")
|
||||
search_value = self.request.GET.get("search[value]", None)
|
||||
if search_value:
|
||||
qs = qs.filter(
|
||||
Q(id__icontains=search_value)
|
||||
| Q(question__icontains=search_value)
|
||||
| Q(answer__icontains=search_value)
|
||||
)
|
||||
|
||||
for column in self.columns:
|
||||
search_value = self.request.GET.get(f'columns[{self.columns.index(column)}][search][value]', None)
|
||||
if search_value:
|
||||
qs = qs.filter(**{f"{column}__icontains": search_value})
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
class FaqCreateOrUpdateView(generic.View):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
class AboutUsView(LoginRequiredMixin, generic.DetailView):
|
||||
page_name = None
|
||||
template_name = "module_cms/about_us_view.html"
|
||||
model = Organization
|
||||
context_object_name = "organization"
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return self.model.objects.only("about_us").first()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
|
||||
class AboutUsCreateOrUpdateView(LoginRequiredMixin, generic.View):
|
||||
# Set the page_name and resource
|
||||
page_name = None
|
||||
resource = None
|
||||
|
||||
# Initialize the action as ACTION_CREATE (can change based on logic)
|
||||
action = None # Default action
|
||||
|
||||
template_name = "module_cms/about_us_add.html"
|
||||
model = Organization
|
||||
form_class = AboutUsForm
|
||||
success_url = reverse_lazy("module_cms:about_us")
|
||||
error_message = "An error occurred while saving the data."
|
||||
|
||||
# Determine the success message dynamically based on whether it's an update or create
|
||||
def get_success_message(self):
|
||||
self.success_message = (
|
||||
constants.RECORD_CREATED if not self.object else constants.RECORD_UPDATED
|
||||
)
|
||||
return self.success_message
|
||||
|
||||
# Get the object (if exists) based on URL parameter 'pk'
|
||||
def get_object(self):
|
||||
return self.model.objects.only("about_us").first()
|
||||
|
||||
# Add page_name and operation to the context
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
"page_name": self.page_name,
|
||||
"operation": "Add" if not self.object else "Edit",
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
# If an object is found, change action to ACTION_UPDATE
|
||||
if self.object is not None:
|
||||
self.action = None
|
||||
|
||||
form = self.form_class(instance=self.object)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
# If an object is found, change action to ACTION_UPDATE
|
||||
if self.object is not None:
|
||||
self.action = None
|
||||
|
||||
form = self.form_class(request.POST, instance=self.object)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
form.save()
|
||||
messages.success(self.request, self.get_success_message())
|
||||
return redirect(self.success_url)
|
||||
|
||||
|
||||
class TermsConditionView(LoginRequiredMixin, generic.DetailView):
|
||||
page_name = None
|
||||
resource = None
|
||||
action = None
|
||||
template_name = "module_cms/terms_and_condition_view.html"
|
||||
model = Organization
|
||||
context_object_name = "organization"
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return self.model.objects.only("terms_condition").first()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
|
||||
class TermsConditionCreateOrUpdateView(LoginRequiredMixin, generic.View):
|
||||
# Set the page_name and resource
|
||||
page_name = None
|
||||
resource = None
|
||||
|
||||
# Initialize the action as ACTION_CREATE (can change based on logic)
|
||||
action = None # Default action
|
||||
|
||||
template_name = "module_cms/terms_and_condition_edit.html"
|
||||
model = Organization
|
||||
form_class = TermsAndConditionForm
|
||||
success_url = reverse_lazy("module_cms:terms_and_condition")
|
||||
error_message = "An error occurred while saving the data."
|
||||
|
||||
# Determine the success message dynamically based on whether it's an update or create
|
||||
def get_success_message(self):
|
||||
self.success_message = (
|
||||
constants.RECORD_CREATED if not self.object else constants.RECORD_UPDATED
|
||||
)
|
||||
return self.success_message
|
||||
|
||||
# Get the object (if exists) based on URL parameter 'pk'
|
||||
def get_object(self):
|
||||
return self.model.objects.only("terms_condition").first()
|
||||
|
||||
# Add page_name and operation to the context
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
"page_name": self.page_name,
|
||||
"operation": "Add" if not self.object else "Edit",
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
# If an object is found, change action to ACTION_UPDATE
|
||||
# if self.object is not None:
|
||||
# self.action = resource_action.ACTION_UPDATE
|
||||
|
||||
form = self.form_class(instance=self.object)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
# If an object is found, change action to ACTION_UPDATE
|
||||
# if self.object is not None:
|
||||
# self.action = resource_action.ACTION_UPDATE
|
||||
|
||||
form = self.form_class(request.POST, instance=self.object)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
form.save()
|
||||
messages.success(self.request, self.get_success_message())
|
||||
return redirect(self.success_url)
|
||||
|
||||
|
||||
class PrivacyPolicyView(LoginRequiredMixin, generic.DetailView):
|
||||
page_name = None
|
||||
resource = None
|
||||
action = None
|
||||
template_name = "module_cms/privacy_policy_view.html"
|
||||
model = Organization
|
||||
context_object_name = "organization"
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return self.model.objects.only("privacy_policy").first()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
|
||||
class PrivacyPolicyCreateOrUpdateView(LoginRequiredMixin, generic.View):
|
||||
# Set the page_name and resource
|
||||
page_name = None
|
||||
resource = None
|
||||
|
||||
# Initialize the action as ACTION_CREATE (can change based on logic)
|
||||
action = None # Default action
|
||||
|
||||
template_name = "module_cms/privacy_policy_edit.html"
|
||||
model = Organization
|
||||
form_class = PrivacyPolicyForm
|
||||
success_url = reverse_lazy("module_cms:privacy_policy")
|
||||
error_message = "An error occurred while saving the data."
|
||||
|
||||
# Determine the success message dynamically based on whether it's an update or create
|
||||
def get_success_message(self):
|
||||
self.success_message = (
|
||||
constants.RECORD_CREATED if not self.object else constants.RECORD_UPDATED
|
||||
)
|
||||
return self.success_message
|
||||
|
||||
# Get the object (if exists) based on URL parameter 'pk'
|
||||
def get_object(self):
|
||||
return self.model.objects.only("privacy_policy").first()
|
||||
|
||||
# Add page_name and operation to the context
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
"page_name": self.page_name,
|
||||
"operation": "Add" if not self.object else "Edit",
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
# If an object is found, change action to ACTION_UPDATE
|
||||
if self.object is not None:
|
||||
self.action = None
|
||||
|
||||
form = self.form_class(instance=self.object)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
# If an object is found, change action to ACTION_UPDATE
|
||||
if self.object is not None:
|
||||
self.action = None
|
||||
|
||||
form = self.form_class(request.POST, instance=self.object)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
form.save()
|
||||
messages.success(self.request, self.get_success_message())
|
||||
return redirect(self.success_url)
|
||||
0
module_iam/__init__.py
Normal file
0
module_iam/__init__.py
Normal file
18
module_iam/admin.py
Normal file
18
module_iam/admin.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from django.contrib import admin
|
||||
from . import models
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register(models.IAmPrincipal)
|
||||
admin.site.register(models.IAmPrincipalType)
|
||||
admin.site.register(models.IAmPrincipalSource)
|
||||
admin.site.register(models.IAmPrincipalGroup)
|
||||
admin.site.register(models.IAmAppResource)
|
||||
admin.site.register(models.IAmRole)
|
||||
admin.site.register(models.IAmAppAction)
|
||||
admin.site.register(models.IAmPrincipalGroupLink)
|
||||
admin.site.register(models.IAmPrincipalOtp)
|
||||
admin.site.register(models.IAmPrincipalBiometric)
|
||||
admin.site.register(models.IAmAppResourceActionLink)
|
||||
admin.site.register(models.IAmPricipalGroupRoleLink)
|
||||
admin.site.register(models.IAmRoleAppResourceActionLink)
|
||||
6
module_iam/apps.py
Normal file
6
module_iam/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ModuleIamConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'module_iam'
|
||||
291
module_iam/migrations/0001_initial.py
Normal file
291
module_iam/migrations/0001_initial.py
Normal file
@@ -0,0 +1,291 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-11 19:08
|
||||
|
||||
import django.contrib.auth.validators
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='IAmAppAction',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('label', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('slug', models.SlugField(blank=True, max_length=255, null=True)),
|
||||
('sort_order', models.IntegerField(blank=True, null=True)),
|
||||
('small_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('large_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_app_action',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmAppResource',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('label', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('slug', models.SlugField(blank=True, max_length=255, null=True)),
|
||||
('sort_order', models.IntegerField(blank=True, null=True)),
|
||||
('small_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('large_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_app_resource',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmPrincipalGroup',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('label', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('slug', models.SlugField(blank=True, max_length=255, null=True)),
|
||||
('sort_order', models.IntegerField(blank=True, null=True)),
|
||||
('small_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('large_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_principal_group',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmPrincipalSource',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('label', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('slug', models.SlugField(blank=True, max_length=255, null=True)),
|
||||
('sort_order', models.IntegerField(blank=True, null=True)),
|
||||
('small_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('large_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_principal_source',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmPrincipalType',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('label', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('slug', models.SlugField(blank=True, max_length=255, null=True)),
|
||||
('sort_order', models.IntegerField(blank=True, null=True)),
|
||||
('small_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('large_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_principal_type',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmRole',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('label', models.CharField(blank=True, max_length=255, null=True)),
|
||||
('slug', models.SlugField(blank=True, max_length=255, null=True)),
|
||||
('sort_order', models.IntegerField(blank=True, null=True)),
|
||||
('small_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('large_image_url', models.ImageField(blank=True, null=True, upload_to='')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_by', models.SmallIntegerField(blank=True, null=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_role',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmPrincipal',
|
||||
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')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('email', models.EmailField(max_length=254, unique=True)),
|
||||
('gender', models.CharField(blank=True, max_length=5, null=True)),
|
||||
('date_of_birth', models.DateField(blank=True, null=True)),
|
||||
('phone_no', models.IntegerField()),
|
||||
('address_line1', models.TextField(blank=True, null=True)),
|
||||
('address_line2', models.TextField(blank=True, null=True)),
|
||||
('city', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('state', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('country', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('post_code', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('profile_photo', models.ImageField(blank=True, null=True, upload_to='profile')),
|
||||
('phone_verified', models.BooleanField(default=False)),
|
||||
('email_verified', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('register_complete', models.BooleanField(default=False)),
|
||||
('player_id', models.CharField(blank=True, help_text='OneSignal player id for push notification', max_length=255, null=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='creations', to=settings.AUTH_USER_MODEL)),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='modifications', to=settings.AUTH_USER_MODEL)),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_principal',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmAppResourceActionLink',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('app_action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='resource_action_link_app_action', to='module_iam.iamappaction')),
|
||||
('app_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='resource_action_link_app_resource', to='module_iam.iamappresource')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_app_resource_action_link',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='iamappresource',
|
||||
name='action',
|
||||
field=models.ManyToManyField(related_name='app_resource_action', through='module_iam.IAmAppResourceActionLink', to='module_iam.iamappaction'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmPrincipalBiometric',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('biometric_type', models.CharField(max_length=100)),
|
||||
('biometric_data', models.CharField(max_length=255)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='principal_biometric', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_principal_biometric',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmPricipalGroupRoleLink',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('principal_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='role_link_principal_group', to='module_iam.iamprincipalgroup')),
|
||||
('role', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='role_link_role', to='module_iam.iamrole')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_principal_group_role_link',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmPrincipalGroupLink',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='principal_group_link_principal', to=settings.AUTH_USER_MODEL)),
|
||||
('principal_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='principal_group_link_group', to='module_iam.iamprincipalgroup')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_principal_principal_group_link',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='iamprincipal',
|
||||
name='principal_group',
|
||||
field=models.ManyToManyField(related_name='principal_groups', through='module_iam.IAmPrincipalGroupLink', to='module_iam.iamprincipalgroup'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmPrincipalOtp',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('otp_code', models.CharField(max_length=4)),
|
||||
('otp_purpose', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('valid_till', models.DateTimeField()),
|
||||
('is_used', models.BooleanField(default=False)),
|
||||
('principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='principal_otp', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_principal_otp',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='iamprincipal',
|
||||
name='principal_source',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='principals_source', to='module_iam.iamprincipalsource'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='iamprincipal',
|
||||
name='principal_type',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='principals_type', to='module_iam.iamprincipaltype'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='iamprincipalgroup',
|
||||
name='role',
|
||||
field=models.ManyToManyField(related_name='principal_group_role', through='module_iam.IAmPricipalGroupRoleLink', to='module_iam.iamrole'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IAmRoleAppResourceActionLink',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('app_resource_action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='role_app_resource_action_link_app_resource_action', to='module_iam.iamappresourceactionlink')),
|
||||
('role', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='role_app_resource_action_link_role', to='module_iam.iamrole')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'iam_role_app_resource_action_link',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='iamrole',
|
||||
name='app_resource_action',
|
||||
field=models.ManyToManyField(related_name='role_app_resource_action', through='module_iam.IAmRoleAppResourceActionLink', to='module_iam.iamappresourceactionlink'),
|
||||
),
|
||||
]
|
||||
18
module_iam/migrations/0002_alter_iamprincipal_phone_no.py
Normal file
18
module_iam/migrations/0002_alter_iamprincipal_phone_no.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-12 11:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_iam', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='iamprincipal',
|
||||
name='phone_no',
|
||||
field=models.CharField(blank=True, max_length=15, null=True),
|
||||
),
|
||||
]
|
||||
18
module_iam/migrations/0003_alter_iamprincipal_gender.py
Normal file
18
module_iam/migrations/0003_alter_iamprincipal_gender.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-23 13:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_iam', '0002_alter_iamprincipal_phone_no'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='iamprincipal',
|
||||
name='gender',
|
||||
field=models.CharField(blank=True, max_length=6, null=True),
|
||||
),
|
||||
]
|
||||
0
module_iam/migrations/__init__.py
Normal file
0
module_iam/migrations/__init__.py
Normal file
369
module_iam/models.py
Normal file
369
module_iam/models.py
Normal file
@@ -0,0 +1,369 @@
|
||||
from collections.abc import Iterable
|
||||
import datetime
|
||||
import random
|
||||
import string
|
||||
# from manage_wallets.models import Wallet, Transaction, TransactionStatus, TransactionType
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AbstractUser, BaseUserManager
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.text import slugify
|
||||
# from phonenumber_field.modelfields import PhoneNumberField
|
||||
|
||||
from module_project.utils import RandomGenerator
|
||||
from .resource_action import PRINCIPAL_TYPE_USER, PRINCIPAL_TYPE_ADMIN
|
||||
|
||||
# from .utils import UserContext
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator
|
||||
|
||||
|
||||
class BaseModel(models.Model):
|
||||
active = models.BooleanField(default=True)
|
||||
deleted = models.BooleanField(default=False)
|
||||
created_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
related_name="%(class)s_created",
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
created_on = models.DateTimeField(auto_now_add=True)
|
||||
modified_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
related_name="%(class)s_modified",
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
modified_on = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
@classmethod
|
||||
def get_deleted(cls):
|
||||
return cls.objects.filter(deleted=True)
|
||||
|
||||
@classmethod
|
||||
def get_all_except_deleted(cls):
|
||||
return cls.objects.filter(deleted=False)
|
||||
|
||||
@classmethod
|
||||
def mark_deleted(cls, pk):
|
||||
try:
|
||||
obj = cls.objects.get(pk=pk)
|
||||
obj.active = False
|
||||
obj.deleted = True
|
||||
obj.save()
|
||||
return obj
|
||||
except cls.DoesNotExist:
|
||||
return None
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.active = False # Set active to False when deleting
|
||||
self.deleted = True
|
||||
self.save()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.deleted:
|
||||
self.active = False # Ensure active is False if record is marked as deleted
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class MasterModel(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
label = models.CharField(max_length=255, null=True, blank=True)
|
||||
slug = models.SlugField(max_length=255, null=True, blank=True)
|
||||
sort_order = models.IntegerField(blank=True, null=True)
|
||||
small_image_url = models.ImageField(blank=True, null=True)
|
||||
large_image_url = models.ImageField(blank=True, null=True)
|
||||
active = models.BooleanField(default=True)
|
||||
deleted = models.BooleanField(default=False)
|
||||
created_by = models.SmallIntegerField(blank=True, null=True)
|
||||
created_on = models.DateTimeField(auto_now_add=True)
|
||||
modified_by = models.SmallIntegerField(blank=True, null=True)
|
||||
modified_on = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Generate a slug from the name field
|
||||
self.slug = slugify(self.name)
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class IAmPrincipalType(MasterModel):
|
||||
class Meta:
|
||||
db_table = "iam_principal_type"
|
||||
|
||||
@classmethod
|
||||
def get_principal_type(cls, type):
|
||||
return cls.objects.filter(name=type).first()
|
||||
|
||||
|
||||
class IAmPrincipalSource(MasterModel):
|
||||
class Meta:
|
||||
db_table = "iam_principal_source"
|
||||
|
||||
|
||||
class IAmAppAction(MasterModel):
|
||||
class Meta:
|
||||
db_table = "iam_app_action"
|
||||
|
||||
|
||||
class IAmAppResource(MasterModel):
|
||||
action = models.ManyToManyField(
|
||||
IAmAppAction,
|
||||
through="IAmAppResourceActionLink",
|
||||
related_name="app_resource_action",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_app_resource"
|
||||
|
||||
|
||||
class IAmRoleAppResourceActionLinkManager(models.Manager):
|
||||
def generate_app_resource_action_data(self):
|
||||
"""
|
||||
Generate a dictionary mapping resource names to associated actions.
|
||||
Returns:
|
||||
dict: A dictionary with resource names as keys and nested dictionaries
|
||||
where action IDs are keys and action names are values.
|
||||
Example:
|
||||
{
|
||||
"res1": {1: "a1", 2: "a2"},
|
||||
"res2": {3: "a1", 4: "a2"}
|
||||
}
|
||||
"""
|
||||
app_resource_action = self.select_related("app_resource", "app_action").all()
|
||||
resource_action_link = {}
|
||||
for item in app_resource_action:
|
||||
resource = item.app_resource.name
|
||||
action = item.app_action.name
|
||||
id = item.id
|
||||
if resource in resource_action_link:
|
||||
resource_action_link[resource][id] = action
|
||||
else:
|
||||
resource_action_link[resource] = {id: action}
|
||||
# print(resource_action_link)
|
||||
return resource_action_link
|
||||
|
||||
|
||||
class IAmAppResourceActionLink(models.Model):
|
||||
app_resource = models.ForeignKey(
|
||||
IAmAppResource,
|
||||
related_name="resource_action_link_app_resource",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
app_action = models.ForeignKey(
|
||||
IAmAppAction,
|
||||
related_name="resource_action_link_app_action",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
objects = IAmRoleAppResourceActionLinkManager()
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_app_resource_action_link"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.app_resource.name}: {self.app_action.name}"
|
||||
|
||||
|
||||
class IAmRole(MasterModel):
|
||||
app_resource_action = models.ManyToManyField(
|
||||
IAmAppResourceActionLink,
|
||||
through="IAmRoleAppResourceActionLink",
|
||||
related_name="role_app_resource_action",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_role"
|
||||
|
||||
|
||||
class IAmRoleAppResourceActionLink(models.Model):
|
||||
role = models.ForeignKey(
|
||||
IAmRole,
|
||||
related_name="role_app_resource_action_link_role",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
app_resource_action = models.ForeignKey(
|
||||
IAmAppResourceActionLink,
|
||||
related_name="role_app_resource_action_link_app_resource_action",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_role_app_resource_action_link"
|
||||
|
||||
|
||||
class IAmPrincipalGroup(MasterModel):
|
||||
role = models.ManyToManyField(
|
||||
IAmRole, through="IAmPricipalGroupRoleLink", related_name="principal_group_role"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_principal_group"
|
||||
|
||||
|
||||
class IAmPricipalGroupRoleLink(models.Model):
|
||||
principal_group = models.ForeignKey(
|
||||
IAmPrincipalGroup,
|
||||
related_name="role_link_principal_group",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
role = models.ForeignKey(
|
||||
IAmRole, related_name="role_link_role", on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_principal_group_role_link"
|
||||
|
||||
|
||||
class IAmPrincipalManager(BaseUserManager):
|
||||
def create_user(self, email, password=None, **extra_fields):
|
||||
if not email:
|
||||
raise ValueError("The Email field must be set")
|
||||
email = self.normalize_email(email)
|
||||
user = self.model(email=email, **extra_fields)
|
||||
user.set_password(password)
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
|
||||
def create_superuser(self, email, password=None, **extra_fields):
|
||||
extra_fields.setdefault("username", email)
|
||||
extra_fields.setdefault("is_staff", True)
|
||||
extra_fields.setdefault("is_superuser", True)
|
||||
extra_fields.setdefault("phone_no", "+919978895465")
|
||||
extra_fields.setdefault("gender", "M")
|
||||
extra_fields.setdefault("date_of_birth", timezone.now())
|
||||
extra_fields.setdefault("created_by", None)
|
||||
extra_fields.setdefault("created_on", timezone.now())
|
||||
extra_fields.setdefault("modified_by", None)
|
||||
extra_fields.setdefault("modified_on", timezone.now())
|
||||
return self.create_user(email, password, **extra_fields)
|
||||
|
||||
|
||||
class IAmPrincipal(AbstractUser):
|
||||
principal_type = models.ForeignKey(
|
||||
IAmPrincipalType,
|
||||
related_name="principals_type",
|
||||
null=True,
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
principal_source = models.ForeignKey(
|
||||
IAmPrincipalSource,
|
||||
related_name="principals_source",
|
||||
on_delete=models.CASCADE,
|
||||
null=True,
|
||||
)
|
||||
email = models.EmailField(unique=True)
|
||||
gender = models.CharField(max_length=6, blank=True, null=True)
|
||||
date_of_birth = models.DateField(blank=True, null=True)
|
||||
# phone_no = PhoneNumberField()
|
||||
phone_no = models.CharField(max_length=15, blank=True, null=True)
|
||||
address_line1 = models.TextField(blank=True, null=True)
|
||||
address_line2 = models.TextField(blank=True, null=True)
|
||||
city = models.CharField(max_length=100, blank=True, null=True)
|
||||
state = models.CharField(max_length=100, blank=True, null=True)
|
||||
country = models.CharField(max_length=100, blank=True, null=True)
|
||||
post_code = models.CharField(max_length=100, blank=True, null=True)
|
||||
profile_photo = models.ImageField(upload_to="profile", blank=True, null=True)
|
||||
phone_verified = models.BooleanField(default=False)
|
||||
email_verified = models.BooleanField(default=False)
|
||||
created_by = models.ForeignKey(
|
||||
"self",
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="creations",
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
created_on = models.DateTimeField(auto_now_add=True)
|
||||
modified_by = models.ForeignKey(
|
||||
"self",
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="modifications",
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
modified_on = models.DateTimeField(auto_now=True)
|
||||
deleted = models.BooleanField(default=False)
|
||||
principal_group = models.ManyToManyField(
|
||||
IAmPrincipalGroup,
|
||||
through="IAmPrincipalGroupLink",
|
||||
related_name="principal_groups",
|
||||
)
|
||||
register_complete = models.BooleanField(default=False)
|
||||
player_id = models.CharField(max_length=255, null=True, blank=True, help_text="OneSignal player id for push notification")
|
||||
|
||||
USERNAME_FIELD = "email"
|
||||
REQUIRED_FIELDS = []
|
||||
|
||||
objects = IAmPrincipalManager()
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_principal"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.email}"
|
||||
|
||||
|
||||
class IAmPrincipalGroupLink(models.Model):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal,
|
||||
related_name="principal_group_link_principal",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
principal_group = models.ForeignKey(
|
||||
IAmPrincipalGroup,
|
||||
related_name="principal_group_link_group",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_principal_principal_group_link"
|
||||
|
||||
|
||||
class IAmPrincipalOtp(models.Model):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal, related_name="principal_otp", on_delete=models.CASCADE
|
||||
)
|
||||
otp_code = models.CharField(max_length=4)
|
||||
otp_purpose = models.CharField(max_length=50, null=True, blank=True)
|
||||
valid_till = models.DateTimeField()
|
||||
is_used = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_principal_otp"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.principal.phone_no}:{self.otp_code} : {self.otp_purpose}"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.pk:
|
||||
self.otp_code = RandomGenerator.random_otp()
|
||||
self.valid_till = timezone.now() + timezone.timedelta(
|
||||
minutes=settings.OTP_EXPIRE_TIME
|
||||
)
|
||||
super(IAmPrincipalOtp, self).save(*args, **kwargs)
|
||||
|
||||
def is_expired(self):
|
||||
return timezone.now() >= self.valid_till
|
||||
|
||||
|
||||
class IAmPrincipalBiometric(BaseModel):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal, related_name="principal_biometric", on_delete=models.CASCADE
|
||||
)
|
||||
biometric_type = models.CharField(max_length=100)
|
||||
biometric_data = models.CharField(max_length=255)
|
||||
|
||||
class Meta:
|
||||
db_table = "iam_principal_biometric"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.principal.first_name}:{self.biometric_type}"
|
||||
31
module_iam/resource_action.py
Normal file
31
module_iam/resource_action.py
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
PRINCIPAL_TYPE_USER = "user"
|
||||
PRINCIPAL_TYPE_ADMIN = "admin"
|
||||
|
||||
ACTION_CREATE = "create"
|
||||
ACTION_READ = "read"
|
||||
ACTION_UPDATE = "update"
|
||||
ACTION_DELETE = "delete"
|
||||
|
||||
RESOURCE_MANAGE_DASHBOARD = "manage_dashboard"
|
||||
RESOURCE_MANAGE_IAM = "manage_iam"
|
||||
RESOURCE_MANAGE_CUSTOMER = "manage_customer"
|
||||
RESOURCE_MANAGE_WALLET = "manage_wallet"
|
||||
RESOURCE_MANAGE_PAYMENT = "manage_payment"
|
||||
RESOURCE_MANAGE_GAMES = "manage_games"
|
||||
RESOURCE_MANAGE_CONTACT_US = "manage_contact_us"
|
||||
RESOURCE_MANAGE_TICKET = "manage_ticket"
|
||||
RESOURCE_MANAGE_CMS = "manage_cms"
|
||||
RESOURCE_MANAGE_REPORTS = "manage_reports"
|
||||
RESOURCE_MANAGE_COUPON = "manage_coupon"
|
||||
RESOURCE_MANAGE_FEEDBACK = "manage_feedback"
|
||||
RESOURCE_MANAGE_STOCK = "manage_stock"
|
||||
|
||||
|
||||
# These constants are used solely for managing the active and inactive state of pages
|
||||
# and should not be considered as resources in the typical sense.
|
||||
# They are used for page management purposes only.
|
||||
RESOURCE_IAM_PRINCIPAL = "iam_principal"
|
||||
RESOURCE_IAM_PRINCIPAL_GROUP = "iam_principal_group"
|
||||
RESOURCE_IAM_GROUP = "iam_group"
|
||||
RESOURCE_IAM_ROLE = "iam_role"
|
||||
3
module_iam/tests.py
Normal file
3
module_iam/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
8
module_iam/urls.py
Normal file
8
module_iam/urls.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = "module_iam"
|
||||
|
||||
urlpatterns = [
|
||||
path('dashboard/', views.DashboardView.as_view(), name="dashboard")
|
||||
]
|
||||
7
module_iam/views.py
Normal file
7
module_iam/views.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.shortcuts import render
|
||||
from django.views import generic
|
||||
|
||||
# Create your views here.
|
||||
|
||||
class DashboardView(generic.TemplateView):
|
||||
template_name = "base_structure/layout/dashboard.html"
|
||||
0
module_notification/__init__.py
Normal file
0
module_notification/__init__.py
Normal file
3
module_notification/admin.py
Normal file
3
module_notification/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
module_notification/apps.py
Normal file
6
module_notification/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ModuleNotificationConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'module_notification'
|
||||
0
module_notification/migrations/__init__.py
Normal file
0
module_notification/migrations/__init__.py
Normal file
3
module_notification/models.py
Normal file
3
module_notification/models.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
module_notification/tests.py
Normal file
3
module_notification/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
3
module_notification/views.py
Normal file
3
module_notification/views.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
0
module_project/__init__.py
Normal file
0
module_project/__init__.py
Normal file
16
module_project/asgi.py
Normal file
16
module_project/asgi.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for module_project 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', 'module_project.settings')
|
||||
|
||||
application = get_asgi_application()
|
||||
72
module_project/constants.py
Normal file
72
module_project/constants.py
Normal file
@@ -0,0 +1,72 @@
|
||||
VALIDATION_ERROR = "Validation Error"
|
||||
|
||||
# CRUD Related Constants
|
||||
SUCCESS = "Operation successful."
|
||||
FAILURE = "Operation failed."
|
||||
RECORD_CREATED = "Record created successfully."
|
||||
RECORD_UPDATED = "Record updated successfully."
|
||||
RECORD_NOT_FOUND = "Record not found."
|
||||
RECORD_DELETED = "Record deleted successfully."
|
||||
ERROR_OCCURR = "An error occurred: {}"
|
||||
SOMETHING_WRONG = "Something went wrong"
|
||||
DATA_SAVED = "Data saved successfully."
|
||||
DATA_UPDATED = "Data updated successfully."
|
||||
DATA_DELETED = "Data deleted successfully."
|
||||
DATA_IMPORT_SUCCESS = "Data import successful."
|
||||
DATA_EXPORT_SUCCESS = "Data export successful."
|
||||
DATA_INTEGRITY_ERROR = "Data integrity error. Please contact support."
|
||||
INTERNAL_SERVER_ERROR = "Internal server error"
|
||||
|
||||
# File Related Constants
|
||||
FILE_NOT_FOUND = "The requested file was not found."
|
||||
FILE_UPLOAD_ERROR = "An error occurred while uploading files."
|
||||
FILE_UPLOAD_SUCCESS = "Files uploaded successfully."
|
||||
|
||||
# Registration and Authentication Related Constants
|
||||
REGISTRATION_INCOMPLETE = "Registration incomplete."
|
||||
REGISTRATION_SUCCESS = "Registration successful."
|
||||
REGISTRATION_FAIL = "Registration failed."
|
||||
LOGIN_FAIL = "Login failed."
|
||||
LOGIN_REQUIRED = "Login required to perform this action."
|
||||
LOGIN_SUCCESS = "Login successful."
|
||||
LOGOUT_SUCCESS = "Logout successful."
|
||||
SESSION_EXPIRED = "Your session has expired. Please log in again."
|
||||
ACCOUNT_DEACTIVATED = "Your account is inactive. Please contact support."
|
||||
EMAIL_EXISTS = "This email address is already in use. Please use a different email."
|
||||
INVALID_EMAIL_PASSWORD = "Invalid email or password."
|
||||
INVALID_PASSWORD = "Invalid password."
|
||||
PASSWORD_NOT_MATCH = "Password do not match"
|
||||
INVALID_OPERATION = "Invalid operation requested."
|
||||
PASSWORD_RESET_SUCCESS = "Password reset successful. You can now log in with your new password."
|
||||
EMAIL_VERIFICATION_SUCCESS = "Email verification successful. You can now log in."
|
||||
PASSWORD_CHANGE_SUCCESS = "Password change successful. Your password has been updated."
|
||||
PASSWORD_CHANGE_FAILURE = "Password change failed. Please try again later."
|
||||
|
||||
|
||||
# Mobile OTP Related Constants
|
||||
PHONE_NUMBER_EXISTS = "This phone number is already in use."
|
||||
PHONE_NUMBER_NOT_REGISTERED = "This phone number is not registered."
|
||||
PHONE_NUMBER_NOT_FOUND = "Phone number not found."
|
||||
PHONE_FIELD_IS_REQUIRED = "Phone field is required."
|
||||
PHONE_NUMBER_INVALID = 'Invalid phone number.'
|
||||
PHONE_NUMBER_VERIFICATION_SUCCESS = "Phone number verification successful."
|
||||
PHONE_NUMBER_VERIFICATION_FAILED = "Phone number verification failed."
|
||||
OTP_INVALID = "Invalid OTP."
|
||||
OTP_VERIFIED = "OTP verified successful"
|
||||
OTP_SENT = "OTP sent successfully."
|
||||
OTP_FIELD_IS_REQUIRED = "OTP is required."
|
||||
OTP_OR_PASSWORD_REQUIRED = "OTP or Password is required"
|
||||
OTP_EXPIRED = "OTP has expired."
|
||||
|
||||
# Email Related Constants
|
||||
EMAIL_NOT_REGISTERED = "Email is not registered"
|
||||
EMAIL_REQUIRED = "Email field is required"
|
||||
EMAIL_SENT = "Email sent successfully."
|
||||
EMAIL_NOT_SENT = "Email could not be sent. Please try again later."
|
||||
|
||||
# Payment and Transaction Related Constants
|
||||
PAYMENT_SUCCESS = "Payment successful. Thank you for your purchase!"
|
||||
PAYMENT_FAILED = "Payment failed. Please check your payment details and try again."
|
||||
TRANSACTION_PENDING = "Your transaction is currently pending processing."
|
||||
WITHDRAWAL_FAILED = "Withdraw failed. Please check your wallet details."
|
||||
WITHDRAWAL_SUCCESS = "Withdraw successful. Happy Earnings!"
|
||||
64
module_project/date_utils.py
Normal file
64
module_project/date_utils.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Format date
|
||||
def format_date_to_string(date, format='%d %b, %Y'):
|
||||
return date.strftime(format)
|
||||
|
||||
# Format date or time
|
||||
def format_datetime_to_sting(dt, format='%d %b, %Y %H:%M:%S'):
|
||||
return dt.strftime(format)
|
||||
|
||||
# Get current date
|
||||
def get_current_date():
|
||||
return datetime.now()
|
||||
|
||||
# Get current time
|
||||
def get_current_time():
|
||||
return datetime.now().time()
|
||||
|
||||
# Get current date in a specific timezone
|
||||
from pytz import timezone
|
||||
def get_current_date_in_timezone(timezone_str='UTC'):
|
||||
tz = timezone(timezone_str)
|
||||
return datetime.now(tz)
|
||||
|
||||
# Convert string to datetime
|
||||
def string_to_date(date_string, format='%Y-%m-%d'):
|
||||
return datetime.strptime(date_string, format)
|
||||
|
||||
# Convert string to datetime
|
||||
def string_to_datetime(datetime_string, format='%Y-%m-%d %H:%M:%S'):
|
||||
return datetime.strptime(datetime_string, format)
|
||||
|
||||
# Get difference between two dates
|
||||
def get_date_difference(date1, date2):
|
||||
return abs(date2 - date1)
|
||||
|
||||
# Get difference between two datetimes
|
||||
def get_datetime_difference(datetime1, datetime2):
|
||||
return abs(datetime2 - datetime1)
|
||||
|
||||
# Add days to a given date
|
||||
def add_days_to_date(date, days):
|
||||
return date + timedelta(days=days)
|
||||
|
||||
# Subtract days from a given date
|
||||
def subtract_days_from_date(date, days):
|
||||
return date - timedelta(days=days)
|
||||
|
||||
# Check if a year is a leap year
|
||||
def is_leap_year(year):
|
||||
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
|
||||
|
||||
# Get the last day of a given month and year
|
||||
def last_day_of_month(year, month):
|
||||
if month == 12:
|
||||
year += 1
|
||||
month = 1
|
||||
else:
|
||||
month += 1
|
||||
return datetime(year, month, 1) - timedelta(days=1)
|
||||
|
||||
# Check if a date is within a specific range
|
||||
def is_date_within_range(date, start_date, end_date):
|
||||
return start_date <= date <= end_date
|
||||
86
module_project/mixins.py
Normal file
86
module_project/mixins.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from django.db.models import Q
|
||||
from django.http.response import JsonResponse
|
||||
from django.core.paginator import Paginator
|
||||
|
||||
class DatatablesMixin:
|
||||
"""
|
||||
Mixin for handling Datatables parameters, filtering, sorting, pagination,
|
||||
and response preparation.
|
||||
"""
|
||||
filter_fields = []
|
||||
search_fields = []
|
||||
|
||||
def get_datatables_params(self, request):
|
||||
"""
|
||||
Extracts Datatables parameters from the request.
|
||||
"""
|
||||
draw = request.GET.get('draw', 1)
|
||||
start = request.GET.get("start", 0)
|
||||
length = request.GET.get("length", 10)
|
||||
order_columns = request.GET.getlist('order[][column]')
|
||||
order_directions = request.GET.getlist('order[][dir]')
|
||||
search_value = request.GET.get("search[value]", "")
|
||||
return draw, start, length, order_columns, order_directions, search_value
|
||||
|
||||
def get_filters(self, request):
|
||||
"""
|
||||
Extracts and applies filters based on request parameters.
|
||||
"""
|
||||
filters = {}
|
||||
for field in self.filter_fields:
|
||||
value = request.GET.get(field)
|
||||
if value:
|
||||
filters[field] = value
|
||||
return filters
|
||||
|
||||
def get_sorting(self, request, order_columns, order_directions):
|
||||
"""
|
||||
Constructs the sorting order based on request parameters.
|
||||
"""
|
||||
sorting = []
|
||||
for i in range(len(order_columns)):
|
||||
column_index = int(order_columns[i])
|
||||
order = order_directions[i]
|
||||
field = self.model._meta.get_field(column_index).name
|
||||
sorting.append('-' + field if order == 'desc' else field)
|
||||
return sorting
|
||||
|
||||
def get_search_filters(self, request, search_value, search_fields):
|
||||
"""
|
||||
Generates Q objects for global and individual column search.
|
||||
"""
|
||||
search_filters = Q()
|
||||
if search_value:
|
||||
for field in search_fields:
|
||||
search_filters |= Q(**{f'{field}__icontains': search_value})
|
||||
if 'columns' in request.GET:
|
||||
search_filters = Q()
|
||||
for i, column_index in enumerate(request.GET.getlist('order[][column]')):
|
||||
if request.GET.get(f'columns[{column_index}][search][value]'):
|
||||
field = self.model._meta.get_field(int(column_index)).name
|
||||
search_filters |= Q(**{f'{field}__icontains': request.GET.get(f'columns[{column_index}][search][value]')})
|
||||
return search_filters
|
||||
|
||||
def get_pagination(self, queryset, start, length):
|
||||
"""
|
||||
Performs pagination based on the requested page and page size.
|
||||
"""
|
||||
paginator = Paginator(queryset, length)
|
||||
page_number = (int(start) // int(length)) + 1
|
||||
page_obj = paginator.page(page_number)
|
||||
|
||||
total_count = paginator.count
|
||||
filtered_count = len(page_obj.object_list)
|
||||
|
||||
return page_obj, total_count, filtered_count
|
||||
|
||||
def prepare_datatables_response(self, draw, total_count, filtered_count, data):
|
||||
"""
|
||||
Prepares the JSON response for Datatables.
|
||||
"""
|
||||
return JsonResponse({
|
||||
"draw": draw,
|
||||
"recordsTotal": total_count,
|
||||
"recordsFiltered": filtered_count,
|
||||
"data": data
|
||||
})
|
||||
255
module_project/service.py
Normal file
255
module_project/service.py
Normal file
@@ -0,0 +1,255 @@
|
||||
from django.conf import settings
|
||||
from django.core.files.uploadedfile import UploadedFile
|
||||
from django.core.mail import EmailMessage
|
||||
from django.utils.html import strip_tags
|
||||
from django.template.loader import render_to_string
|
||||
from django.shortcuts import get_object_or_404
|
||||
from smtplib import SMTPException
|
||||
from module_iam.models import IAmPrincipal, IAmPrincipalOtp, IAmPrincipalType
|
||||
from .utils import RandomGenerator
|
||||
# from twilio.rest import Client
|
||||
from django.db.models import Q
|
||||
import phonenumbers
|
||||
from decimal import Decimal
|
||||
from django.db.models import F
|
||||
from django.db import transaction
|
||||
from datetime import timedelta, time, datetime
|
||||
from django.utils import timezone
|
||||
# from onesignal_sdk.client import Client as OneSignalClient
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EmailService:
|
||||
email = None
|
||||
body = None
|
||||
subject = None
|
||||
to = None
|
||||
from_email = None
|
||||
|
||||
content_subtype = "html"
|
||||
|
||||
def __init__(self, subject=None, to=None, from_email=None):
|
||||
self.subject = subject
|
||||
self.to = (to,)
|
||||
self.from_email = from_email
|
||||
|
||||
def set_to(self, to):
|
||||
self.to = to
|
||||
|
||||
def set_subject(self, subject):
|
||||
self.subject = subject
|
||||
|
||||
def set_from_email(self, from_email):
|
||||
self.from_email = from_email
|
||||
|
||||
def set_text_body(self, body):
|
||||
self.body = strip_tags(body)
|
||||
|
||||
def set_html_body(self, html_body):
|
||||
self.body = html_body
|
||||
|
||||
def load_template(self, path=None, context={}):
|
||||
if path is None:
|
||||
raise Exception("Email temaplate path is not provided.")
|
||||
|
||||
self.content_subtype = "html"
|
||||
html_body = render_to_string(path, context=context)
|
||||
self.body = html_body
|
||||
|
||||
def attach(self, file_path):
|
||||
self.email.attach_file(file_path)
|
||||
|
||||
def send(self):
|
||||
try:
|
||||
self.email = EmailMessage(
|
||||
subject=self.subject,
|
||||
body=self.body,
|
||||
to=self.to,
|
||||
from_email=self.from_email,
|
||||
)
|
||||
|
||||
self.email.content_subtype = self.content_subtype
|
||||
|
||||
self.email.send()
|
||||
except SMTPException as e:
|
||||
logger.error(str(e))
|
||||
|
||||
|
||||
class SMSError(Exception):
|
||||
def __init__(self, message, payload=None):
|
||||
self.message = message
|
||||
self.payload = payload
|
||||
|
||||
def __str__(self):
|
||||
return str(self.message)
|
||||
|
||||
|
||||
class SMSService:
|
||||
# def send(self, to: list, text: str):
|
||||
# """
|
||||
# Sends text sms to the given user(s).
|
||||
|
||||
# Parameters:
|
||||
# to (list): list of phone numbers
|
||||
|
||||
# text (str): a text message.
|
||||
|
||||
# Return:
|
||||
# True or False
|
||||
# """
|
||||
|
||||
# # if settings.TESTING_ENV:
|
||||
# # logger.info(f"TESTING ENV SMS LOG : {text}")
|
||||
# # return True
|
||||
|
||||
# account_sid = settings.TWILIO_ACCOUNT_SID
|
||||
# auth_token = settings.TWILIO_AUTH_TOKEN
|
||||
# my_twilio_number = settings.MY_TWILIO_NUMBER
|
||||
|
||||
# client = Client(account_sid, auth_token)
|
||||
|
||||
# try:
|
||||
# for number in to:
|
||||
# logger.info("SENDING SMS TO " + str(number))
|
||||
# message = client.messages.create(
|
||||
# from_=my_twilio_number, body=text, to=number
|
||||
# )
|
||||
|
||||
# except Exception as e:
|
||||
# logger.error(str(e))
|
||||
|
||||
# raise SMSError(message=str(e))
|
||||
|
||||
def create_otp(self, principal: IAmPrincipal, otp_purpose: str):
|
||||
otp = IAmPrincipalOtp.objects.create(
|
||||
principal=principal, otp_purpose=otp_purpose
|
||||
)
|
||||
otp.save()
|
||||
return otp.otp_code
|
||||
|
||||
def send_otp(self, principal: IAmPrincipal, otp_purpose: str):
|
||||
"""
|
||||
Sends otp to the given user.
|
||||
|
||||
Parameters:
|
||||
user (User): User object
|
||||
otp_purpose (str) : a text that describe otp purpose
|
||||
|
||||
Return:
|
||||
True or False
|
||||
"""
|
||||
|
||||
if not isinstance(principal, IAmPrincipal):
|
||||
raise Exception(
|
||||
f"parameter 'principal' required type of User object, Given {type(principal)} type object"
|
||||
)
|
||||
|
||||
otp_code = self.create_otp(principal=principal, otp_purpose=otp_purpose)
|
||||
# below working will change as it is temporary purpose
|
||||
body = f"Your Nifty11 OTP is {otp_code}."
|
||||
|
||||
print(body)
|
||||
|
||||
phone_numbers = []
|
||||
|
||||
try:
|
||||
parsed_number = phonenumbers.parse(str(principal.phone_no), None)
|
||||
if phonenumbers.is_valid_number(parsed_number):
|
||||
formatted_number = phonenumbers.format_number(
|
||||
parsed_number, phonenumbers.PhoneNumberFormat.E164
|
||||
)
|
||||
phone_numbers.append(formatted_number)
|
||||
else:
|
||||
raise ValueError("Invalid phone number")
|
||||
except Exception as e:
|
||||
logger.warning(f"{e}")
|
||||
raise ValueError("Invalid phone number")
|
||||
|
||||
if not phone_numbers:
|
||||
raise ValueError("Invalid phone number")
|
||||
|
||||
print(f"phone number {type(phone_numbers)} {phone_numbers}")
|
||||
|
||||
# self.send(phone_numbers, body)
|
||||
return otp_code
|
||||
|
||||
|
||||
# class OneSignalNotificationService:
|
||||
|
||||
# """
|
||||
# Class for sending notifications using the OneSignal API.
|
||||
|
||||
# Provides a convenient way to create and send notifications to OneSignal users,
|
||||
# with features like targeting specific devices or segments, customizing notification content,
|
||||
# and handling errors gracefully.
|
||||
|
||||
# **Parameters:**
|
||||
|
||||
# - **app_id** (str): Your OneSignal App ID.
|
||||
# - **rest_api_key** (str): Your OneSignal REST API Key.
|
||||
# - **user_auth_key** (str): Your OneSignal User Auth Key.
|
||||
|
||||
# **Keyword Arguments:**
|
||||
|
||||
# This method accepts additional keyword arguments (`**kwargs`) to customize the notification
|
||||
# further, including:
|
||||
|
||||
# - `url` (str): URL to open when the notification is clicked.
|
||||
# - `data` (dict): Custom data to be sent with the notification.
|
||||
# - `buttons` (list): List of action buttons to display within the notification.
|
||||
# - `send_after` (str): Timestamp for scheduling the notification.
|
||||
# - `delayed_option` (dict): Option for delayed delivery (Android-specific).
|
||||
# - `android_channel_id` (str): Channel ID for Android notifications.
|
||||
# - `ios_sound` (str): Sound to play for iOS notifications.
|
||||
# - `ios_badgeType` (str): Badge type for iOS notifications.
|
||||
# - `ios_badgeCount` (int): Badge count for iOS notifications.
|
||||
# - `ios_thread_id` (str): Thread ID to group notifications in iOS.
|
||||
# - `android_background_layout` (str): Layout for background notifications on Android.
|
||||
# - `android_group` (str): Group notification on Android.
|
||||
# - `android_group_message` (str): Summary for grouped notifications on Android.
|
||||
# - `android_group_summary` (str): Summary for grouped notifications on Android.
|
||||
# - `android_led_color` (str): LED color for Android notifications.
|
||||
# - `android_accent_color` (str): Accent color for Android notifications.
|
||||
# - `android_visibility` (str): Visibility settings for Android notifications.
|
||||
|
||||
# **Example usage:**
|
||||
|
||||
# notification = OneSignalNotificationService()
|
||||
# response = notification.send_notification(
|
||||
# headings="Welcome",
|
||||
# message="Thanks for signing up!",
|
||||
# player_tokens=["PLAYER_TOKEN1", "PLAYER_TOKEN2"],
|
||||
# url="https://yourwebsite.com/welcome",
|
||||
# data={"user_id": 123},
|
||||
# )
|
||||
# """
|
||||
|
||||
# def __init__(self):
|
||||
# self.config = OneSignalClient(
|
||||
# app_id=settings.ONESIGNAL_APP_ID,
|
||||
# rest_api_key=settings.ONESIGNAL_REST_API_KEY,
|
||||
# user_auth_key=settings.ONESIGNAL_USER_AUTH_KEY
|
||||
# )
|
||||
|
||||
# # Set up logging
|
||||
# self.logger = logging.getLogger(__name__)
|
||||
|
||||
# def send_notification(self, headings, message, player_tokens=None, **kwargs):
|
||||
# notification_obj = {
|
||||
# "headings": {"en": headings},
|
||||
# "contents": {"en": message},
|
||||
# **kwargs
|
||||
# }
|
||||
|
||||
# if player_tokens:
|
||||
# notification_obj["include_player_ids"] = player_tokens
|
||||
|
||||
# try:
|
||||
# response = self.config.send_notification(notification_obj)
|
||||
# self.logger.info(f"Notification send successfully : {response}")
|
||||
# return response
|
||||
# except Exception as e:
|
||||
# self.logger.error(f"OneSignal error {e}")
|
||||
# raise Exception("Generic OneSignal error: {}".format(e))
|
||||
23
module_project/settings/__init__.py
Normal file
23
module_project/settings/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import environ
|
||||
from pathlib import Path
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
env = environ.Env()
|
||||
|
||||
READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=True)
|
||||
if READ_DOT_ENV_FILE:
|
||||
# OS environment variables take precedence over variables from .env
|
||||
env.read_env(str(BASE_DIR / ".env"))
|
||||
|
||||
# Access the "ENV_NAME" environment variable using env
|
||||
env_name = env("ENV_NAME")
|
||||
|
||||
if env_name == 'Production':
|
||||
from .production import * # noqa
|
||||
elif env_name == 'Staging':
|
||||
from .staging import * # noqa
|
||||
elif env_name == 'Development':
|
||||
from .development import * # noqa
|
||||
else:
|
||||
raise ValueError("Invalid or missing ENV_NAME environment variable")
|
||||
276
module_project/settings/base.py
Normal file
276
module_project/settings/base.py
Normal file
@@ -0,0 +1,276 @@
|
||||
"""
|
||||
Django settings for module_project 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 environ
|
||||
from pathlib import Path
|
||||
from django.contrib.messages import constants as messages
|
||||
import colorlog
|
||||
import datetime
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
env = environ.Env()
|
||||
|
||||
READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=True)
|
||||
if READ_DOT_ENV_FILE:
|
||||
# OS environment variables take precedence over variables from .env
|
||||
env.read_env(str(BASE_DIR / ".env"))
|
||||
|
||||
# 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-#7rdu=fr58ba9_!n3$l5pm!xs8l%6%8xt@vb8$&o@hqhd@rtd%'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
DJANGO_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
]
|
||||
|
||||
LOCAL_APPS = [
|
||||
"module_iam",
|
||||
"module_auth",
|
||||
"module_activity",
|
||||
"module_cms",
|
||||
"module_support",
|
||||
]
|
||||
|
||||
THIRD_PARTY_APPS = [
|
||||
"corsheaders",
|
||||
"widget_tweaks",
|
||||
"rest_framework_simplejwt",
|
||||
"taggit",
|
||||
"django_quill",
|
||||
]
|
||||
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
||||
|
||||
|
||||
MIDDLEWARE = [
|
||||
"corsheaders.middleware.CorsMiddleware",
|
||||
'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 = 'module_project.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [BASE_DIR.joinpath("templates")],
|
||||
'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 = 'module_project.wsgi.application'
|
||||
# WSGI_APPLICATION = 'module_project.asgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.mysql",
|
||||
"NAME": "digest_db",
|
||||
"HOST": env.str("DB_HOST"),
|
||||
"USER": env.str("DB_USERNAME"),
|
||||
"PASSWORD": env.str("DB_PASSWORD"),
|
||||
"PORT": env.str("DB_PORT"),
|
||||
}
|
||||
}
|
||||
# DATABASES["default"]["ATOMIC_REQUESTS"] = True
|
||||
|
||||
# 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 = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
SHORT_DATETIME_FORMAT = "d-m-Y H:i:s"
|
||||
|
||||
SHORT_DATE_FORMAT = "d-m-Y"
|
||||
|
||||
TIME_FORMAT = "H:i p"
|
||||
|
||||
# otp expire time limit
|
||||
OTP_EXPIRE_TIME = 10 # mins
|
||||
|
||||
APPEND_SLASH = True
|
||||
LOGIN_REDIRECT_URL = "/iam/dashboard/"
|
||||
LOGIN_URL = "/auth/login/"
|
||||
LOGOUT_REDIRECT_URL = "/auth/login/"
|
||||
|
||||
|
||||
# https://docs.djangoproject.com/en/4.2/topics/auth/customizing/#substituting-a-custom-user-model
|
||||
AUTH_USER_MODEL = "module_iam.IAmPrincipal"
|
||||
|
||||
# https://docs.djangoproject.com/en/4.2/topics/auth/customizing/
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
# 'accounts.backend.EmailBackend',
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
]
|
||||
|
||||
|
||||
# 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'
|
||||
|
||||
|
||||
# rest framework permission and authentication settings
|
||||
# https://www.django-rest-framework.org/api-guide/permissions/#setting-the-permission-policy
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_PERMISSION_CLASSES": [
|
||||
"rest_framework.permissions.IsAuthenticated",
|
||||
],
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
),
|
||||
}
|
||||
|
||||
MESSAGE_TAGS = {
|
||||
messages.DEBUG: "alert-info",
|
||||
messages.INFO: "alert-info",
|
||||
messages.SUCCESS: "alert-success",
|
||||
messages.WARNING: "alert-warning",
|
||||
messages.ERROR: "alert-danger",
|
||||
}
|
||||
|
||||
|
||||
# smtp email settings
|
||||
# https://docs.djangoproject.com/en/4.2/topics/email/#smtp-backend
|
||||
|
||||
EMAIL_BACKEND = env.str(
|
||||
"EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend"
|
||||
)
|
||||
EMAIL_HOST = env.str("EMAIL_HOST")
|
||||
EMAIL_HOST_USER = env.str("EMAIL_HOST_USER")
|
||||
EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD")
|
||||
EMAIL_PORT = env.str("EMAIL_PORT")
|
||||
EMAIL_USE_TLS = True
|
||||
|
||||
# LOGGING
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/4.2/topics/logging/#logging
|
||||
# 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": {
|
||||
"()": colorlog.ColoredFormatter,
|
||||
"format": "%(cyan)s%(asctime)s%(reset)s | %(red)s[%(levelname)8s]%(reset)s | [ %(yellow)s%(name)s.%(module)s:%(white)s%(lineno)d%(reset)s - %(green)s%(funcName)10s()%(reset)s ] --> %(message)s",
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
"log_colors": {
|
||||
"DEBUG": "white",
|
||||
"INFO": "green",
|
||||
"WARNING": "yellow",
|
||||
"ERROR": "red",
|
||||
"CRITICAL": "bold_red",
|
||||
},
|
||||
"secondary_log_colors": {},
|
||||
"style": "%",
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"level": "DEBUG",
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "verbose",
|
||||
}
|
||||
},
|
||||
"root": {"level": "INFO", "handlers": ["console"]},
|
||||
}
|
||||
|
||||
|
||||
# jwt configuration
|
||||
# https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html#settings
|
||||
SIMPLE_JWT = {
|
||||
"ACCESS_TOKEN_LIFETIME": datetime.timedelta(days=10),
|
||||
"REFRESH_TOKEN_LIFETIME": datetime.timedelta(days=15),
|
||||
"ROTATE_REFRESH_TOKENS": False,
|
||||
"BLACKLIST_AFTER_ROTATION": False,
|
||||
"UPDATE_LAST_LOGIN": False,
|
||||
"ALGORITHM": "HS256",
|
||||
"SIGNING_KEY": SECRET_KEY,
|
||||
"VERIFYING_KEY": "",
|
||||
"AUDIENCE": None,
|
||||
"ISSUER": None,
|
||||
"JSON_ENCODER": None,
|
||||
"JWK_URL": None,
|
||||
"LEEWAY": 0,
|
||||
"AUTH_HEADER_TYPES": ("Bearer",),
|
||||
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
|
||||
"USER_ID_FIELD": "id",
|
||||
"USER_ID_CLAIM": "user_id",
|
||||
"USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
|
||||
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
|
||||
"TOKEN_TYPE_CLAIM": "token_type",
|
||||
"TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
|
||||
"JTI_CLAIM": "jti",
|
||||
}
|
||||
46
module_project/settings/development.py
Normal file
46
module_project/settings/development.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from .base import * # noqa
|
||||
import os
|
||||
|
||||
DEBUG = True
|
||||
ALLOWED_HOSTS = [
|
||||
"*",
|
||||
]
|
||||
|
||||
# CORS
|
||||
# CORS_ALLOWED_ORIGINS = [
|
||||
# # "http://127.0.0.1:3000",
|
||||
# ]
|
||||
|
||||
|
||||
# CORS_ORIGIN_ALLOW_ALL = True
|
||||
|
||||
|
||||
# CORS_ORIGIN_WHITELIST = ("http://localhost:3000",)
|
||||
|
||||
if DEBUG:
|
||||
MIDDLEWARE += [
|
||||
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
||||
]
|
||||
INSTALLED_APPS += [
|
||||
"debug_toolbar",
|
||||
"django_extensions",
|
||||
]
|
||||
INTERNAL_IPS = [
|
||||
"127.0.0.1",
|
||||
]
|
||||
|
||||
BASE_DOMAIN = ""
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
|
||||
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
|
||||
|
||||
# STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
|
||||
STATICFILES_DIRS = [BASE_DIR.joinpath("static")]
|
||||
87
module_project/settings/production.py
Normal file
87
module_project/settings/production.py
Normal file
@@ -0,0 +1,87 @@
|
||||
from .base import * # noqa
|
||||
from .base import env, BASE_DIR
|
||||
import os
|
||||
import colorlog
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
|
||||
DEBUG = False
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
# CORS_ALLOWED_ORIGINS = [
|
||||
# # "http://127.0.0.1:3000",
|
||||
# ]
|
||||
|
||||
|
||||
# CORS_ORIGIN_ALLOW_ALL = True
|
||||
|
||||
|
||||
# CORS_ORIGIN_WHITELIST = ("",)
|
||||
|
||||
|
||||
LOGGING_DIR = os.path.join(
|
||||
BASE_DIR, "logs"
|
||||
) # Define the directory where log files will be stored
|
||||
|
||||
# Ensure the directory exists; create it if it doesn't
|
||||
if not os.path.exists(LOGGING_DIR):
|
||||
os.makedirs(LOGGING_DIR)
|
||||
|
||||
LOGGING_LEVEL = env.str(
|
||||
"LOG_LEVEL", "INFO"
|
||||
) # Set your desired log level (e.g., DEBUG, INFO, WARNING, ERROR)
|
||||
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"verbose": {
|
||||
"()": colorlog.ColoredFormatter,
|
||||
"format": "%(cyan)s%(asctime)s%(reset)s | %(red)s[%(levelname)8s]%(reset)s | [ %(yellow)s%(name)s.%(module)s:%(white)s%(lineno)d%(reset)s - %(green)s%(funcName)10s()%(reset)s ] --> %(message)s",
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
"log_colors": {
|
||||
"DEBUG": "white",
|
||||
"INFO": "green",
|
||||
"WARNING": "yellow",
|
||||
"ERROR": "red",
|
||||
"CRITICAL": "bold_red",
|
||||
},
|
||||
"secondary_log_colors": {},
|
||||
"style": "%",
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"logfile": {
|
||||
"level": LOGGING_LEVEL,
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": os.path.join(LOGGING_DIR, "errors.log"),
|
||||
'maxBytes': 5242880, # 5*1024*1024 bytes (5MB)
|
||||
"backupCount": 10, # Number of log files to keep (15 days' worth of logs)
|
||||
"formatter": "verbose",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"django": {
|
||||
"handlers": ["logfile"],
|
||||
"level": LOGGING_LEVEL,
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
BASE_DOMAIN = ""
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
|
||||
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
|
||||
|
||||
# STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
|
||||
STATICFILES_DIRS = [BASE_DIR.joinpath("static")]
|
||||
85
module_project/settings/staging.py
Normal file
85
module_project/settings/staging.py
Normal file
@@ -0,0 +1,85 @@
|
||||
from .base import * # noqa
|
||||
from .base import env, BASE_DIR
|
||||
import os
|
||||
import colorlog
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
|
||||
DEBUG = False
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
# CORS_ALLOWED_ORIGINS = [
|
||||
# "http://127.0.0.1:3000",
|
||||
# ]
|
||||
|
||||
|
||||
# CORS_ORIGIN_ALLOW_ALL = True
|
||||
|
||||
|
||||
# CORS_ORIGIN_WHITELIST = ("http://localhost:3000",)
|
||||
|
||||
|
||||
LOGGING_DIR = os.path.join(
|
||||
BASE_DIR, "logs"
|
||||
) # Define the directory where log files will be stored
|
||||
|
||||
# Ensure the directory exists; create it if it doesn't
|
||||
if not os.path.exists(LOGGING_DIR):
|
||||
os.makedirs(LOGGING_DIR)
|
||||
|
||||
LOGGING_LEVEL = env.str(
|
||||
"LOG_LEVEL", "INFO"
|
||||
) # Set your desired log level (e.g., DEBUG, INFO, WARNING, ERROR) in the env file
|
||||
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"verbose": {
|
||||
"()": colorlog.ColoredFormatter,
|
||||
"format": "%(cyan)s%(asctime)s%(reset)s | %(red)s[%(levelname)8s]%(reset)s | [ %(yellow)s%(name)s.%(module)s:%(white)s%(lineno)d%(reset)s - %(green)s%(funcName)10s()%(reset)s ] --> %(message)s",
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
"log_colors": {
|
||||
"DEBUG": "white",
|
||||
"INFO": "green",
|
||||
"WARNING": "yellow",
|
||||
"ERROR": "red",
|
||||
"CRITICAL": "bold_red",
|
||||
},
|
||||
"secondary_log_colors": {},
|
||||
"style": "%",
|
||||
}
|
||||
},
|
||||
"handlers": {
|
||||
"logfile": {
|
||||
"level": LOGGING_LEVEL,
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": os.path.join(LOGGING_DIR, "errors.log"),
|
||||
'maxBytes': 5242880, # 5*1024*1024 bytes (5MB)
|
||||
"backupCount": 10, # Number of log files to keep (15 days' worth of logs)
|
||||
"formatter": "verbose",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"django": {
|
||||
"handlers": ["logfile"],
|
||||
"level": LOGGING_LEVEL,
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
BASE_DOMAIN = ""
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
|
||||
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
|
||||
|
||||
# STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
|
||||
STATICFILES_DIRS = [BASE_DIR.joinpath("static")]
|
||||
123
module_project/settings_file.py
Normal file
123
module_project/settings_file.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""
|
||||
Django settings for module_project 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/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# 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-#7rdu=fr58ba9_!n3$l5pm!xs8l%6%8xt@vb8$&o@hqhd@rtd%'
|
||||
|
||||
# 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',
|
||||
]
|
||||
|
||||
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 = 'module_project.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 = 'module_project.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 = 'en-us'
|
||||
|
||||
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'
|
||||
44
module_project/urls.py
Normal file
44
module_project/urls.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""
|
||||
URL configuration for module_project project.
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
|
||||
path('iam/', include('module_iam.urls')),
|
||||
|
||||
path('auth/', include('module_auth.urls')),
|
||||
path('api/auth/', include('module_auth.api.urls')),
|
||||
|
||||
path('cms/', include('module_cms.urls')),
|
||||
path('api/cms/', include('module_cms.api.urls')),
|
||||
|
||||
# path('support/', include('module_support.urls')),
|
||||
path('api/support/', include('module_support.api.urls')),
|
||||
|
||||
path('activity/', include("module_activity.urls")),
|
||||
path('api/activity/', include("module_activity.api.urls")),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
import debug_toolbar
|
||||
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
urlpatterns += [path('__debug__/', include(debug_toolbar.urls))]
|
||||
77
module_project/utils.py
Normal file
77
module_project/utils.py
Normal file
@@ -0,0 +1,77 @@
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.exceptions import NotFound
|
||||
from django.http import JsonResponse
|
||||
from . import constants
|
||||
from rest_framework import status
|
||||
import string
|
||||
import random
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
|
||||
class GroupWriteRotatingFileHandler(logging.handlers.RotatingFileHandler):
|
||||
|
||||
def doRollover(self):
|
||||
"""
|
||||
Overrides base class method to make the new log file group writable.
|
||||
"""
|
||||
# Rotate the file first.
|
||||
logging.handlers.RotatingFileHandler.doRollover(self)
|
||||
|
||||
# Add group write to the current permissions.
|
||||
currMode = os.stat(self.baseFilename).st_mode
|
||||
os.chmod(self.baseFilename, currMode | stat.S_IWGRP)
|
||||
|
||||
class ApiResponse:
|
||||
@staticmethod
|
||||
def success(message, data=None, status=status.HTTP_200_OK):
|
||||
response_data = {"success": True, "status": status, "message": message}
|
||||
if data is not None:
|
||||
response_data["data"] = data
|
||||
return Response(response_data, status=status)
|
||||
|
||||
@staticmethod
|
||||
def error(message, errors=None, status=status.HTTP_403_FORBIDDEN):
|
||||
response_data = {"success": False, "status": status, "message": message}
|
||||
if errors is not None:
|
||||
response_data["errors"] = errors
|
||||
return Response(response_data, status=status)
|
||||
|
||||
# @staticmethod
|
||||
# def validation_error(errors, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY):
|
||||
# return ApiResponse.error("Validation error", errors, status_code)
|
||||
|
||||
class JsonResponseUtil:
|
||||
@staticmethod
|
||||
def success(message, data=None, status_code=200):
|
||||
response_data = {"success": True, "status": status_code, "message": message}
|
||||
if data is not None:
|
||||
response_data["data"] = data
|
||||
return JsonResponse(response_data, status=status_code)
|
||||
|
||||
@staticmethod
|
||||
def error(message, errors=None, status_code=403):
|
||||
response_data = {"success": False, "status": status_code, "message": message}
|
||||
if errors is not None:
|
||||
response_data["errors"] = errors
|
||||
return JsonResponse(response_data, status=status_code)
|
||||
|
||||
|
||||
class RandomGenerator:
|
||||
@staticmethod
|
||||
def number(start, end):
|
||||
# import random
|
||||
return random.randint(start, end)
|
||||
|
||||
@staticmethod
|
||||
def password_reset_code():
|
||||
return RandomGenerator.number(10000000, 99999999)
|
||||
|
||||
def random_otp():
|
||||
return RandomGenerator.number(1000, 9999)
|
||||
|
||||
@staticmethod
|
||||
def random_alphnum(length):
|
||||
return "".join(
|
||||
random.choice(string.ascii_uppercase + string.digits) for _ in range(length)
|
||||
)
|
||||
16
module_project/wsgi.py
Normal file
16
module_project/wsgi.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for module_project 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', 'module_project.settings')
|
||||
|
||||
application = get_wsgi_application()
|
||||
0
module_report/__init__.py
Normal file
0
module_report/__init__.py
Normal file
3
module_report/admin.py
Normal file
3
module_report/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
module_report/apps.py
Normal file
6
module_report/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ModuleReportConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'module_report'
|
||||
0
module_report/migrations/__init__.py
Normal file
0
module_report/migrations/__init__.py
Normal file
3
module_report/models.py
Normal file
3
module_report/models.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
module_report/tests.py
Normal file
3
module_report/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
3
module_report/views.py
Normal file
3
module_report/views.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
0
module_support/__init__.py
Normal file
0
module_support/__init__.py
Normal file
3
module_support/admin.py
Normal file
3
module_support/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
13
module_support/api/serializers.py
Normal file
13
module_support/api/serializers.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from rest_framework import serializers
|
||||
from module_support.models import ContactUs, Feedback
|
||||
|
||||
class ContactUsSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ContactUs
|
||||
fields = ["email_address", "subject", "message"]
|
||||
|
||||
|
||||
class FeedbackSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Feedback
|
||||
fields = ["feedback_reaction", "comment"]
|
||||
7
module_support/api/urls.py
Normal file
7
module_support/api/urls.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path("contact-us/", views.ContactusAPIView.as_view()),
|
||||
path("feedback/", views.FeedbackAPIView.as_view()),
|
||||
]
|
||||
41
module_support/api/views.py
Normal file
41
module_support/api/views.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework_simplejwt.authentication import JWTAuthentication
|
||||
from module_project import constants
|
||||
from module_project.utils import ApiResponse
|
||||
from .serializers import ContactUsSerializer, FeedbackSerializer
|
||||
from ..models import ContactUs, Feedback
|
||||
|
||||
|
||||
class ContactusAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = ContactUsSerializer
|
||||
model = ContactUs
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=serializer.errors)
|
||||
try:
|
||||
serializer.save()
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
|
||||
|
||||
class FeedbackAPIView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = FeedbackSerializer
|
||||
model = Feedback
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=serializer.errors)
|
||||
try:
|
||||
serializer.save(principal=request.user)
|
||||
except Exception as e:
|
||||
return ApiResponse.error(message=constants.FAILURE, errors=str(e))
|
||||
return ApiResponse.success(message=constants.SUCCESS, data=serializer.data)
|
||||
6
module_support/apps.py
Normal file
6
module_support/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ModuleSupportConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'module_support'
|
||||
38
module_support/migrations/0001_initial.py
Normal file
38
module_support/migrations/0001_initial.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-14 14:51
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ContactUs',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('email_address', models.EmailField(max_length=254)),
|
||||
('mobile_number', models.CharField(blank=True, max_length=15, null=True)),
|
||||
('subject', models.CharField(max_length=200)),
|
||||
('message', models.TextField()),
|
||||
('reply', models.TextField(blank=True, null=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'contact_us',
|
||||
},
|
||||
),
|
||||
]
|
||||
35
module_support/migrations/0002_feedback.py
Normal file
35
module_support/migrations/0002_feedback.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# Generated by Django 5.0.2 on 2024-02-15 05:54
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('module_support', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Feedback',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('deleted', models.BooleanField(default=False)),
|
||||
('created_on', models.DateTimeField(auto_now_add=True)),
|
||||
('modified_on', models.DateTimeField(auto_now=True)),
|
||||
('email', models.EmailField(blank=True, help_text='Email address of the feedback provider', max_length=254, null=True)),
|
||||
('comment', models.TextField(help_text='Feedback comment')),
|
||||
('feedback_reaction', models.CharField(blank=True, help_text='Reaction associated with the feedback', max_length=20, null=True)),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modified', to=settings.AUTH_USER_MODEL)),
|
||||
('principal', models.ForeignKey(blank=True, help_text='User associated with this feedback', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='feedbacks', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'feedback',
|
||||
},
|
||||
),
|
||||
]
|
||||
0
module_support/migrations/__init__.py
Normal file
0
module_support/migrations/__init__.py
Normal file
40
module_support/models.py
Normal file
40
module_support/models.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from django.db import models
|
||||
from module_iam.models import BaseModel, IAmPrincipal
|
||||
|
||||
# Create your models here.
|
||||
|
||||
class ContactUs(BaseModel):
|
||||
name = models.CharField(max_length=100, blank=True, null=True)
|
||||
email_address = models.EmailField()
|
||||
mobile_number = models.CharField(max_length=15, blank=True, null=True)
|
||||
subject = models.CharField(max_length=200)
|
||||
message = models.TextField()
|
||||
reply = models.TextField(blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "contact_us"
|
||||
|
||||
|
||||
class Feedback(BaseModel):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="feedbacks",
|
||||
help_text="User associated with this feedback",
|
||||
)
|
||||
email = models.EmailField(null=True, blank=True, help_text="Email address of the feedback provider")
|
||||
comment = models.TextField(help_text="Feedback comment")
|
||||
feedback_reaction = models.CharField(
|
||||
max_length=20,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Reaction associated with the feedback",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = "feedback"
|
||||
|
||||
def __str__(self):
|
||||
return f"Author: {self.principal}, Comment: {self.comment}"
|
||||
3
module_support/tests.py
Normal file
3
module_support/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user