mirror of
https://github.com/lemeow125/DocManagerBackend.git
synced 2025-01-18 17:13:00 +08:00
Move sex and age fields from questionnaire to user and add planning role restrictions
This commit is contained in:
parent
724132e396
commit
e0eba6ca21
25 changed files with 157 additions and 320 deletions
|
@ -10,7 +10,8 @@ class CustomUserAdmin(UserAdmin):
|
||||||
readonly_fields = ("date_joined",)
|
readonly_fields = ("date_joined",)
|
||||||
|
|
||||||
# Add this line to include the role field in the admin form
|
# Add this line to include the role field in the admin form
|
||||||
fieldsets = UserAdmin.fieldsets + ((None, {"fields": ("role",)}),)
|
fieldsets = UserAdmin.fieldsets + \
|
||||||
|
((None, {"fields": ("role", "sex", "birthday")}),)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(CustomUser, CustomUserAdmin)
|
admin.site.register(CustomUser, CustomUserAdmin)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-23 17:01
|
# Generated by Django 5.1.3 on 2024-12-03 16:27
|
||||||
|
|
||||||
import django.contrib.auth.models
|
import django.contrib.auth.models
|
||||||
import django.contrib.auth.validators
|
import django.contrib.auth.validators
|
||||||
|
@ -106,6 +106,13 @@ class Migration(migrations.Migration):
|
||||||
default=django.utils.timezone.now, editable=False
|
default=django.utils.timezone.now, editable=False
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"sex",
|
||||||
|
models.CharField(
|
||||||
|
choices=[("male", "Male"), ("female", "Female")], max_length=32
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("birthday", models.DateField()),
|
||||||
(
|
(
|
||||||
"groups",
|
"groups",
|
||||||
models.ManyToManyField(
|
models.ManyToManyField(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now, localdate
|
||||||
|
|
||||||
|
|
||||||
class CustomUser(AbstractUser):
|
class CustomUser(AbstractUser):
|
||||||
|
@ -22,10 +22,33 @@ class CustomUser(AbstractUser):
|
||||||
("staff", "Staff"),
|
("staff", "Staff"),
|
||||||
)
|
)
|
||||||
|
|
||||||
role = models.CharField(max_length=32, choices=ROLE_CHOICES, default="client")
|
role = models.CharField(
|
||||||
|
max_length=32, choices=ROLE_CHOICES, default="client")
|
||||||
|
|
||||||
date_joined = models.DateTimeField(default=now, editable=False)
|
date_joined = models.DateTimeField(default=now, editable=False)
|
||||||
|
|
||||||
|
SEX_CHOICES = (
|
||||||
|
("male", "Male"),
|
||||||
|
("female", "Female"),
|
||||||
|
)
|
||||||
|
|
||||||
|
sex = models.CharField(
|
||||||
|
max_length=32, choices=SEX_CHOICES, blank=False, null=False)
|
||||||
|
birthday = models.DateField(blank=False, null=False)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def age(self):
|
||||||
|
date_now = localdate(now())
|
||||||
|
age = (
|
||||||
|
date_now.year
|
||||||
|
- self.birthday.year
|
||||||
|
- (
|
||||||
|
(date_now.month, date_now.day)
|
||||||
|
< (self.birthday.month, self.birthday.day)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return age
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_name(self):
|
def full_name(self):
|
||||||
return f"{self.first_name} {self.last_name}"
|
return f"{self.first_name} {self.last_name}"
|
||||||
|
|
|
@ -12,6 +12,15 @@ class IsStaff(BasePermission):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class IsPlanning(BasePermission):
|
||||||
|
"""
|
||||||
|
Allows access only to users with head, admin planning role
|
||||||
|
"""
|
||||||
|
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return bool(request.user and request.user.role in ("head", "admin", "planning"))
|
||||||
|
|
||||||
|
|
||||||
class IsHead(BasePermission):
|
class IsHead(BasePermission):
|
||||||
"""
|
"""
|
||||||
Allows access only to users with staff role
|
Allows access only to users with staff role
|
||||||
|
|
|
@ -6,6 +6,8 @@ from rest_framework.settings import api_settings
|
||||||
|
|
||||||
|
|
||||||
class CustomUserSerializer(serializers.ModelSerializer):
|
class CustomUserSerializer(serializers.ModelSerializer):
|
||||||
|
birthday = serializers.DateField(format="%m-%d-%Y")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CustomUser
|
model = CustomUser
|
||||||
fields = [
|
fields = [
|
||||||
|
@ -16,8 +18,22 @@ class CustomUserSerializer(serializers.ModelSerializer):
|
||||||
"last_name",
|
"last_name",
|
||||||
"full_name",
|
"full_name",
|
||||||
"role",
|
"role",
|
||||||
|
"birthday",
|
||||||
|
"age",
|
||||||
|
"sex",
|
||||||
|
"date_joined",
|
||||||
|
]
|
||||||
|
read_only_fields = [
|
||||||
|
"id",
|
||||||
|
"username",
|
||||||
|
"email",
|
||||||
|
"full_name",
|
||||||
|
"role",
|
||||||
|
"birthday",
|
||||||
|
"age",
|
||||||
|
"sex",
|
||||||
|
"date_joined",
|
||||||
]
|
]
|
||||||
read_only_fields = ["id", "username", "email", "full_name", "role"]
|
|
||||||
|
|
||||||
|
|
||||||
class CustomUserRegistrationSerializer(serializers.ModelSerializer):
|
class CustomUserRegistrationSerializer(serializers.ModelSerializer):
|
||||||
|
@ -27,10 +43,12 @@ class CustomUserRegistrationSerializer(serializers.ModelSerializer):
|
||||||
)
|
)
|
||||||
first_name = serializers.CharField(required=True)
|
first_name = serializers.CharField(required=True)
|
||||||
last_name = serializers.CharField(required=True)
|
last_name = serializers.CharField(required=True)
|
||||||
|
birthday = serializers.DateField(format="%Y-%m-%d", required=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CustomUser
|
model = CustomUser
|
||||||
fields = ["email", "password", "first_name", "last_name"]
|
fields = ["email", "password", "first_name",
|
||||||
|
"last_name", "sex", "birthday"]
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
user_attrs = attrs.copy()
|
user_attrs = attrs.copy()
|
||||||
|
@ -48,8 +66,7 @@ class CustomUserRegistrationSerializer(serializers.ModelSerializer):
|
||||||
raise serializers.ValidationError({"password": errors})
|
raise serializers.ValidationError({"password": errors})
|
||||||
if self.Meta.model.objects.filter(username=attrs.get("email")).exists():
|
if self.Meta.model.objects.filter(username=attrs.get("email")).exists():
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
"A user with that email already exists."
|
"A user with that email already exists.")
|
||||||
)
|
|
||||||
return super().validate(attrs)
|
return super().validate(attrs)
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from config.settings import get_secret
|
from config.settings import get_secret
|
||||||
from django.db.models.signals import post_migrate
|
from django.db.models.signals import post_migrate
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
from django.utils.timezone import now, localdate
|
||||||
|
|
||||||
from .models import CustomUser
|
from .models import CustomUser
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,12 +10,15 @@ from .models import CustomUser
|
||||||
def create_admin_user(sender, **kwargs):
|
def create_admin_user(sender, **kwargs):
|
||||||
# Programatically creates the administrator account
|
# Programatically creates the administrator account
|
||||||
if sender.name == "accounts":
|
if sender.name == "accounts":
|
||||||
ADMIN_USER = CustomUser.objects.filter(email=get_secret("ADMIN_EMAIL")).first()
|
ADMIN_USER = CustomUser.objects.filter(
|
||||||
|
email=get_secret("ADMIN_EMAIL")).first()
|
||||||
if not ADMIN_USER:
|
if not ADMIN_USER:
|
||||||
ADMIN_USER = CustomUser.objects.create_superuser(
|
ADMIN_USER = CustomUser.objects.create_superuser(
|
||||||
username=get_secret("ADMIN_EMAIL"),
|
username=get_secret("ADMIN_EMAIL"),
|
||||||
email=get_secret("ADMIN_EMAIL"),
|
email=get_secret("ADMIN_EMAIL"),
|
||||||
password=get_secret("ADMIN_PASSWORD"),
|
password=get_secret("ADMIN_PASSWORD"),
|
||||||
|
sex="male",
|
||||||
|
birthday=localdate(now()),
|
||||||
)
|
)
|
||||||
|
|
||||||
print("Created administrator account:", ADMIN_USER.email)
|
print("Created administrator account:", ADMIN_USER.email)
|
||||||
|
|
|
@ -17,9 +17,11 @@ import time
|
||||||
|
|
||||||
class PDFHandler(FileSystemEventHandler):
|
class PDFHandler(FileSystemEventHandler):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
logging.basicConfig(level=logging.INFO,
|
logging.basicConfig(
|
||||||
format='%(asctime)s - %(message)s',
|
level=logging.INFO,
|
||||||
datefmt='%Y-%m-%d %H:%M:%S')
|
format="%(asctime)s - %(message)s",
|
||||||
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
|
)
|
||||||
|
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
self.logger.info("Starting Document Watcher...")
|
self.logger.info("Starting Document Watcher...")
|
||||||
|
@ -28,7 +30,7 @@ class PDFHandler(FileSystemEventHandler):
|
||||||
if event.is_directory:
|
if event.is_directory:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if event.src_path.endswith('.pdf'):
|
if event.src_path.endswith(".pdf"):
|
||||||
self.logger.info(f"New PDF file detected: {event.src_path}")
|
self.logger.info(f"New PDF file detected: {event.src_path}")
|
||||||
self.process_pdf(event.src_path)
|
self.process_pdf(event.src_path)
|
||||||
|
|
||||||
|
@ -57,13 +59,16 @@ class PDFHandler(FileSystemEventHandler):
|
||||||
# Perform OCR
|
# Perform OCR
|
||||||
text = pytesseract.image_to_string(img).strip()
|
text = pytesseract.image_to_string(img).strip()
|
||||||
|
|
||||||
lines = text.split('\n')
|
lines = text.split("\n")
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.strip():
|
if line.strip():
|
||||||
document_type = line.strip().lower()
|
document_type = line.strip().lower()
|
||||||
break
|
break
|
||||||
if not document_type or document_type not in Document.DOCUMENT_TYPE_CHOICES:
|
if (
|
||||||
|
not document_type
|
||||||
|
or document_type not in Document.DOCUMENT_TYPE_CHOICES
|
||||||
|
):
|
||||||
document_type = "other"
|
document_type = "other"
|
||||||
|
|
||||||
metadata += text
|
metadata += text
|
||||||
|
@ -72,17 +77,17 @@ class PDFHandler(FileSystemEventHandler):
|
||||||
DOCUMENT, created = Document.objects.get_or_create(
|
DOCUMENT, created = Document.objects.get_or_create(
|
||||||
name=filename,
|
name=filename,
|
||||||
defaults={
|
defaults={
|
||||||
'number_pages': num_pages,
|
"number_pages": num_pages,
|
||||||
'ocr_metadata': metadata,
|
"ocr_metadata": metadata,
|
||||||
'document_type': document_type
|
"document_type": document_type,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
DOCUMENT.file.save(
|
DOCUMENT.file.save(name=filename, content=File(open(file_path, "rb")))
|
||||||
name=filename, content=File(open(file_path, 'rb')))
|
self.logger.info(
|
||||||
self.logger.info(f"Document '{filename}' created successfully with type '{
|
f"Document '{filename}' created successfully with type '{document_type}'."
|
||||||
document_type}'.")
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.info(f"Document '{filename}' already exists.")
|
self.logger.info(f"Document '{filename}' already exists.")
|
||||||
|
@ -100,8 +105,7 @@ class PDFWatcher:
|
||||||
event_handler = PDFHandler()
|
event_handler = PDFHandler()
|
||||||
watch_directory = os.path.join(MEDIA_ROOT, "uploads")
|
watch_directory = os.path.join(MEDIA_ROOT, "uploads")
|
||||||
|
|
||||||
self.observer.schedule(
|
self.observer.schedule(event_handler, watch_directory, recursive=True)
|
||||||
event_handler, watch_directory, recursive=True)
|
|
||||||
self.observer.start()
|
self.observer.start()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -265,8 +265,9 @@ AUTH_USER_MODEL = "accounts.CustomUser"
|
||||||
|
|
||||||
DATA_UPLOAD_MAX_NUMBER_FIELDS = 20480
|
DATA_UPLOAD_MAX_NUMBER_FIELDS = 20480
|
||||||
|
|
||||||
GRAPH_MODELS = {"app_labels": [
|
GRAPH_MODELS = {
|
||||||
"accounts", "documents", "document_requests", "questionnaires"]}
|
"app_labels": ["accounts", "documents", "document_requests", "questionnaires"]
|
||||||
|
}
|
||||||
|
|
||||||
CORS_ORIGIN_ALLOW_ALL = True
|
CORS_ORIGIN_ALLOW_ALL = True
|
||||||
CORS_ALLOW_CREDENTIALS = True
|
CORS_ALLOW_CREDENTIALS = True
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-23 17:01
|
# Generated by Django 5.1.3 on 2024-12-03 16:27
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
|
@ -48,6 +48,14 @@ class Migration(migrations.Migration):
|
||||||
max_length=32,
|
max_length=32,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"type",
|
||||||
|
models.CharField(
|
||||||
|
choices=[("softcopy", "Softcopy"), ("hardcopy", "Hardcopy")],
|
||||||
|
default="softcopy",
|
||||||
|
max_length=16,
|
||||||
|
),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"requester",
|
"requester",
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-24 02:12
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("document_requests", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="documentrequest",
|
|
||||||
name="type",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[("softcopy", "Softcopy"), ("hardcopy", "Hardcopy")],
|
|
||||||
default="softcopy",
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -24,8 +24,7 @@ class DocumentRequestCreationSerializer(serializers.ModelSerializer):
|
||||||
documents = DocumentRequestUnitCreationSerializer(many=True, required=True)
|
documents = DocumentRequestUnitCreationSerializer(many=True, required=True)
|
||||||
college = serializers.CharField(max_length=64)
|
college = serializers.CharField(max_length=64)
|
||||||
purpose = serializers.CharField(max_length=512)
|
purpose = serializers.CharField(max_length=512)
|
||||||
type = serializers.ChoiceField(
|
type = serializers.ChoiceField(choices=DocumentRequest.TYPE_CHOICES, required=True)
|
||||||
choices=DocumentRequest.TYPE_CHOICES, required=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DocumentRequest
|
model = DocumentRequest
|
||||||
|
@ -75,7 +74,10 @@ class DocumentRequestUnitWithFileSerializer(serializers.ModelSerializer):
|
||||||
class DocumentRequestSerializer(serializers.ModelSerializer):
|
class DocumentRequestSerializer(serializers.ModelSerializer):
|
||||||
documents = serializers.SerializerMethodField()
|
documents = serializers.SerializerMethodField()
|
||||||
requester = serializers.SlugRelatedField(
|
requester = serializers.SlugRelatedField(
|
||||||
many=False, slug_field="email", queryset=CustomUser.objects.all(), required=False
|
many=False,
|
||||||
|
slug_field="email",
|
||||||
|
queryset=CustomUser.objects.all(),
|
||||||
|
required=False,
|
||||||
)
|
)
|
||||||
purpose = serializers.CharField(max_length=512)
|
purpose = serializers.CharField(max_length=512)
|
||||||
date_requested = serializers.DateTimeField(
|
date_requested = serializers.DateTimeField(
|
||||||
|
@ -116,7 +118,10 @@ class DocumentRequestSerializer(serializers.ModelSerializer):
|
||||||
class FullDocumentRequestSerializer(serializers.ModelSerializer):
|
class FullDocumentRequestSerializer(serializers.ModelSerializer):
|
||||||
documents = DocumentRequestUnitWithFileSerializer()
|
documents = DocumentRequestUnitWithFileSerializer()
|
||||||
requester = serializers.SlugRelatedField(
|
requester = serializers.SlugRelatedField(
|
||||||
many=False, slug_field="email", queryset=CustomUser.objects.all(), required=False
|
many=False,
|
||||||
|
slug_field="email",
|
||||||
|
queryset=CustomUser.objects.all(),
|
||||||
|
required=False,
|
||||||
)
|
)
|
||||||
purpose = serializers.CharField(max_length=512)
|
purpose = serializers.CharField(max_length=512)
|
||||||
date_requested = serializers.DateTimeField(
|
date_requested = serializers.DateTimeField(
|
||||||
|
|
|
@ -3,7 +3,7 @@ from .views import (
|
||||||
DocumentRequestCreateView,
|
DocumentRequestCreateView,
|
||||||
DocumentRequestListView,
|
DocumentRequestListView,
|
||||||
DocumentRequestUpdateView,
|
DocumentRequestUpdateView,
|
||||||
DocumentRequestFullListView
|
DocumentRequestFullListView,
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
|
@ -7,4 +7,5 @@ class DocumentsConfig(AppConfig):
|
||||||
|
|
||||||
def ready(self) -> None:
|
def ready(self) -> None:
|
||||||
import documents.signals
|
import documents.signals
|
||||||
|
|
||||||
return super().ready()
|
return super().ready()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-23 17:01
|
# Generated by Django 5.1.3 on 2024-12-03 16:27
|
||||||
|
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
import documents.models
|
import documents.models
|
||||||
|
@ -29,17 +29,19 @@ class Migration(migrations.Migration):
|
||||||
"document_type",
|
"document_type",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("pdf", "PDF"),
|
("memorandum", "Memorandum"),
|
||||||
("image", "Image"),
|
("hoa", "HOA"),
|
||||||
("video", "Video"),
|
(
|
||||||
("doc", "Word Document"),
|
"documented procedures manual",
|
||||||
("excel", "Excel Document"),
|
"Documented Procedures Manual",
|
||||||
("ppt", "Powerpoint Document"),
|
),
|
||||||
|
("other", "Other"),
|
||||||
],
|
],
|
||||||
max_length=32,
|
max_length=32,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
("number_pages", models.IntegerField()),
|
("number_pages", models.IntegerField()),
|
||||||
|
("ocr_metadata", models.TextField(blank=True, null=True)),
|
||||||
(
|
(
|
||||||
"file",
|
"file",
|
||||||
models.FileField(upload_to=documents.models.Document.upload_to),
|
models.FileField(upload_to=documents.models.Document.upload_to),
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-24 05:17
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("documents", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="document",
|
|
||||||
name="metadata",
|
|
||||||
field=models.TextField(null=True),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="document",
|
|
||||||
name="document_type",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[("memorandum", "Memorandum"), ("hoa", "HOA")], max_length=32
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-24 06:04
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("documents", "0002_document_metadata_alter_document_document_type"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name="document",
|
|
||||||
name="metadata",
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="document",
|
|
||||||
name="ocr_metadata",
|
|
||||||
field=models.TextField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,26 +0,0 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-26 15:12
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("documents", "0003_remove_document_metadata_document_ocr_metadata"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="document",
|
|
||||||
name="document_type",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("memorandum", "Memorandum"),
|
|
||||||
("hoa", "HOA"),
|
|
||||||
("documented procedures manual", "Documented Procedures Manual"),
|
|
||||||
("other", "Other"),
|
|
||||||
],
|
|
||||||
max_length=32,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
import uuid
|
import uuid
|
||||||
|
@ -12,7 +11,6 @@ class Document(models.Model):
|
||||||
("hoa", "HOA"),
|
("hoa", "HOA"),
|
||||||
("documented procedures manual", "Documented Procedures Manual"),
|
("documented procedures manual", "Documented Procedures Manual"),
|
||||||
("other", "Other"),
|
("other", "Other"),
|
||||||
|
|
||||||
)
|
)
|
||||||
document_type = models.CharField(
|
document_type = models.CharField(
|
||||||
max_length=32, choices=DOCUMENT_TYPE_CHOICES, null=False, blank=False
|
max_length=32, choices=DOCUMENT_TYPE_CHOICES, null=False, blank=False
|
||||||
|
|
|
@ -35,8 +35,14 @@ class DocumentSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Document
|
model = Document
|
||||||
fields = ["id", "name", "document_type",
|
fields = [
|
||||||
"number_pages", "ocr_metadata", "date_uploaded"]
|
"id",
|
||||||
|
"name",
|
||||||
|
"document_type",
|
||||||
|
"number_pages",
|
||||||
|
"ocr_metadata",
|
||||||
|
"date_uploaded",
|
||||||
|
]
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from documents.models import Document
|
from documents.models import Document
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-24 02:27
|
# Generated by Django 5.1.3 on 2024-12-03 16:27
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
|
@ -44,13 +44,6 @@ class Migration(migrations.Migration):
|
||||||
default=django.utils.timezone.now, editable=False
|
default=django.utils.timezone.now, editable=False
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
|
||||||
"sex",
|
|
||||||
models.CharField(
|
|
||||||
choices=[("male", "Male"), ("female", "Female")], max_length=16
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("age", models.IntegerField()),
|
|
||||||
("region_of_residence", models.CharField(max_length=64)),
|
("region_of_residence", models.CharField(max_length=64)),
|
||||||
("service_availed", models.CharField(max_length=64)),
|
("service_availed", models.CharField(max_length=64)),
|
||||||
(
|
(
|
||||||
|
@ -121,7 +114,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd0_answer",
|
"sqd0_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
@ -135,7 +128,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd1_answer",
|
"sqd1_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
@ -149,7 +142,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd2_answer",
|
"sqd2_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
@ -163,7 +156,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd3_answer",
|
"sqd3_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
@ -177,7 +170,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd4_answer",
|
"sqd4_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
@ -191,7 +184,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd5_answer",
|
"sqd5_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
@ -205,7 +198,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd6_answer",
|
"sqd6_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
@ -219,7 +212,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd7_answer",
|
"sqd7_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
@ -233,7 +226,7 @@ class Migration(migrations.Migration):
|
||||||
"sqd8_answer",
|
"sqd8_answer",
|
||||||
models.CharField(
|
models.CharField(
|
||||||
choices=[
|
choices=[
|
||||||
("1", "Strongly disagree"),
|
("1", "Strongly Disagree"),
|
||||||
("2", "Disagree"),
|
("2", "Disagree"),
|
||||||
("3", "Neither Agree nor Disagree"),
|
("3", "Neither Agree nor Disagree"),
|
||||||
("4", "Agree"),
|
("4", "Agree"),
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
# Generated by Django 5.1.3 on 2024-11-28 07:43
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("questionnaires", "0001_initial"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd0_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd1_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd2_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd3_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd4_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd5_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd6_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd7_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name="questionnaire",
|
|
||||||
name="sqd8_answer",
|
|
||||||
field=models.CharField(
|
|
||||||
choices=[
|
|
||||||
("1", "Strongly Disagree"),
|
|
||||||
("2", "Disagree"),
|
|
||||||
("3", "Neither Agree nor Disagree"),
|
|
||||||
("4", "Agree"),
|
|
||||||
("5", "Strongly Agree"),
|
|
||||||
("6", "N/A"),
|
|
||||||
],
|
|
||||||
max_length=16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -16,15 +16,8 @@ class Questionnaire(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
date_submitted = models.DateTimeField(default=now, editable=False)
|
date_submitted = models.DateTimeField(default=now, editable=False)
|
||||||
SEX_CHOICES = (
|
|
||||||
("male", "Male"),
|
region_of_residence = models.CharField(max_length=64, null=False, blank=False)
|
||||||
("female", "Female"),
|
|
||||||
)
|
|
||||||
sex = models.CharField(
|
|
||||||
max_length=16, choices=SEX_CHOICES, null=False, blank=False)
|
|
||||||
age = models.IntegerField(null=False, blank=False)
|
|
||||||
region_of_residence = models.CharField(
|
|
||||||
max_length=64, null=False, blank=False)
|
|
||||||
service_availed = models.CharField(max_length=64, null=False, blank=False)
|
service_availed = models.CharField(max_length=64, null=False, blank=False)
|
||||||
I_AM_I_CHOICES = (
|
I_AM_I_CHOICES = (
|
||||||
("faculty", "Faculty"),
|
("faculty", "Faculty"),
|
||||||
|
|
|
@ -5,16 +5,18 @@ from .models import Questionnaire
|
||||||
|
|
||||||
class QuestionnaireSerializer(serializers.ModelSerializer):
|
class QuestionnaireSerializer(serializers.ModelSerializer):
|
||||||
client = serializers.SlugRelatedField(
|
client = serializers.SlugRelatedField(
|
||||||
many=False, slug_field="email", queryset=CustomUser.objects.all(), required=False
|
many=False,
|
||||||
|
slug_field="email",
|
||||||
|
queryset=CustomUser.objects.all(),
|
||||||
|
required=False,
|
||||||
)
|
)
|
||||||
client_type = serializers.ChoiceField(
|
client_type = serializers.ChoiceField(choices=Questionnaire.CLIENT_TYPE_CHOICES)
|
||||||
choices=Questionnaire.CLIENT_TYPE_CHOICES)
|
|
||||||
|
|
||||||
date_submitted = serializers.DateTimeField(
|
date_submitted = serializers.DateTimeField(
|
||||||
format="%m-%d-%Y %I:%M %p", read_only=True
|
format="%m-%d-%Y %I:%M %p", read_only=True
|
||||||
)
|
)
|
||||||
sex = serializers.ChoiceField(choices=Questionnaire.SEX_CHOICES)
|
age = serializers.SerializerMethodField()
|
||||||
age = serializers.IntegerField(min_value=1)
|
sex = serializers.SerializerMethodField()
|
||||||
region_of_residence = serializers.CharField(max_length=64)
|
region_of_residence = serializers.CharField(max_length=64)
|
||||||
service_availed = serializers.CharField(max_length=64)
|
service_availed = serializers.CharField(max_length=64)
|
||||||
i_am_a = serializers.ChoiceField(choices=Questionnaire.I_AM_I_CHOICES)
|
i_am_a = serializers.ChoiceField(choices=Questionnaire.I_AM_I_CHOICES)
|
||||||
|
@ -32,6 +34,12 @@ class QuestionnaireSerializer(serializers.ModelSerializer):
|
||||||
sqd8_answer = serializers.ChoiceField(choices=Questionnaire.SQD_CHOICES)
|
sqd8_answer = serializers.ChoiceField(choices=Questionnaire.SQD_CHOICES)
|
||||||
extra_suggestions = serializers.CharField(max_length=512, required=False)
|
extra_suggestions = serializers.CharField(max_length=512, required=False)
|
||||||
|
|
||||||
|
def get_age(self, obj):
|
||||||
|
return obj.client.age
|
||||||
|
|
||||||
|
def get_sex(self, obj):
|
||||||
|
return obj.client.sex
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
representation = super().to_representation(instance)
|
representation = super().to_representation(instance)
|
||||||
representation["client"] = instance.client.email
|
representation["client"] = instance.client.email
|
||||||
|
|
|
@ -3,7 +3,7 @@ from .serializers import QuestionnaireSerializer
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from .models import Questionnaire
|
from .models import Questionnaire
|
||||||
from rest_framework.pagination import PageNumberPagination
|
from rest_framework.pagination import PageNumberPagination
|
||||||
from accounts.permissions import IsStaff
|
from accounts.permissions import IsStaff, IsPlanning
|
||||||
|
|
||||||
|
|
||||||
class QuestionnaireListAPIView(generics.ListAPIView):
|
class QuestionnaireListAPIView(generics.ListAPIView):
|
||||||
|
@ -15,7 +15,7 @@ class QuestionnaireListAPIView(generics.ListAPIView):
|
||||||
serializer_class = QuestionnaireSerializer
|
serializer_class = QuestionnaireSerializer
|
||||||
queryset = Questionnaire.objects.all()
|
queryset = Questionnaire.objects.all()
|
||||||
pagination_class = PageNumberPagination
|
pagination_class = PageNumberPagination
|
||||||
permission_classes = [IsAuthenticated, IsStaff]
|
permission_classes = [IsAuthenticated, IsPlanning]
|
||||||
|
|
||||||
|
|
||||||
class QuestionnaireSubmitView(generics.CreateAPIView):
|
class QuestionnaireSubmitView(generics.CreateAPIView):
|
||||||
|
|
Loading…
Reference in a new issue