From f9cfe26accddb99db13cd7a0d52c5e7ed41a5db8 Mon Sep 17 00:00:00 2001 From: Kanav Date: Thu, 5 Feb 2026 15:18:39 +0530 Subject: [PATCH 01/14] Implemented Live server support --- ClassLens_DB/ClassLens_DB/settings.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ClassLens_DB/ClassLens_DB/settings.py b/ClassLens_DB/ClassLens_DB/settings.py index 9d2d85c..ba85ead 100644 --- a/ClassLens_DB/ClassLens_DB/settings.py +++ b/ClassLens_DB/ClassLens_DB/settings.py @@ -31,7 +31,12 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = [ + '14.139.121.110', + 'localhost', + '127.0.0.1', + '172.25.13.31' +] # Application definition From df3cd8c14459fdf2f4b3564025e6330480ff432c Mon Sep 17 00:00:00 2001 From: Kanav Date: Wed, 25 Feb 2026 11:07:28 +0530 Subject: [PATCH 02/14] in Allowed Origin classlensfrontend.vercel.app Updated --- ClassLens_DB/DatabaseAdminApp/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ClassLens_DB/DatabaseAdminApp/settings.py b/ClassLens_DB/DatabaseAdminApp/settings.py index 64a635c..5181323 100644 --- a/ClassLens_DB/DatabaseAdminApp/settings.py +++ b/ClassLens_DB/DatabaseAdminApp/settings.py @@ -24,4 +24,5 @@ CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", "http://127.0.0.1:3000", + "https://classlensfrontend.vercel.app" ] \ No newline at end of file From b5dfb255b880b5b96fc592beb34dbeaaeb2ccddd Mon Sep 17 00:00:00 2001 From: Kanav Date: Thu, 7 May 2026 15:17:09 +0530 Subject: [PATCH 03/14] rabbitmq and start_server.bat --- ClassLens_DB/ClassLens_DB/celery.py | 6 +-- ClassLens_DB/ClassLens_DB/settings.py | 12 ++---- ClassLens_DB/ClassLens_DB/urls.py | 2 + ClassLens_DB/Home/tasks.py | 1 + ClassLens_DB/Home/urls.py | 1 + ClassLens_DB/Home/views.py | 43 ++++++++++++++++--- ClassLens_DB/requirements.txt | Bin 6196 -> 6126 bytes ClassLens_DB/start_server.bat | 5 +++ RABBITMQ_MIGRATION.md | 57 ++++++++++++++++++++++++++ README.md | 25 +++++++---- requirements.txt | Bin 5112 -> 5042 bytes 11 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 ClassLens_DB/start_server.bat create mode 100644 RABBITMQ_MIGRATION.md diff --git a/ClassLens_DB/ClassLens_DB/celery.py b/ClassLens_DB/ClassLens_DB/celery.py index 71231c6..b6bf0e6 100644 --- a/ClassLens_DB/ClassLens_DB/celery.py +++ b/ClassLens_DB/ClassLens_DB/celery.py @@ -7,7 +7,7 @@ env = environ.Env() environ.Env.read_env(os.path.join(BASE_DIR, '.env')) -redis_url = env('REDIS_URL') +rabbitmq_url = env('RABBITMQ_URL') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ClassLens_DB.settings') @@ -15,7 +15,7 @@ app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks() app.conf.update( - broker_url=redis_url, - result_backend=redis_url, + broker_url=rabbitmq_url, + result_backend='rpc://', broker_connection_retry_on_startup=True, ) \ No newline at end of file diff --git a/ClassLens_DB/ClassLens_DB/settings.py b/ClassLens_DB/ClassLens_DB/settings.py index 9549c20..6d4e58e 100644 --- a/ClassLens_DB/ClassLens_DB/settings.py +++ b/ClassLens_DB/ClassLens_DB/settings.py @@ -52,7 +52,6 @@ "DatabaseAdminApp", "rest_framework", 'corsheaders', - 'django_redis' ] MIDDLEWARE = [ @@ -105,11 +104,8 @@ CACHES = { "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": env('REDIS_URL'), - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", - } + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + "LOCATION": "classlens-local-cache", } } @@ -164,8 +160,8 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -CELERY_BROKER_URL = env('REDIS_URL') -CELERY_RESULT_BACKEND = env('REDIS_URL') +CELERY_BROKER_URL = env('RABBITMQ_URL') +CELERY_RESULT_BACKEND = 'rpc://' CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json' diff --git a/ClassLens_DB/ClassLens_DB/urls.py b/ClassLens_DB/ClassLens_DB/urls.py index d134947..12d786d 100644 --- a/ClassLens_DB/ClassLens_DB/urls.py +++ b/ClassLens_DB/ClassLens_DB/urls.py @@ -21,9 +21,11 @@ from django.conf.urls.static import static from DatabaseAdminApp import urls as db_admin_urls from django.urls import include +from Home.views import health urlpatterns = [ path("admin/", admin.site.urls), + path("health/",health,name="health_check"), path("api/", include(urls)), path("api/", include(db_admin_urls)), ] diff --git a/ClassLens_DB/Home/tasks.py b/ClassLens_DB/Home/tasks.py index c31c9c0..485543f 100644 --- a/ClassLens_DB/Home/tasks.py +++ b/ClassLens_DB/Home/tasks.py @@ -226,6 +226,7 @@ def evaluate_attendance(total_sessions,class_session_id:int,scheme, host): session.subject.name, session.class_datetime ) + print(f"images url {image_urls[0]}") return { "num_faces": total_faces, diff --git a/ClassLens_DB/Home/urls.py b/ClassLens_DB/Home/urls.py index 16f4a2f..720e04b 100644 --- a/ClassLens_DB/Home/urls.py +++ b/ClassLens_DB/Home/urls.py @@ -27,6 +27,7 @@ path('student/dashboard/', get_student_dashboard, name='get_student_dashboard'), path('student/notification-token/', update_notification_token, name='update_notification_token'), path('student/notification-token/remove/', remove_notification_token, name='remove_notification_token'), + ] if settings.DEBUG: diff --git a/ClassLens_DB/Home/views.py b/ClassLens_DB/Home/views.py index 379caff..79e87e2 100644 --- a/ClassLens_DB/Home/views.py +++ b/ClassLens_DB/Home/views.py @@ -390,8 +390,12 @@ def set_password(request, *args, **kwargs): if student : student.password_hash = make_password(password) try : - student.face_embedding=registerNewStudent(request.FILES.get("photo")) - except ValueError as ve : + embedding=registerNewStudent(request.FILES.get("photo")) + if not isinstance(embedding,Exception): + student.face_embedding = embedding + else : + raise Exception("Face embedding error: " + str(embedding)) + except Exception as e : return Response({"error": "Face Not Detected, Upload A New Image"}, status=status.HTTP_400_BAD_REQUEST) student.save() print("Student password set successfully") @@ -480,8 +484,28 @@ def mark_attendance(request, *args, **kwargs): departmentName = request.data.get("departmentName") year = request.data.get("year") - if not all([photos, subject_id, teacher_id, departmentName, year]): - return Response({"error": "Missing required fields (photo, subject_id, teacher_id, department_id, year)."}, status=400) + # Debug log to see exactly what is received + print("=" * 60) + print("MARK ATTENDANCE REQUEST RECEIVED") + print(f" photos : {photos}") + print(f" subject_id : {subject_id!r}") + print(f" teacher_id : {teacher_id!r}") + print(f" department : {departmentName!r}") + print(f" year : {year!r}") + print("=" * 60) + + missing = [] + if not photos: missing.append("photo") + if not subject_id: missing.append("subjectID") + if not teacher_id: missing.append("teacherID") + if not departmentName: missing.append("departmentName") + if not year: missing.append("year") + + if missing: + return Response({"error": f"Missing required fields: {', '.join(missing)}"}, status=400) + + if int(teacher_id) == 0: + return Response({"error": "Invalid teacher ID (0). Please log in again."}, status=400) try: class_session = ClassSession.objects.create( @@ -502,7 +526,7 @@ def mark_attendance(request, *args, **kwargs): photo=photo ) - task = evaluate_attendance.delay(total_sessions,class_session.id,request.scheme, request.get_host()) + task = evaluate_attendance.delay(total_sessions,class_session.id,request.scheme,"14.139.121.110:11020") return Response({ "message": "Attendance processing started. You will be notified once it's done.", @@ -808,4 +832,11 @@ def remove_notification_token(request, *args, **kwargs): return Response( {"detail": "Something went wrong"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, - ) \ No newline at end of file + ) + +@api_view(["GET"]) +def health(request,*args,**kwargs): + return Response( + {"message":"ok"}, + status=200 + ) \ No newline at end of file diff --git a/ClassLens_DB/requirements.txt b/ClassLens_DB/requirements.txt index b49df48c272489670d9f7098c79d15586d5b72fa..4ea7e0371eb36d0906bfe9dd7f37dacfd169d75d 100644 GIT binary patch delta 17 YcmdmD@J@e25bNd|RtMhAH-utX0YT~phyVZp delta 59 ycmaE-zr|of5UZ#zLlHwNLkdGCLotIb5SlUQF&J#NWew#OMin#xOLPjQvH}2^WDG(8 diff --git a/ClassLens_DB/start_server.bat b/ClassLens_DB/start_server.bat new file mode 100644 index 0000000..423331a --- /dev/null +++ b/ClassLens_DB/start_server.bat @@ -0,0 +1,5 @@ +@echo off +cd C:\Users\Admin\Desktop\ClassLens\ClassLens_DB +call C:\Users\Admin\Desktop\ClassLens\venv\Scripts\activate.bat +waitress-serve --host=127.0.0.1 --port=8000 ClassLens_DB.wsgi:application +pause \ No newline at end of file diff --git a/RABBITMQ_MIGRATION.md b/RABBITMQ_MIGRATION.md new file mode 100644 index 0000000..532a80c --- /dev/null +++ b/RABBITMQ_MIGRATION.md @@ -0,0 +1,57 @@ +# RabbitMQ Migration Summary + +## What was changed + +The backend has been migrated from Redis-based Celery configuration to RabbitMQ. + +### 1) Django/Celery settings updated +- `ClassLens_DB/ClassLens_DB/settings.py` + - Replaced `CELERY_BROKER_URL` source from `REDIS_URL` to `RABBITMQ_URL`. + - Replaced `CELERY_RESULT_BACKEND` from Redis URL to `rpc://` (RabbitMQ-compatible Celery result backend). + - Removed `django_redis` from `INSTALLED_APPS`. + - Replaced Redis cache backend with Django local memory cache: + - `django.core.cache.backends.locmem.LocMemCache` + +### 2) Celery app config updated +- `ClassLens_DB/ClassLens_DB/celery.py` + - Replaced Redis URL variable with RabbitMQ URL variable. + - Updated `broker_url` to use `RABBITMQ_URL`. + - Updated `result_backend` to `rpc://`. + +### 3) Environment configuration updated +- `ClassLens_DB/.env` + - Removed Redis URL entry. + - Added RabbitMQ broker URL: + +```env +RABBITMQ_URL=amqp://guest:guest@localhost:5672// +``` + +### 4) Dependencies cleaned up +- `requirements.txt` +- `ClassLens_DB/requirements.txt` + - Removed: + - `django-redis` + - `redis` + +### 5) Documentation updated +- `README.md` + - Replaced Redis references with RabbitMQ references. + - Updated environment variable docs to `RABBITMQ_URL`. + - Replaced Redis setup section with RabbitMQ setup instructions. + - Added RabbitMQ management UI credentials: + - URL: `http://localhost:15672/` + - Username: `guest` + - Password: `guest` + +## RabbitMQ values in use + +- Broker URL: `amqp://guest:guest@localhost:5672//` +- Management UI: `http://localhost:15672/` +- Username: `guest` +- Password: `guest` + +## Notes + +- Celery with RabbitMQ does not use Redis as result backend; `rpc://` is now used. +- If you run Celery workers, ensure RabbitMQ server is running before starting workers. diff --git a/README.md b/README.md index 32a62d8..03c2cd1 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ ClassLens/ - **Backend Framework**: Django, Django REST Framework - **Task Queue**: Celery -- **Message Broker / Cache**: Redis +- **Message Broker**: RabbitMQ - **Database**: PostgreSQL (with `pgvector` extension) - **Face Pipeline**: DeepFace, RetinaFace, GFPGAN - **Auth & OTP**: JWT authentication + Email OTP verification @@ -63,7 +63,7 @@ ClassLens/ - Python 3.10+ - PostgreSQL 13+ (local or managed, with pgvector installed) -- Redis server +- RabbitMQ server - Virtual environment (recommended) --- @@ -104,8 +104,8 @@ DB_PASSWORD=your_password DB_HOST=your_host DB_PORT=5432 -# Redis -REDIS_URL=redis://localhost:6379 +# RabbitMQ +RABBITMQ_URL=amqp://guest:guest@localhost:5672// # Email Configuration (SMTP) EMAIL_HOST=smtp.gmail.com # Use smtp-mail.outlook.com for Outlook @@ -156,15 +156,24 @@ You can now hit the API from: --- -## ⚡ Celery & Redis Setup +## ⚡ Celery & RabbitMQ Setup -Start Redis locally or via Docker: +Start RabbitMQ locally or via Docker: ```bash -redis-server # local OR -docker run -d --name classlens-redis -p 6379:6379 redis +# local server (default broker: 5672, management UI: 15672) +rabbitmq-server + +# OR Docker +docker run -d --name classlens-rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management ``` +RabbitMQ management UI: + +- URL: http://localhost:15672/ +- Username: guest +- Password: guest + Start Celery worker: ```bash diff --git a/requirements.txt b/requirements.txt index 99241d857866042a5dcc4879a2084f6dfd4b61ed..f1b802b82111794acb0837532ddebe9818565b23 100644 GIT binary patch delta 17 ZcmeyNzDa#U3CrerEcZA!&)`d71pr6a2O9tY delta 59 ycmdm_{zH9335%#MLlHwNLkdGCLotIb5SlUQF&J!)XZg%2j4EgXmhj}uWCZ}Q-wf3N From 7d72095fdd960df6e25f9d43428f4527539220bf Mon Sep 17 00:00:00 2001 From: ClassLens Date: Thu, 7 May 2026 15:26:47 +0530 Subject: [PATCH 04/14] Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 03c2cd1..203d268 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,7 @@ rabbitmq-server docker run -d --name classlens-rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management ``` +//// RabbitMQ management UI: - URL: http://localhost:15672/ From 80ab63dc2e8858cc0bbc4d627ff3efd81e734fed Mon Sep 17 00:00:00 2001 From: Mann Shah Date: Tue, 12 May 2026 14:14:58 +0530 Subject: [PATCH 05/14] Design change in DB and Backend --- ClassLens_DB/ClassLens_DB/urls.py | 18 + ClassLens_DB/DatabaseAdminApp/models.py | 109 +- ClassLens_DB/DatabaseAdminApp/serializers.py | 46 +- ClassLens_DB/DatabaseAdminApp/urls.py | 22 + ClassLens_DB/DatabaseAdminApp/views.py | 304 +++- ClassLens_DB/Home/admin.py | 3 +- ClassLens_DB/Home/models.py | 41 +- ClassLens_DB/Home/tasks.py | 142 +- ClassLens_DB/Home/views.py | 40 +- ClassLens_DB/scripts/fix_home_migrations.py | 22 + DATABASE_SCHEMA.md | 683 +++++++++ DBMSUIS_V7.sql | Bin 0 -> 129752 bytes DBMSUIS_V7_utf8.sql | 1335 ++++++++++++++++++ FRONTEND_CHANGES.md | 328 +++++ FRONTEND_CONTEXT.md | 452 ++++++ README.md | 10 +- data-1778222711514.csv | 103 ++ db-chat.txt | 132 ++ requirements.txt | Bin 5042 -> 5118 bytes test_sync_endpoint.py | 49 + 20 files changed, 3780 insertions(+), 59 deletions(-) create mode 100644 ClassLens_DB/scripts/fix_home_migrations.py create mode 100644 DATABASE_SCHEMA.md create mode 100644 DBMSUIS_V7.sql create mode 100644 DBMSUIS_V7_utf8.sql create mode 100644 FRONTEND_CHANGES.md create mode 100644 FRONTEND_CONTEXT.md create mode 100644 data-1778222711514.csv create mode 100644 db-chat.txt create mode 100644 test_sync_endpoint.py diff --git a/ClassLens_DB/ClassLens_DB/urls.py b/ClassLens_DB/ClassLens_DB/urls.py index 12d786d..92e9395 100644 --- a/ClassLens_DB/ClassLens_DB/urls.py +++ b/ClassLens_DB/ClassLens_DB/urls.py @@ -22,10 +22,28 @@ from DatabaseAdminApp import urls as db_admin_urls from django.urls import include from Home.views import health +from django.views.generic import RedirectView +from django.http import JsonResponse + + +def api_root(request): + return JsonResponse( + { + "message": "ClassLens API", + "routes": { + "health": "/api/health/", + "departments": "/api/getDepartments/", + "admin": "/api/admin/", + }, + } + ) urlpatterns = [ path("admin/", admin.site.urls), path("health/",health,name="health_check"), + path("api", RedirectView.as_view(url="/api/", permanent=False)), + path("api/", api_root, name="api_root"), + path("api/health/", health, name="api_health"), path("api/", include(urls)), path("api/", include(db_admin_urls)), ] diff --git a/ClassLens_DB/DatabaseAdminApp/models.py b/ClassLens_DB/DatabaseAdminApp/models.py index 71a8362..3ea46b7 100644 --- a/ClassLens_DB/DatabaseAdminApp/models.py +++ b/ClassLens_DB/DatabaseAdminApp/models.py @@ -1,3 +1,110 @@ from django.db import models -# Create your models here. + +class APIEnrollment(models.Model): + """Simplified mirror of enrollment data from MSUIS API - attendance-only focus.""" + prn = models.BigIntegerField(db_index=True) + subject_code = models.CharField(max_length=100) + department_name = models.CharField(max_length=200) + program_name = models.CharField(max_length=200) + year = models.IntegerField() + semester = models.IntegerField() + division = models.CharField(max_length=20) # A, B, C, etc. + raw_payload = models.JSONField(default=dict) + synced_at = models.DateTimeField(auto_now=True) + + class Meta: + unique_together = ('prn', 'subject_code', 'division', 'semester') + + def __str__(self): + return f"PRN {self.prn} - {self.subject_code} Div {self.division}" + + +class APIFaculty(models.Model): + """Mirror of faculty data received from MSUIS API.""" + msuis_id = models.BigIntegerField(primary_key=True) + name = models.TextField(null=True, blank=True) + is_active = models.BooleanField(null=True, blank=True) + is_deleted = models.BooleanField(null=True, blank=True) + raw_payload = models.JSONField(default=dict) + synced_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return f"{self.msuis_id} - {self.name or 'Faculty'}" + + +class APIStudent(models.Model): + """Mirror of MstStudent API payloads.""" + prn = models.BigIntegerField(primary_key=True) + first_name = models.CharField(max_length=100, null=True, blank=True) + middle_name = models.CharField(max_length=100, null=True, blank=True) + last_name = models.CharField(max_length=100, null=True, blank=True) + email_id = models.CharField(max_length=150, null=True, blank=True) + mobile_no = models.CharField(max_length=50, null=True, blank=True) + faculty_id = models.BigIntegerField(null=True, blank=True) + programme_name = models.CharField(max_length=200, null=True, blank=True) + admission_year = models.IntegerField(null=True, blank=True) + passing_year = models.IntegerField(null=True, blank=True) + raw_payload = models.JSONField(default=dict) + synced_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return str(self.prn) + + +class APIPaper(models.Model): + """Mirror of MstPaper API payloads.""" + msuis_id = models.BigIntegerField(primary_key=True) + subject_id = models.BigIntegerField(null=True, blank=True) + paper_name = models.CharField(max_length=1000) + paper_code = models.CharField(max_length=100) + is_credit = models.BooleanField(null=True, blank=True) + max_marks = models.IntegerField(null=True, blank=True) + min_marks = models.IntegerField(null=True, blank=True) + credits = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) + is_active = models.BooleanField(null=True, blank=True) + is_deleted = models.BooleanField(null=True, blank=True) + raw_payload = models.JSONField(default=dict) + synced_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return f"{self.paper_code} - {self.paper_name}" + + +class APIStudentAcademicInformation(models.Model): + """Mirror of IncStudentAcademicInformation API payloads.""" + msuis_id = models.BigIntegerField(primary_key=True) + prn = models.BigIntegerField(db_index=True) + student_admission_id = models.BigIntegerField(null=True, blank=True) + programme_instance_part_term_id = models.BigIntegerField(null=True, blank=True) + programme_id = models.BigIntegerField(null=True, blank=True) + specialisation_id = models.BigIntegerField(null=True, blank=True) + academic_year_id = models.BigIntegerField(null=True, blank=True) + institute_id = models.BigIntegerField(null=True, blank=True) + faculty_id = models.BigIntegerField(null=True, blank=True) + part_term_status = models.CharField(max_length=100, null=True, blank=True) + raw_payload = models.JSONField(default=dict) + synced_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return f"{self.msuis_id} - {self.prn}" + + +class APIStudentPartTermPaperMap(models.Model): + """Mirror of IncStudentPartTermPaperMap API payloads. (Legacy - use APIEnrollment instead)""" + msuis_id = models.BigIntegerField(primary_key=True) + prn = models.BigIntegerField(null=True, blank=True, db_index=True) + student_academic_information_id = models.BigIntegerField(null=True, blank=True) + programme_instance_part_term_id = models.BigIntegerField(null=True, blank=True) + paper_id = models.BigIntegerField(null=True, blank=True) + mst_paper_id = models.BigIntegerField(null=True, blank=True) + obtained_marks = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) + obtained_grade = models.CharField(max_length=10, null=True, blank=True) + paper_status = models.CharField(max_length=100, null=True, blank=True) + part_term_status = models.CharField(max_length=100, null=True, blank=True) + division = models.CharField(max_length=20, null=True, blank=True) + raw_payload = models.JSONField(default=dict) + synced_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return f"{self.msuis_id} - {self.prn}" diff --git a/ClassLens_DB/DatabaseAdminApp/serializers.py b/ClassLens_DB/DatabaseAdminApp/serializers.py index 7c2eb01..a6d82d5 100644 --- a/ClassLens_DB/DatabaseAdminApp/serializers.py +++ b/ClassLens_DB/DatabaseAdminApp/serializers.py @@ -5,6 +5,13 @@ Department, Teacher, Student, Subject, SubjectFromDept, StudentEnrollment, TeacherSubject, AdminUser ) +from .models import ( + APIFaculty, + APIStudent, + APIPaper, + APIStudentAcademicInformation, + APIStudentPartTermPaperMap, +) class DepartmentSerializer(serializers.ModelSerializer): class Meta: @@ -93,4 +100,41 @@ def create(self, validated_data): ) user.set_password(validated_data['password']) user.save() - return user \ No newline at end of file + return user + + +class APIFacultySerializer(serializers.ModelSerializer): + class Meta: + model = APIFaculty + fields = "__all__" + + +class APIStudentSerializer(serializers.ModelSerializer): + class Meta: + model = APIStudent + fields = "__all__" + + +class APIPaperSerializer(serializers.ModelSerializer): + class Meta: + model = APIPaper + fields = "__all__" + + +class APIStudentAcademicInformationSerializer(serializers.ModelSerializer): + class Meta: + model = APIStudentAcademicInformation + fields = "__all__" + + +class APIStudentPartTermPaperMapSerializer(serializers.ModelSerializer): + class Meta: + model = APIStudentPartTermPaperMap + fields = "__all__" + + +class DivisionSerializer(serializers.ModelSerializer): + class Meta: + from Home.models import Division + model = Division + fields = ['id', 'department', 'program_name', 'year', 'semester', 'name'] \ No newline at end of file diff --git a/ClassLens_DB/DatabaseAdminApp/urls.py b/ClassLens_DB/DatabaseAdminApp/urls.py index 8c00c77..c29b166 100644 --- a/ClassLens_DB/DatabaseAdminApp/urls.py +++ b/ClassLens_DB/DatabaseAdminApp/urls.py @@ -14,6 +14,13 @@ admin_login, get_dashboard_stats, AdminUserViewSet, + APIFacultyViewSet, + APIStudentViewSet, + APIPaperViewSet, + APIStudentAcademicInformationViewSet, + APIStudentPartTermPaperMapViewSet, + sync_msuis_payload, + DivisionViewSet, ) router = DefaultRouter() @@ -28,11 +35,26 @@ r"student-enrollments", StudentEnrollmentViewSet, basename="student-enrollment" ) router.register(r"admin-users", AdminUserViewSet, basename="admin-user") +router.register(r"api-faculties", APIFacultyViewSet, basename="api-faculty") +router.register(r"api-students", APIStudentViewSet, basename="api-student") +router.register(r"api-papers", APIPaperViewSet, basename="api-paper") +router.register( + r"api-student-academic-info", + APIStudentAcademicInformationViewSet, + basename="api-student-academic-info", +) +router.register( + r"api-student-part-term-paper-map", + APIStudentPartTermPaperMapViewSet, + basename="api-student-part-term-paper-map", +) +router.register(r"divisions", DivisionViewSet, basename="division") urlpatterns = [ # Authentication path("admin/login/", admin_login, name="admin-login"), path("admin/token/refresh/", TokenRefreshView.as_view(), name="token-refresh"), + path("admin/sync/msuis/", sync_msuis_payload, name="sync-msuis-payload"), # CRUD APIs path("admin/stats/", get_dashboard_stats, name="admin-stats"), path("admin/", include(router.urls)), diff --git a/ClassLens_DB/DatabaseAdminApp/views.py b/ClassLens_DB/DatabaseAdminApp/views.py index 3f214f1..60146f5 100644 --- a/ClassLens_DB/DatabaseAdminApp/views.py +++ b/ClassLens_DB/DatabaseAdminApp/views.py @@ -5,18 +5,32 @@ from rest_framework_simplejwt.tokens import RefreshToken from django.contrib.auth.hashers import make_password from django.http import HttpResponse -import pandas as pd +try: + import pandas as pd +except Exception: + pd = None import io from .pagination import StudentPagination from Home.models import ( Department, Teacher, Student, Subject, SubjectFromDept, - StudentEnrollment, TeacherSubject, AdminUser, StudentAttendancePercentage + StudentEnrollment, TeacherSubject, AdminUser, StudentAttendancePercentage, Division +) +from .models import ( + APIFaculty, + APIStudent, + APIPaper, + APIStudentAcademicInformation, + APIStudentPartTermPaperMap, ) from .serializers import ( DepartmentSerializer, TeacherSerializer, StudentSerializer, SubjectSerializer, SubjectFromDeptSerializer, StudentEnrollmentSerializer, - TeacherSubjectSerializer, AdminUserSerializer + TeacherSubjectSerializer, AdminUserSerializer, + APIFacultySerializer, APIStudentSerializer, APIPaperSerializer, + APIStudentAcademicInformationSerializer, APIStudentPartTermPaperMapSerializer, + DivisionSerializer, ) +from django.db import transaction from rest_framework.permissions import BasePermission @@ -466,4 +480,288 @@ def bulk_upload(self, request): except Exception as e: return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class APIFacultyViewSet(viewsets.ModelViewSet): + queryset = APIFaculty.objects.all().order_by("msuis_id") + serializer_class = APIFacultySerializer + permission_classes = [IsAuthenticated] + + +class APIStudentViewSet(viewsets.ModelViewSet): + queryset = APIStudent.objects.all().order_by("prn") + serializer_class = APIStudentSerializer + permission_classes = [IsAuthenticated] + + +class APIPaperViewSet(viewsets.ModelViewSet): + queryset = APIPaper.objects.all().order_by("msuis_id") + serializer_class = APIPaperSerializer + permission_classes = [IsAuthenticated] + + +class APIStudentAcademicInformationViewSet(viewsets.ModelViewSet): + queryset = APIStudentAcademicInformation.objects.all().order_by("msuis_id") + serializer_class = APIStudentAcademicInformationSerializer + permission_classes = [IsAuthenticated] + + +class APIStudentPartTermPaperMapViewSet(viewsets.ModelViewSet): + queryset = APIStudentPartTermPaperMap.objects.all().order_by("msuis_id") + serializer_class = APIStudentPartTermPaperMapSerializer + permission_classes = [IsAuthenticated] + + +class DivisionViewSet(viewsets.ModelViewSet): + queryset = Division.objects.all().select_related('department') + serializer_class = DivisionSerializer + permission_classes = [IsAuthenticated] + + +def _full_name(student_record): + name_parts = [ + student_record.get("FirstName"), + student_record.get("MiddleName"), + student_record.get("LastName"), + ] + merged = " ".join([part.strip() for part in name_parts if isinstance(part, str) and part.strip()]) + return merged or student_record.get("NameAsPerMarksheet") or "Unknown" + + +def _to_bool(value): + if isinstance(value, bool): + return value + if isinstance(value, (int, float)): + return bool(value) + if isinstance(value, str): + return value.strip().lower() in {"1", "true", "yes", "y"} + return None + + +@api_view(["POST"]) +@permission_classes([IsAuthenticated]) +def sync_msuis_payload(request): + """ + Single entrypoint for API-sourced data ingestion through admin app. + This keeps external-source writes centralized for future DB merge workflows. + """ + payload = request.data or {} + apply_to_core = bool(payload.get("apply_to_core", True)) + + faculties = payload.get("faculties", []) + students = payload.get("students", []) + papers = payload.get("papers", []) + academic_records = payload.get("student_academic_information", []) + part_term_maps = payload.get("student_part_term_paper_maps", []) + + counters = { + "faculties_synced": 0, + "students_synced": 0, + "papers_synced": 0, + "academic_records_synced": 0, + "part_term_maps_synced": 0, + "core_departments_upserted": 0, + "core_students_upserted": 0, + "core_subjects_upserted": 0, + "core_enrollments_upserted": 0, + "core_divisions_upserted": 0, + } + + # Use the latest academic snapshot to derive student year/faculty defaults. + latest_academic_by_prn = {} + + with transaction.atomic(): + for row in faculties: + msuis_id = row.get("Id") or row.get("id") + if msuis_id is None: + continue + + name = row.get("FacultyName") or row.get("Name") or row.get("name") + APIFaculty.objects.update_or_create( + msuis_id=msuis_id, + defaults={ + "name": name, + "is_active": _to_bool(row.get("IsActive")), + "is_deleted": _to_bool(row.get("IsDeleted")), + "raw_payload": row, + }, + ) + counters["faculties_synced"] += 1 + + if apply_to_core and name: + Department.objects.update_or_create( + id=msuis_id, + defaults={"name": name}, + ) + counters["core_departments_upserted"] += 1 + + for row in academic_records: + msuis_id = row.get("Id") or row.get("id") + if msuis_id is None: + continue + + prn = row.get("PRN") or row.get("Prn") or row.get("prn") + APIStudentAcademicInformation.objects.update_or_create( + msuis_id=msuis_id, + defaults={ + "prn": prn, + "student_admission_id": row.get("StudentAdmissionId"), + "programme_instance_part_term_id": row.get("ProgrammeInstancePartTermId"), + "programme_id": row.get("ProgrammeId"), + "specialisation_id": row.get("SpecialisationId"), + "academic_year_id": row.get("AcademicYearId"), + "institute_id": row.get("InstituteId"), + "faculty_id": row.get("FacultyId"), + "part_term_status": row.get("PartTermStatus"), + "raw_payload": row, + }, + ) + counters["academic_records_synced"] += 1 + + if prn is not None: + latest_academic_by_prn[prn] = row + + for row in students: + prn = row.get("PRN") or row.get("Prn") or row.get("prn") + if prn is None: + continue + + APIStudent.objects.update_or_create( + prn=prn, + defaults={ + "first_name": row.get("FirstName"), + "middle_name": row.get("MiddleName"), + "last_name": row.get("LastName"), + "email_id": row.get("EmailId"), + "mobile_no": row.get("MobileNo"), + "faculty_id": row.get("FacultyId"), + "programme_name": row.get("ProgrammeName"), + "admission_year": row.get("AdmissionYear"), + "passing_year": row.get("PassingYear"), + "raw_payload": row, + }, + ) + counters["students_synced"] += 1 + + if apply_to_core: + academic = latest_academic_by_prn.get(prn, {}) + faculty_id = row.get("FacultyId") or academic.get("FacultyId") + if not faculty_id: + continue + + dept = Department.objects.filter(id=faculty_id).first() + if dept is None: + dept = Department.objects.create( + id=faculty_id, + name=f"Faculty-{faculty_id}", + ) + counters["core_departments_upserted"] += 1 + + # When exact year is unavailable from API, keep a stable fallback. + year = row.get("Year") or 1 + + Student.objects.update_or_create( + prn=prn, + defaults={ + "name": _full_name(row), + "email": row.get("EmailId") or f"{prn}@classlens.local", + "year": year, + "department": dept, + }, + ) + counters["core_students_upserted"] += 1 + + for row in papers: + msuis_id = row.get("Id") or row.get("id") + if msuis_id is None: + continue + + paper_code = row.get("PaperCode") or row.get("Code") or f"PAPER-{msuis_id}" + paper_name = row.get("PaperName") or row.get("Name") or paper_code + + APIPaper.objects.update_or_create( + msuis_id=msuis_id, + defaults={ + "subject_id": row.get("SubjectId"), + "paper_name": paper_name, + "paper_code": paper_code, + "is_credit": _to_bool(row.get("IsCredit")), + "max_marks": row.get("MaxMarks"), + "min_marks": row.get("MinMarks"), + "credits": row.get("Credits"), + "is_active": _to_bool(row.get("IsActive")), + "is_deleted": _to_bool(row.get("IsDeleted")), + "raw_payload": row, + }, + ) + counters["papers_synced"] += 1 + + if apply_to_core: + Subject.objects.update_or_create( + id=msuis_id, + defaults={"code": paper_code, "name": paper_name}, + ) + counters["core_subjects_upserted"] += 1 + + for row in part_term_maps: + msuis_id = row.get("Id") or row.get("id") + if msuis_id is None: + continue + + prn = row.get("PRN") or row.get("Prn") + paper_id = row.get("MstPaperId") or row.get("PaperId") + + APIStudentPartTermPaperMap.objects.update_or_create( + msuis_id=msuis_id, + defaults={ + "prn": prn, + "student_academic_information_id": row.get("StudentAcademicInformationId"), + "programme_instance_part_term_id": row.get("ProgrammeInstancePartTermId"), + "paper_id": row.get("PaperId"), + "mst_paper_id": row.get("MstPaperId"), + "obtained_marks": row.get("ObtainedMarks"), + "obtained_grade": row.get("ObtainedGrade"), + "paper_status": row.get("PaperStatus"), + "part_term_status": row.get("PartTermStatus"), + "division": row.get("Division"), + "raw_payload": row, + }, + ) + counters["part_term_maps_synced"] += 1 + + if apply_to_core and prn and paper_id: + student = Student.objects.filter(prn=prn).first() + subject = Subject.objects.filter(id=paper_id).first() + if student and subject: + StudentEnrollment.objects.update_or_create( + student_prn=student.prn, + subject=subject, + ) + StudentAttendancePercentage.objects.get_or_create( + student=student, + subject=subject, + defaults={"present_count": 0, "attendancePercentage": 0.0}, + ) + counters["core_enrollments_upserted"] += 1 + + division_name = row.get("Division") + semester = row.get("Semester") + if division_name and semester: + division_obj, _ = Division.objects.get_or_create( + department=student.department, + program_name=(row.get("ProgrammeName") or "Program"), + year=student.year, + semester=int(semester), + name=str(division_name), + ) + counters["core_divisions_upserted"] += 1 + + return Response( + { + "message": "MSUIS payload synced via admin app", + "apply_to_core": apply_to_core, + "counts": counters, + }, + status=status.HTTP_200_OK, + ) diff --git a/ClassLens_DB/Home/admin.py b/ClassLens_DB/Home/admin.py index 6a81616..c5d0c3a 100644 --- a/ClassLens_DB/Home/admin.py +++ b/ClassLens_DB/Home/admin.py @@ -2,7 +2,7 @@ # Register your models here. -from .models import Student, Subject, Teacher, Department, ClassSession, SubjectFromDept, TeacherSubject, StudentEnrollment +from .models import Student, Subject, Teacher, Department, ClassSession, SubjectFromDept, TeacherSubject, StudentEnrollment, Division admin.site.register(Student) admin.site.register(Teacher) @@ -13,3 +13,4 @@ admin.site.register(Department) admin.site.register(SubjectFromDept) +admin.site.register(Division) diff --git a/ClassLens_DB/Home/models.py b/ClassLens_DB/Home/models.py index 3e26ac0..784f93a 100644 --- a/ClassLens_DB/Home/models.py +++ b/ClassLens_DB/Home/models.py @@ -1,9 +1,6 @@ from django.db import models -from pgvector.django import VectorField, IvfflatIndex, HnswIndex from django.contrib.auth.hashers import make_password, check_password - -from django.db import models -from django.db.models import F +from pgvector.django import HnswIndex, VectorField class Department(models.Model): name = models.TextField(unique=True, null=False) @@ -50,13 +47,15 @@ def __str__(self): class Subject(models.Model): code = models.TextField(unique=True, null=False,default="") name = models.TextField(null=False) + department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True) + def __str__(self): return f"{self.name}" class SubjectFromDept(models.Model): department = models.ForeignKey(Department, on_delete=models.CASCADE) year = models.IntegerField(null=False) - subject = models.ManyToManyField(Subject,null=False) + subject = models.ManyToManyField(Subject) semester=models.IntegerField(null=False) class Meta: @@ -64,16 +63,37 @@ class Meta: def __str__(self): return f"{self.department} - {self.year}" + + +class Division(models.Model): + """ + Local teaching division metadata, e.g. BE CSE 4th year Sem 8 Division A. + """ + department = models.ForeignKey(Department, on_delete=models.CASCADE) + program_name = models.TextField(null=False, default="") + year = models.IntegerField(null=False) + semester = models.IntegerField(null=False) + name = models.CharField(max_length=20, null=False) + + class Meta: + unique_together = ("department", "program_name", "year", "semester", "name") + + def __str__(self): + return ( + f"{self.program_name} {self.year}th year {self.semester}th Sem " + f"Division {self.name}" + ) class StudentEnrollment(models.Model): student_prn = models.BigIntegerField(null=False) subject = models.ForeignKey(Subject, on_delete=models.CASCADE) + division = models.ForeignKey(Division, on_delete=models.SET_NULL, null=True, blank=True) class Meta: - unique_together = ('student_prn', 'subject') + unique_together = ('student_prn', 'subject', 'division') - def _str_(self): - return f"{self.student_prn} enrolled in {self.subject}" + def __str__(self): + return f"{self.student_prn} enrolled in {self.subject} Division {self.division.name if self.division else 'N/A'}" class TeacherSubject(models.Model): teacher_id = models.ForeignKey(Teacher, on_delete=models.CASCADE) @@ -82,14 +102,15 @@ class TeacherSubject(models.Model): class Meta: unique_together = ('teacher_id', 'subject') - def _str_(self): - return f"{self.teacher.name} teaches {self.subject.name}" + def __str__(self): + return f"{self.teacher_id.name} teaches {self.subject.name}" class ClassSession(models.Model): department = models.ForeignKey(Department, on_delete=models.CASCADE) year = models.IntegerField(null=False) subject = models.ForeignKey(Subject, on_delete=models.CASCADE) teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE) + division = models.ForeignKey(Division, on_delete=models.SET_NULL, null=True, blank=True) class_datetime = models.DateTimeField(null=False) def __str__(self): diff --git a/ClassLens_DB/Home/tasks.py b/ClassLens_DB/Home/tasks.py index 485543f..4193f45 100644 --- a/ClassLens_DB/Home/tasks.py +++ b/ClassLens_DB/Home/tasks.py @@ -1,50 +1,112 @@ from celery import shared_task -import matplotlib.pyplot as plt -import cv2 import os from rest_framework.response import Response -from deepface import DeepFace import uuid -import torch from django.conf import settings from django.http import request import numpy as np from scipy.spatial.distance import cosine import json import sys, types -import torchvision.transforms.functional as F from django.db.models import F as DbF -import firebase_admin -from firebase_admin import credentials, messaging + +# Optional heavy dependencies — import lazily or fall back to None so management commands work without them +try: + import matplotlib.pyplot as plt +except Exception: + plt = None +try: + import cv2 +except Exception: + cv2 = None +try: + from deepface import DeepFace +except Exception: + DeepFace = None +try: + import torch +except Exception: + torch = None +try: + import torchvision.transforms.functional as F +except Exception: + F = None +try: + import firebase_admin + from firebase_admin import credentials, messaging +except Exception: + firebase_admin = None + credentials = None + messaging = None +try: + from gfpgan import GFPGANer +except Exception: + GFPGANer = None module_name = 'torchvision.transforms.functional_tensor' -if module_name not in sys.modules: - functional_tensor_module = types.ModuleType(module_name) - functional_tensor_module.rgb_to_grayscale = F.rgb_to_grayscale - sys.modules[module_name] = functional_tensor_module +if F is not None: + if module_name not in sys.modules: + functional_tensor_module = types.ModuleType(module_name) + functional_tensor_module.rgb_to_grayscale = F.rgb_to_grayscale + sys.modules[module_name] = functional_tensor_module -_original_torch_load = torch.load +if torch is not None: + _original_torch_load = torch.load -def patched_torch_load(f, *args, **kwargs): - if 'weights_only' not in kwargs: - kwargs['weights_only'] = False - return _original_torch_load(f, *args, **kwargs) + def patched_torch_load(f, *args, **kwargs): + if 'weights_only' not in kwargs: + kwargs['weights_only'] = False + return _original_torch_load(f, *args, **kwargs) -torch.load = patched_torch_load + torch.load = patched_torch_load -from gfpgan import GFPGANer from .models import Student, AttendanceRecord, ClassSession, StudentEnrollment, StudentAttendancePercentage -restorer = GFPGANer( - model_path='GFPGANv1.4.pth', - upscale=2, - arch='clean', - channel_multiplier=2, - bg_upsampler=None -) +# Defer GFPGAN restorer initialization until a task runs to avoid import-time file access +restorer = None + +def get_restorer(): + global restorer + if restorer is not None: + return restorer + + # If GFPGANer isn't available, skip initialization + if GFPGANer is None: + print("GFPGAN not available; skipping restorer initialization") + return None + + model_path = None + try: + from django.conf import settings as _settings + if hasattr(_settings, 'GFPGAN_MODEL_PATH') and _settings.GFPGAN_MODEL_PATH: + model_path = _settings.GFPGAN_MODEL_PATH + else: + # default to BASE_DIR/GFPGANv1.4.pth + model_path = str(_settings.BASE_DIR / 'GFPGANv1.4.pth') + except Exception: + model_path = 'GFPGANv1.4.pth' + + try: + restorer = GFPGANer( + model_path=model_path, + upscale=2, + arch='clean', + channel_multiplier=2, + bg_upsampler=None + ) + print(f"GFPGAN restorer initialized with model: {model_path}") + except Exception as e: + print(f"Warning: GFPGAN restorer failed to initialize: {e}") + restorer = None + + return restorer def initialize_firebase(): + if firebase_admin is None or credentials is None: + print("Firebase Admin SDK not available; skipping notifications") + return + if not firebase_admin._apps: cred_path = os.path.join(settings.BASE_DIR, 'firebase-service-account.json') if os.path.exists(cred_path): @@ -143,13 +205,21 @@ def evaluate_attendance(total_sessions,class_session_id:int,scheme, host): facial_area = face_data['facial_area'] x, y, w, h = facial_area['x'], facial_area['y'], facial_area['w'], facial_area['h'] - _, restored_list, _ = restorer.enhance( - face_crop_bgr, - has_aligned=False, - only_center_face=True, - paste_back=False, - weight=0.1 - ) + _restorer = get_restorer() + if _restorer is not None: + try: + _, restored_list, _ = _restorer.enhance( + face_crop_bgr, + has_aligned=False, + only_center_face=True, + paste_back=False, + weight=0.1 + ) + except Exception: + restored_list = [] + else: + restored_list = [] + face_to_scan = restored_list[0] if restored_list else face_crop_bgr face_to_scan_rgb = cv2.cvtColor(face_to_scan, cv2.COLOR_BGR2RGB) @@ -163,8 +233,12 @@ def evaluate_attendance(total_sessions,class_session_id:int,scheme, host): align=True ) captured_embedding = embedding_result[0]['embedding'] - except ValueError: - cv2.rectangle(img_bgr, (x, y), (x + w, y + h), (0, 0, 255), 2) + except Exception: + if cv2 is not None: + try: + cv2.rectangle(img_bgr, (x, y), (x + w, y + h), (0, 0, 255), 2) + except Exception: + pass continue best_score = 1.0 diff --git a/ClassLens_DB/Home/views.py b/ClassLens_DB/Home/views.py index 79e87e2..0dd9810 100644 --- a/ClassLens_DB/Home/views.py +++ b/ClassLens_DB/Home/views.py @@ -2,11 +2,18 @@ import string from django.db.models import F from rest_framework.decorators import api_view, parser_classes,permission_classes -from deepface import DeepFace -from PIL import Image +# defer heavy/optional imports so Django can run management commands without GPU/deep libs +try: + from deepface import DeepFace +except Exception: + DeepFace = None +try: + from PIL import Image +except Exception: + Image = None import numpy as np from rest_framework.response import Response -from .models import Department, Student, Teacher, SubjectFromDept, StudentAttendancePercentage,AttendanceRecord, StudentEnrollment,TeacherSubject, ClassSession, Subject,AttendancePhotos,AdminUser +from .models import Department, Student, Teacher, SubjectFromDept, StudentAttendancePercentage,AttendanceRecord, StudentEnrollment,TeacherSubject, ClassSession, Subject,AttendancePhotos,AdminUser, Division from django.db.models import Count, Q from .serializers import DepartmentSerializer,SubjectSerializer from rest_framework.parsers import MultiPartParser @@ -22,8 +29,14 @@ import environ import os from pathlib import Path -import cv2 -import matplotlib.pyplot as plt +try: + import cv2 +except Exception: + cv2 = None +try: + import matplotlib.pyplot as plt +except Exception: + plt = None import uuid from .tasks import evaluate_attendance, send_attendance_notifications from django.core.files.storage import default_storage @@ -483,6 +496,7 @@ def mark_attendance(request, *args, **kwargs): teacher_id = request.data.get("teacherID") departmentName = request.data.get("departmentName") year = request.data.get("year") + division_id = request.data.get("divisionID") # Debug log to see exactly what is received print("=" * 60) @@ -492,6 +506,7 @@ def mark_attendance(request, *args, **kwargs): print(f" teacher_id : {teacher_id!r}") print(f" department : {departmentName!r}") print(f" year : {year!r}") + print(f" division_id : {division_id!r}") print("=" * 60) missing = [] @@ -508,11 +523,16 @@ def mark_attendance(request, *args, **kwargs): return Response({"error": "Invalid teacher ID (0). Please log in again."}, status=400) try: + division = None + if division_id: + division = get_object_or_404(Division, id=division_id) + class_session = ClassSession.objects.create( department = get_object_or_404(Department, name=departmentName), year = year, subject = get_object_or_404(Subject, id=subject_id), teacher = get_object_or_404(Teacher, id=teacher_id), + division=division, class_datetime = datetime.now(), ) @@ -756,11 +776,19 @@ def get_student_dashboard(request, *args, **kwargs): "date": record.class_session.class_datetime.isoformat() }) + # compute overall attendance across all subjects (weighted by total sessions) + total_classes_sum = sum(item.get('total', 0) for item in subjects_data) + attended_sum = sum(item.get('attended', 0) for item in subjects_data) + overall_percentage = None + if total_classes_sum > 0: + overall_percentage = round((attended_sum / total_classes_sum) * 100.0, 2) + return Response({ "student_name": student.name, "prn": student.prn, + "overall_attendance": overall_percentage, "subjects": subjects_data, - "recent_activity": recent_activity + "recent_activity": recent_activity, }, status=status.HTTP_200_OK) except Exception as e: diff --git a/ClassLens_DB/scripts/fix_home_migrations.py b/ClassLens_DB/scripts/fix_home_migrations.py new file mode 100644 index 0000000..b9baeff --- /dev/null +++ b/ClassLens_DB/scripts/fix_home_migrations.py @@ -0,0 +1,22 @@ +import os +import django +import sys + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ClassLens_DB.settings') +try: + django.setup() +except Exception as e: + print('Django setup error:', e) + sys.exit(1) + +from django.db import connection + +with connection.cursor() as cur: + cur.execute("SELECT id, app, name FROM django_migrations WHERE app='Home'") + rows = cur.fetchall() + print('Home migrations in django_migrations:', rows) + if rows: + cur.execute("DELETE FROM django_migrations WHERE app='Home'") + print('Deleted Home migration entries from django_migrations') + else: + print('No Home migration entries found') diff --git a/DATABASE_SCHEMA.md b/DATABASE_SCHEMA.md new file mode 100644 index 0000000..b6390e2 --- /dev/null +++ b/DATABASE_SCHEMA.md @@ -0,0 +1,683 @@ +# ClassLens Attendance Tracking Database Schema + +## Overview + +ClassLens uses a **focused database architecture optimized for attendance tracking**. Students can view their attendance grouped by divisions, subjects, semesters, years, and departments. + +``` +┌─────────────────────────────────────┐ +│ MSUIS External API │ +│ (Faculty, Student, Subject) │ +│ (Enrollment & Division Info) │ +└──────────────┬──────────────────────┘ + │ (Sync Payload) + ▼ +┌──────────────────────────────────────────┐ +│ LAYER 1: ENROLLMENT DATA (Mirror) │ +│ (Enrollment & Division mapping only) │ +├──────────────────────────────────────────┤ +│ • APIEnrollment (student-subject-div) │ +└──────────────┬───────────────────────────┘ + │ (Project to Core) + ▼ +┌──────────────────────────────────────────┐ +│ LAYER 2: ATTENDANCE CORE TABLES │ +│ (Attendance tracking & statistics) │ +├──────────────────────────────────────────┤ +│ • Department │ +│ • Student │ +│ • Subject │ +│ • Division │ +│ • StudentEnrollment │ +│ • Teacher │ +│ • TeacherSubject │ +│ • ClassSession │ +│ • AttendanceRecord │ +│ • StudentAttendancePercentage │ +│ • AdminUser │ +└──────────────────────────────────────────┘ +``` + +--- + +## Layer 1: Enrollment Data Mirror (Simplified) + +This minimal mirror table stores enrollment data from MSUIS used to sync divisions and student enrollments. Focus is on attendance information only. + +### 1. APIEnrollment — Student Enrollment with Division & Semester + +**Location:** `DatabaseAdminApp/models.py` + +```python +class APIEnrollment(models.Model): + """Mirrors student enrollment with division and semester info from MSUIS.""" + prn = models.BigIntegerField(db_index=True) + subject_code = models.CharField(max_length=100) + department_name = models.CharField(max_length=200) + program_name = models.CharField(max_length=200) + year = models.IntegerField() + semester = models.IntegerField() + division = models.CharField(max_length=20) # A, B, C, etc. + raw_payload = models.JSONField(default=dict) + synced_at = models.DateTimeField(auto_now=True) + + class Meta: + unique_together = ('prn', 'subject_code', 'division', 'semester') +``` + +| Field | Type | Purpose | +|-------|------|---------| +| `prn` | BigInt (indexed) | Student PRN | +| `subject_code` | Char(100) | Subject code (e.g., "CS101") | +| `department_name` | Char(200) | Department name | +| `program_name` | Char(200) | Program/degree name | +| `year` | Int | Student year (1, 2, 3, 4) | +| `semester` | Int | Semester (1-8) | +| `division` | Char(20) | Division code (A, B, C, etc.) | +| `raw_payload` | JSON | Original API data | +| `synced_at` | DateTime | Last sync timestamp | + +**Why needed:** +- Store enrollment info with division and semester +- Minimal data for division and enrollment creation in core tables +- No academic grades, marks, or specialized fields +- Focus purely on attendance grouping + +**Example data:** +``` +prn: 2021001 +subject_code: "CS101" +department_name: "Department of Computer Science" +program_name: "B.E Computer Science" +year: 2 +semester: 3 +division: "A" +synced_at: 2026-05-11 12:00:00 +``` + +--- + +## Layer 2: Core Attendance Tracking Tables (Home App) + +These tables are **optimized for attendance tracking**. They contain only the essential data for recording and displaying attendance by divisions, subjects, semesters, years, and departments. + +### 6. Department — Core Department Entity + +**Location:** `Home/models.py` + +```python +class Department(models.Model): + name = models.TextField(unique=True, null=False) +``` + +| Field | Type | Purpose | +|-------|------|---------| +| `id` | AutoInt (PK) | Unique identifier | +| `name` | Text (unique) | Department name; must be unique | + +**Source:** Created from `APIFaculty.name` during MSUIS sync +**Purpose:** Core reference for all department-related data in ClassLens +**Example:** +``` +id: 10 +name: "Department of Computer Science" +``` + +--- + +### 7. Student — Core Student Entity + +**Location:** `Home/models.py` + +```python +class Student(models.Model): + prn = models.BigIntegerField(unique=True, null=False) + name = models.TextField(null=False) + email = models.EmailField(unique=True, null=False) + password_hash = models.TextField(null=True, blank=True) + year = models.IntegerField(null=False) + department = models.ForeignKey(Department, on_delete=models.CASCADE) + face_embedding = VectorField(dimensions=512, null=True, blank=True) + notification_token = models.TextField(null=True, blank=True) +``` + +| Field | Type | Purpose | +|-------|------|---------| +| `prn` | BigInt (unique) | Student PRN; primary identifier | +| `name` | Text | Full student name | +| `email` | Email (unique) | Student email for login | +| `password_hash` | Text | Hashed password for authentication | +| `year` | Int | Academic year (1, 2, 3, 4) | +| `department` | FK to Department | Department enrollment | +| `face_embedding` | Vector(512) | Face recognition during attendance photo processing | +| `notification_token` | Text | Firebase FCM token for push notifications | + +**Source:** Created/updated from `APIEnrollment` during sync +**Purpose:** Core student entity for attendance tracking +**Example:** +``` +prn: 2021001 +name: "John Kumar Singh" +email: "john@example.com" +year: 2 +department_id: 10 +``` + +--- + +### 8. Subject — Course/Paper Entity + +**Location:** `Home/models.py` + +```python +class Subject(models.Model): + code = models.TextField(unique=True, null=False) + name = models.TextField(null=False) + department = models.ForeignKey(Department, on_delete=models.CASCADE) +``` + +| Field | Type | Purpose | +|-------|------|---------| +| `id` | AutoInt (PK) | Unique identifier | +| `code` | Text (unique) | Subject code (e.g., "CS101") | +| `name` | Text | Subject name (e.g., "Data Structures") | +| `department` | FK to Department | Department offering this subject | + +**Source:** Extracted from `APIEnrollment` during sync +**Purpose:** Defines subjects for attendance tracking +**Example:** +``` +id: 50 +code: "CS101" +name: "Data Structures and Algorithms" +department_id: 10 +``` + +--- + +### 9. Division — ⭐ NEW — Teaching Division Classification + +**Location:** `Home/models.py` + +```python +class Division(models.Model): + department = models.ForeignKey(Department, on_delete=models.CASCADE) + program_name = models.TextField(null=False, default="") + year = models.IntegerField(null=False) + semester = models.IntegerField(null=False) + name = models.CharField(max_length=20, null=False) + + class Meta: + unique_together = ("department", "program_name", "year", "semester", "name") +``` + +| Field | Type | Purpose | +|-------|------|---------| +| `id` | AutoInt (PK) | Unique identifier | +| `department` | FK to Department | Which department offers this division | +| `program_name` | Text | Degree program name (e.g., "B.E Computer Science") | +| `year` | Int | Academic year (1, 2, 3, 4) | +| `semester` | Int | Semester (1-8, where 1-2=year1, 3-4=year2, etc.) | +| `name` | Char(20) | Division code (A, B, C, D, etc.) | + +**Why this table was added:** +- **Requirement**: Group students by division for attendance tracking +- Students in the same division attend the same class sessions together +- Teachers mark attendance per division +- Each division can have separate schedules/teachers + +**Uniqueness constraint:** `(department, program_name, year, semester, name)` ensures no duplicates like "CSE B.E 2nd year Sem 3 Division A" + +**Example data:** +``` +id: 1 +department_id: 10 +program_name: "B.E Computer Science" +year: 2 +semester: 3 +name: "A" + +id: 2 +department_id: 10 +program_name: "B.E Computer Science" +year: 2 +semester: 3 +name: "B" +``` + +This creates two parallel divisions (A and B) for the same year/semester, allowing independent attendance tracking. + +--- + +### 10. StudentEnrollment — Student-Subject-Division Mapping + +**Location:** `Home/models.py` + +```python +class StudentEnrollment(models.Model): + student_prn = models.BigIntegerField(null=False) + subject = models.ForeignKey(Subject, on_delete=models.CASCADE) + division = models.ForeignKey(Division, on_delete=models.CASCADE) + + class Meta: + unique_together = ('student_prn', 'subject', 'division') +``` + +| Field | Type | Purpose | +|-------|------|---------| +| `student_prn` | BigInt | Student's PRN | +| `subject` | FK to Subject | Enrolled subject | +| `division` | FK to Division | Division (A, B, C, etc.) | + +**Source:** Created from `APIEnrollment` during sync +**Purpose:** Track which students are enrolled in which subjects within specific divisions +**Example:** +``` +student_prn: 2021001, subject_id: 50, division_id: 1 # John in CS101, Division A +student_prn: 2021001, subject_id: 51, division_id: 1 # John in CS102, Division A +``` + +--- + +### 11. TeacherSubject — Teacher-Subject Mapping + +**Location:** `Home/models.py` + +```python +class TeacherSubject(models.Model): + teacher_id = models.ForeignKey(Teacher, on_delete=models.CASCADE) + subject = models.ForeignKey(Subject, on_delete=models.CASCADE) + + class Meta: + unique_together = ('teacher_id', 'subject') +``` + +**Purpose:** Track which teacher teaches which subject +**Example:** +``` +teacher_id: 5, subject_id: 50 # Dr. Smith teaches CS101 +``` + +--- + +### 12. ClassSession — ⭐ MODIFIED — Attendance Session Record + +**Location:** `Home/models.py` + +```python +class ClassSession(models.Model): + department = models.ForeignKey(Department, on_delete=models.CASCADE) + year = models.IntegerField(null=False) + subject = models.ForeignKey(Subject, on_delete=models.CASCADE) + teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE) + division = models.ForeignKey(Division, on_delete=models.SET_NULL, null=True, blank=True) # ⭐ NEW + class_datetime = models.DateTimeField(null=False) +``` + +| Field | Type | Purpose | +|-------|------|---------| +| `id` | AutoInt (PK) | Unique session identifier | +| `department` | FK to Department | Which department | +| `year` | Int | Student year | +| `subject` | FK to Subject | Subject taught | +| `teacher` | FK to Teacher | Teacher who taught | +| `division` | FK to Division | ⭐ **NEW** — Which division attended | +| `class_datetime` | DateTime | When the class happened | + +**Why `division` field was added:** +- **Before:** Couldn't distinguish "Class of CS101 for Div A" from "Class of CS101 for Div B" +- **After:** Can track separate class sessions for each division +- When teacher marks attendance, they specify division +- Attendance only applies to that division's students + +**Example:** +``` +ClassSession 1: + subject_id: 50 (CS101) + teacher_id: 5 (Dr. Smith) + division_id: 1 (CSE B.E 2nd year Sem 3 Div A) + class_datetime: 2026-05-11 10:00 AM + +ClassSession 2: + subject_id: 50 (CS101) + teacher_id: 5 (Dr. Smith) + division_id: 2 (CSE B.E 2nd year Sem 3 Div B) + class_datetime: 2026-05-11 12:00 PM +``` + +--- + +### 13. AttendanceRecord — Individual Student Attendance + +**Location:** `Home/models.py` + +```python +class AttendanceRecord(models.Model): + class_session = models.ForeignKey(ClassSession, on_delete=models.CASCADE) + student = models.ForeignKey(Student, on_delete=models.CASCADE) + status = models.BooleanField() # True = Present, False = Absent + marked_at = models.DateTimeField(auto_now_add=True) + + class Meta: + unique_together = ('class_session', 'student') +``` + +**Purpose:** One record per student per class session +**Example:** +``` +class_session_id: 1 +student_id: 1001 +status: True # Student was present +marked_at: 2026-05-11 10:30 AM +``` + +--- + +### 14. StudentAttendancePercentage — Aggregated Per-Subject Attendance + +**Location:** `Home/models.py` + +```python +class StudentAttendancePercentage(models.Model): + student = models.ForeignKey(Student, on_delete=models.CASCADE) + subject = models.ForeignKey(Subject, on_delete=models.CASCADE) + present_count = models.IntegerField(null=False, default=0) + attendancePercentage = models.FloatField(null=False, default=0.0) +``` + +| Field | Type | Purpose | +|-------|------|---------| +| `student` | FK to Student | Which student | +| `subject` | FK to Subject | For which subject | +| `present_count` | Int | Number of classes attended | +| `attendancePercentage` | Float | (present_count / total_classes) * 100 | + +**Purpose:** Quick lookup of per-subject attendance without recalculating +**Used by:** Student dashboard to show per-subject attendance breakdown +**Example:** +``` +student_id: 1001 +subject_id: 50 +present_count: 17 +attendancePercentage: 85.0 # (17 / 20) * 100 +``` + +--- + +### 15. Teacher — Existing Core Table + +**Location:** `Home/models.py` + +```python +class Teacher(models.Model): + name = models.TextField(null=False) + email = models.EmailField(unique=True, null=False) + password_hash = models.TextField(null=True) + department = models.ForeignKey(Department, on_delete=models.CASCADE) + date_joined = models.DateField(null=True, auto_now_add=True) +``` + +**Purpose:** Core teacher entity for ClassLens +**No changes in this release** + +--- + +### 16. AdminUser — Admin Authentication + +**Location:** `Home/models.py` + +```python +class AdminUser(models.Model): + username = models.CharField(max_length=150, unique=True) + password = models.CharField(max_length=128) + is_active = models.BooleanField(default=True) + created_at = models.DateTimeField(auto_now_add=True) + + @property + def is_authenticated(self): + return True +``` + +**Purpose:** Admin users for managing MSUIS sync and system configuration + +--- + +## Data Flow: Attendance-Only Sync Workflow + +### Scenario: Sync 1 student enrolled in 2 subjects in Division A + +#### Input: Enrollment API Payload + +```json +{ + "enrollments": [ + { + "prn": 2021001, + "subject_code": "CS101", + "department_name": "Department of Computer Science", + "program_name": "B.E Computer Science", + "year": 2, + "semester": 3, + "division": "A" + }, + { + "prn": 2021001, + "subject_code": "CS102", + "department_name": "Department of Computer Science", + "program_name": "B.E Computer Science", + "year": 2, + "semester": 3, + "division": "A" + } + ], + "apply_to_core": true +} +``` + +#### Step 1: Mirror Storage (APIEnrollment) + +**APIEnrollment table (2 records):** +``` +prn: 2021001 +subject_code: "CS101" +department_name: "Department of Computer Science" +program_name: "B.E Computer Science" +year: 2 +semester: 3 +division: "A" +synced_at: 2026-05-11 12:00:00 + +prn: 2021001 +subject_code: "CS102" +department_name: "Department of Computer Science" +program_name: "B.E Computer Science" +year: 2 +semester: 3 +division: "A" +synced_at: 2026-05-11 12:00:00 +``` + +#### Step 2: Core Table Projection (When apply_to_core=true) +programme_name: "B.E Computer Science" +part_term_status: "Active" +``` + +**APIStudentPartTermPaperMap table (2 records):** +``` +msuis_id: 1000, prn: 2021001, paper_id: 50, division: "A" +msuis_id: 1001, prn: 2021001, paper_id: 51, division: "A" +``` + +#### Step 2: Projection → Core Operational Tables + +**Department table (if not exists):** +``` +id: 10 +name: "Department of Computer Science" +``` + +**Student table (create/update):** +``` +prn: 2021001 +name: "John Kumar Singh" # Merged from first/middle/last +email: "john.singh@example.com" +year: 2 +department_id: 10 +``` + +**Subject table (2 records, if not exist):** +``` +id: 50, code: "CS101", name: "Data Structures" +id: 51, code: "CS102", name: "Algorithms" +``` + +**Division table (create/update):** +``` +id: 1 +department_id: 10 +program_name: "B.E Computer Science" +year: 2 +semester: 3 +name: "A" +``` + +**StudentEnrollment table (2 records):** +``` +student_prn: 2021001, subject_id: 50, division_id: 1 +student_prn: 2021001, subject_id: 51, division_id: 1 +``` + +**StudentAttendancePercentage table (2 records, initialized):** +``` +student_id: 1001, subject_id: 50, present_count: 0, attendancePercentage: 0.0 +student_id: 1001, subject_id: 51, present_count: 0, attendancePercentage: 0.0 +``` + +--- + +## Why Two Layers? + +| Aspect | Mirror Layer | Core Layer | +|--------|--------------|-----------| +| **Purpose** | Store enrollment data from API exactly | Track attendance and display to students | +| **Data Retention** | Keep enrollment records | Keep attendance records and metrics | +| **Transformations** | None—raw API data | Normalized enrollments + attendance aggregations | +| **Update Pattern** | Upsert (idempotent) | Insert attendance records, update percentages | +| **Key Focus** | Enrollment data (student-subject-division) | Attendance metrics (present%, per-subject, per-division) | +| **Access Pattern** | Historical sync lookup | Real-time attendance dashboard queries | + +### Real-world Scenario: + +1. API sends enrollment: PRN 2021001 in CS101 Division A Semester 3 +2. Mirror table (APIEnrollment) stores exactly as received +3. Core creates: Student, Subject, Division, StudentEnrollment +4. Teacher marks attendance for 20 classes of this division +5. Student dashboard shows: "Overall: 85%, CS101: 85%, CS102: 90%" + +--- + +## Summary of Attendance-Focused Architecture + +### Core Purpose +**Track and display student attendance by division, subject, semester, year, and department** + +### Key Components + +**Mirror Layer (DatabaseAdminApp):** +- APIEnrollment — Stores enrollment data with division and semester info + +**Core Layer (Home app):** +- Division — Groups students by year, semester, program, department +- StudentEnrollment — Links student to subject + division +- ClassSession — Records when a class session occurs (per division) +- AttendanceRecord — Individual student attendance in each session +- StudentAttendancePercentage — Computed per-subject attendance % + +**Data Flow:** +1. Admin syncs enrollments via `POST /api/admin/sync/msuis/` +2. API data stored in APIEnrollment mirror table +3. Core tables auto-created/updated (Division, Student, Subject, StudentEnrollment) +4. Teachers use app to mark attendance (upload class photos) +5. System recognizes faces and marks attendance in AttendanceRecord +6. StudentAttendancePercentage automatically computed +7. Students see dashboard: Overall attendance + per-subject breakdown + by division/semester/year + +--- + +## Database Diagrams + +### Entity Relationship: Core Layer + +``` +Department + ├─ Student + ├─ Teacher + ├─ Subject + │ ├─ TeacherSubject + │ └─ StudentEnrollment + └─ Division + └─ ClassSession + ├─ AttendanceRecord + │ └─ Student + └─ AttendancePhotos +``` + +### Data Flow: API → Mirror → Core + +``` +MSUIS API + ↓ +APIFaculty, APIStudent, APIPaper, APIStudentAcademicInformation, APIStudentPartTermPaperMap + ↓ (Projection with apply_to_core=true) +Department, Student, Subject, Division, StudentEnrollment + ↓ +ClassSession → AttendanceRecord → StudentAttendancePercentage +``` + +--- + +## Indexing Strategy + +- **APIStudent.prn**: Primary key, used for lookups +- **APIStudentAcademicInformation.prn**: Indexed for joins +- **APIStudentPartTermPaperMap.prn**: Indexed for lookups +- **Student.face_embedding**: HNSW vector index for face recognition similarity search +- **AttendanceRecord**: Unique constraint (class_session, student) +- **StudentEnrollment**: Unique constraint (student_prn, subject) + +--- + +## Access Patterns + +### Admin Operations +``` +POST /api/admin/sync/msuis/ → Populates all mirror tables → Projects to core tables +GET /api/admin/divisions/ → Lists Division records +``` + +### Teacher Operations +``` +POST /api/markAttendance → Creates ClassSession with division → Creates AttendanceRecords +GET /api/teacher/subjects/ → Lists Teacher's subjects via TeacherSubject +``` + +### Student Operations +``` +POST /api/student/dashboard/ → Queries: + - Student by prn + - StudentEnrollment by student_prn + - StudentAttendancePercentage per subject + - AttendanceRecord recent activity +``` + +--- + +## Notes + +1. **Mirror tables use MSUIS IDs as primary keys** — ensures idempotent upserts during sync +2. **Core tables use auto-increment IDs** — standard ClassLens references +3. **Division is unique by (dept, program, year, semester, name)** — prevents duplicates +4. **StudentAttendancePercentage is computed** — updated when attendance is marked +5. **face_embedding uses pgvector** — enables similarity-based student identification during attendance photo processing +6. **RABBITMQ_URL required in .env** — settings.py imports it at module load time + diff --git a/DBMSUIS_V7.sql b/DBMSUIS_V7.sql new file mode 100644 index 0000000000000000000000000000000000000000..e4001424db19e4147e3063b3801e4e21901ad023 GIT binary patch literal 129752 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 ZlhL5$0CcXvpXt2%)#}&$)ZDYB{{JJMBJcnJ literal 0 HcmV?d00001 diff --git a/DBMSUIS_V7_utf8.sql b/DBMSUIS_V7_utf8.sql new file mode 100644 index 0000000..3e7cb13 --- /dev/null +++ b/DBMSUIS_V7_utf8.sql @@ -0,0 +1,1335 @@ +USE [MSUISv7_0] +GO +/****** Object: Table [dbo].[IncAcademicYear] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncAcademicYear]( + [Id] [int] NOT NULL, + [AcademicYearCode] [nvarchar](20) NOT NULL, + [SequenceNo] [int] NULL, + [FromDate] [datetime] NULL, + [ToDate] [datetime] NULL, + [IsOpen] [bit] NULL, + [IsActive] [bit] NULL, + [IsDeleted] [bit] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [CancellationFeeRefundEndDate] [datetime] NULL, + [AdmissionEndDate] [datetime] NULL, + [IsCurrentYear] [bit] NULL, + [IsDSWApplicationStart] [bit] NULL, + [DSWStartDate] [datetime] NULL, + [DSWEndDate] [datetime] NULL, + [DSWApplicationFee] [decimal](7, 2) NULL, + [DSWYearlyBudget] [decimal](10, 2) NULL, + CONSTRAINT [PK_IncAcademicYear] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncInstitutePartTermPaperMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncInstitutePartTermPaperMap]( + [Id] [bigint] NOT NULL, + [InstituteId] [int] NOT NULL, + [ProgInstPartTermId] [bigint] NOT NULL, + [PartTermPaperMapId] [bigint] NOT NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_IncInstitutePartTermPaperMap] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncPreferanceGroupMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncPreferanceGroupMap]( + [Id] [bigint] NOT NULL, + [PreferenceId] [int] NOT NULL, + [GroupId] [bigint] NOT NULL, + [ProgrammeInstancePartTermId] [bigint] NOT NULL, + [IsActive] [bit] NULL, + [IsDeleted] [bit] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_IncPreferanceGroupMap] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncProgInstPartTermPaperMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncProgInstPartTermPaperMap]( + [Id] [bigint] NOT NULL, + [ProgrammeInstancePartTermId] [bigint] NOT NULL, + [PaperId] [bigint] NOT NULL, + [GroupId] [bigint] NULL, + [IsActive] [bit] NULL, + [IsDelete] [bit] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_IncProgInstPartTermPaperMap] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncProgrammeInstance] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncProgrammeInstance]( + [Id] [bigint] NOT NULL, + [ProgrammeId] [int] NOT NULL, + [AcademicYearId] [int] NOT NULL, + [FacultyId] [int] NOT NULL, + [InstanceName] [nvarchar](500) NOT NULL, + [Intake] [int] NULL, + [AdmissionRight] [nvarchar](50) NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_IncProgrammeInstance] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncProgrammeInstancePart] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncProgrammeInstancePart]( + [Id] [bigint] NOT NULL, + [InstancePartName] [nvarchar](1000) NULL, + [ProgrammeInstanceId] [bigint] NOT NULL, + [ProgrammePartId] [int] NOT NULL, + [MaxMarks] [int] NULL, + [MinMarks] [int] NULL, + [IsSeparatePassingHead] [bit] NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [IsAllowPaperSelByStudent] [bit] NULL, + [AcademicYearId] [int] NULL, + CONSTRAINT [PK_AdmProgramInstancePart] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncProgrammeInstancePartTerm] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncProgrammeInstancePartTerm]( + [Id] [int] NOT NULL, + [InstancePartTermName] [nvarchar](max) NULL, + [ProgrammeBranchMapId] [int] NOT NULL, + [SpecialisationId] [int] NOT NULL, + [ProgrammePartId] [int] NOT NULL, + [ProgrammeInstancePartId] [bigint] NOT NULL, + [ProgrammePartTermId] [int] NOT NULL, + [FacultyId] [int] NOT NULL, + [ProgrammeId] [int] NOT NULL, + [AcademicYearId] [int] NOT NULL, + [ProgrammeInstanceId] [bigint] NOT NULL, + [MinPapers] [int] NOT NULL, + [MaxPapers] [int] NOT NULL, + [MinMarks] [int] NULL, + [MaxMarks] [int] NULL, + [IsForApplication] [bit] NULL, + [IsForAdmission] [bit] NULL, + [Intake] [int] NULL, + [InstanceYearId] [int] NULL, + [IsSeparatePassingHead] [bit] NULL, + [IsLaunch] [bit] NULL, + [LaunchedBy] [bigint] NULL, + [LaunchedOn] [datetime] NULL, + [UnLaunchedBy] [bigint] NULL, + [UnLaunchedOn] [datetime] NULL, + [IsVerify] [bit] NULL, + [VerifiedBy] [bigint] NULL, + [StructureReportRemark] [nvarchar](max) NULL, + [IsApprovedStructureReport] [bit] NULL, + [ApprovedStructureReportBy] [bigint] NULL, + [ApprovedStructureReportOn] [datetime] NULL, + [AssessmentReportRemark] [nvarchar](max) NULL, + [IsApprovedAssessmentReport] [bit] NULL, + [ApprovedAssessmentReportBy] [bigint] NULL, + [ApprovedAssessmentReportOn] [datetime] NULL, + [VerifiedOn] [datetime] NULL, + [IsAssessmentLaunched] [bit] NULL, + [AssessmentLaunchedBy] [bigint] NULL, + [AssessmentLaunchedOn] [datetime] NULL, + [IsAssessmentVerified] [bit] NULL, + [AssessmentVerifiedBy] [bigint] NULL, + [AssessmentVerifiedOn] [datetime] NULL, + [IsCentrallyAdmission] [bit] NULL, + [IsCompleted] [bit] NULL, + [CompletedBy] [bigint] NULL, + [CompletedOn] [datetime] NULL, + [IsCompletedAssessment] [bit] NULL, + [AssessmentCompletedBy] [bigint] NULL, + [AssessmentCompletedOn] [datetime] NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [IsPaperSelByStudent] [bit] NULL, + [IsPaperSelBeforeFees] [bit] NULL, + [IsPreferenceRequired] [bit] NULL, + [IsAdmThroughGCAS] [bit] NULL, + [IsPrerequisiteRequired] [bit] NULL, + CONSTRAINT [PK_MstProgramInstancePartTerm] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncProgrammeInstancePartTermPaperGroup] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup]( + [Id] [bigint] NOT NULL, + [ProgrammeInstancePartTermId] [bigint] NOT NULL, + [MstPartTermGroupId] [bigint] NOT NULL, + [ContainsSubgroup] [bit] NOT NULL, + [IsSubGroup] [bit] NULL, + [ParentGroupId] [bigint] NULL, + [MinPapers] [int] NULL, + [MaxPapers] [int] NULL, + [MinSubgroup] [int] NULL, + [MaxSubgroup] [int] NULL, + [SeparatePassingHead] [bit] NULL, + [MinMarks] [int] NULL, + [MaxMarks] [int] NULL, + [MinCredits] [decimal](5, 2) NULL, + [MaxCredits] [decimal](5, 2) NULL, + [IsActive] [bit] NULL, + [IsDeleted] [bit] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_MstProgrammeInstancePaperGroup] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncStudentAcademicInformation] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncStudentAcademicInformation]( + [Id] [bigint] NOT NULL, + [PRN] [bigint] NOT NULL, + [StudentAdmissionId] [bigint] NOT NULL, + [ProgrammeInstancePartId] [bigint] NULL, + [ProgrammeInstancePartTermId] [bigint] NOT NULL, + [ProgrammeId] [int] NOT NULL, + [SpecialisationId] [int] NOT NULL, + [AcademicYearId] [int] NOT NULL, + [InstituteId] [int] NOT NULL, + [FacultyId] [int] NOT NULL, + [AdmissionFeeCategoryId] [int] NULL, + [AdmissionFeeCategoryPartTermMapId] [bigint] NULL, + [PreferenceGroupId] [int] NULL, + [AdmissionCommitteeId] [int] NULL, + [AllotmentNo] [nvarchar](50) NULL, + [MeritNo] [nvarchar](50) NULL, + [PartTermStatus] [nvarchar](50) NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [IsDeleted] [bit] NULL, + [PartStatus] [nvarchar](50) NULL, + [CancelForReAdmission] [bit] NULL, + [IsMarkedAsTransfered] [bit] NULL, + [IsEligibleForDegree] [bit] NULL, + [IsLateral] [bit] NULL, + [IsExempted] [bit] NULL, + [DegreeExamEventId] [int] NULL, + [IsAdmissionCancelled] [bit] NULL, + [ExamMasterId] [int] NULL, + CONSTRAINT [PK_IncStudentAcademicInformation] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncStudentAdmission] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncStudentAdmission]( + [Id] [bigint] NOT NULL, + [PRN] [bigint] NOT NULL, + [ProgrammeInstancePartId] [bigint] NOT NULL, + [ProgrammeInstancePartTermId] [bigint] NOT NULL, + [ProgrammeId] [int] NOT NULL, + [SpecialisationId] [int] NOT NULL, + [AcademicYearId] [int] NOT NULL, + [InstituteId] [int] NOT NULL, + [FacultyId] [int] NOT NULL, + [AdmissionFeeCategoryId] [int] NOT NULL, + [AdmissionFeeCategoryPartTermMapId] [bigint] NOT NULL, + [EligibilityByFaculty] [nvarchar](500) NULL, + [ApprovedByFaculty] [bigint] NULL, + [ApprovedOnFaculty] [datetime] NULL, + [AdminRemarkByFaculty] [nvarchar](3000) NULL, + [EligibilityByAcademics] [nvarchar](100) NULL, + [ApprovedByAcademics] [bigint] NULL, + [ApprovedOnAcademics] [datetime] NULL, + [AdminRemarkByAcademics] [nvarchar](3000) NULL, + [AdmissionStatus] [nvarchar](50) NULL, + [IsDualAdmission] [bit] NULL, + [DualAdmissionDoc] [nvarchar](3000) NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [IsDeleted] [bit] NULL, + [IsTransferAdmission] [bit] NULL, + [TransferAdmissionRemarksByFaculty] [nvarchar](3000) NULL, + [TransferAdmissionRemarksByAcademic] [nvarchar](3000) NULL, + [TransferAdmissionDoc] [nvarchar](3000) NULL, + [CancelForReAdmission] [bit] NULL, + [IsMarkedAsTransfered] [bit] NULL, + [IsEligibleForDegree] [bit] NULL, + [IsLateral] [bit] NULL, + [DegreeExamEventId] [int] NULL, + [IsAdmissionCancelled] [bit] NULL, + [GCAS_ApplicationNo] [nvarchar](50) NULL, + [AdmittedGenResCategoryId] [int] NULL, + [IsAdmittedInPHDisabled] [bit] NULL, + [MSUIS_DisabilityId] [tinyint] NULL, + CONSTRAINT [PK_IncStudentAdmission] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[IncStudentPartTermPaperMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[IncStudentPartTermPaperMap]( + [Id] [bigint] NOT NULL, + [PRN] [bigint] NULL, + [StudentAcademicInformationId] [bigint] NULL, + [ProgrammeInstancePartTermId] [bigint] NULL, + [PaperId] [bigint] NULL, + [MstPaperId] [bigint] NULL, + [ObtainedMarks] [decimal](4, 0) NULL, + [ObtainedGrade] [nvarchar](4) NULL, + [PaperStatus] [nvarchar](50) NULL, + [PartTermStatus] [nvarchar](50) NULL, + [IsExempted] [bit] NULL, + [ResultStatus] [nvarchar](50) NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [IsDeleted] [bit] NULL, + [IsLateral] [bit] NULL, + [IsAdmissionCancelled] [bit] NULL, + [Division] [nvarchar](10) NULL, + [ExamMasterId] [int] NULL, + CONSTRAINT [PK_IncStudentPartTermPaperMap] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstInstitute] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstInstitute]( + [Id] [int] NOT NULL, + [InstituteName] [nvarchar](200) NOT NULL, + [InstituteCode] [nvarchar](20) NOT NULL, + [InstituteType] [nvarchar](20) NULL, + [InstituteAddress] [nvarchar](max) NULL, + [CityName] [nvarchar](50) NULL, + [Pincode] [int] NULL, + [InstituteContactNo] [nvarchar](15) NULL, + [InstituteFaxNo] [nvarchar](20) NULL, + [InstituteEmail] [nvarchar](150) NULL, + [InstituteUrl] [nvarchar](max) NULL, + [IsConsiderForAdmission] [bit] NOT NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_MstInstitute] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstInstituteProgrammeMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstInstituteProgrammeMap]( + [Id] [int] NOT NULL, + [InstituteId] [int] NULL, + [ProgrammeId] [int] NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedOn] [datetime] NULL, + [CreatedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + CONSTRAINT [PK_MstInstituteProgramMap] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstPaper] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstPaper]( + [Id] [bigint] NOT NULL, + [SubjectId] [int] NOT NULL, + [PaperName] [nvarchar](1000) NOT NULL, + [PaperCode] [nvarchar](30) NOT NULL, + [IsCredit] [bit] NOT NULL, + [MaxMarks] [int] NULL, + [MinMarks] [int] NULL, + [Credits] [decimal](5, 2) NULL, + [IsSeparatePassingHead] [bit] NOT NULL, + [EvaluationId] [int] NULL, + [ClassGradeTemplateId] [int] NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_MstPaper] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstPaperTeachingLearningMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstPaperTeachingLearningMap]( + [Id] [bigint] NOT NULL, + [PaperId] [bigint] NOT NULL, + [TeachingLearningMethodId] [int] NOT NULL, + [AssessmentMethodId] [int] NOT NULL, + [AssessmentType] [nvarchar](15) NULL, + [AssessmentMethodMarks] [int] NULL, + [AssessmentTypeMinMarks] [int] NULL, + [AssessmentTypeMaxMarks] [int] NULL, + [IsExemption] [bit] NULL, + [IsCarryForwarded] [bit] NULL, + [NoOfLecturesPerWeek] [int] NULL, + [NoOfHoursPerWeek] [decimal](5, 2) NULL, + [NoOfCredits] [decimal](5, 2) NULL, + [IsActive] [bit] NULL, + [IsDeleted] [bit] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_MstPaperTeachingLearningMap] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstProgramme] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstProgramme]( + [Id] [int] NOT NULL, + [ProgrammeName] [nvarchar](300) NOT NULL, + [ProgrammeCode] [nvarchar](100) NOT NULL, + [FacultyId] [int] NOT NULL, + [ProgrammeDescription] [nvarchar](max) NULL, + [ProgrammeLevelId] [int] NOT NULL, + [ProgrammeModeId] [int] NOT NULL, + [ProgrammeTypeId] [int] NOT NULL, + [InstructionMediumId] [int] NOT NULL, + [EvaluationId] [int] NOT NULL, + [IsCBCS] [bit] NOT NULL, + [IsSepartePassingHead] [bit] NULL, + [MaxMarks] [int] NULL, + [MinMarks] [int] NULL, + [MaxCredits] [decimal](5, 2) NULL, + [MinCredits] [decimal](5, 2) NULL, + [ProgrammeDuration] [int] NOT NULL, + [ProgrammeValidity] [int] NOT NULL, + [TotalParts] [int] NOT NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [IsNEP] [bit] NULL, + CONSTRAINT [PK_MstProgramme] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstProgrammeBranchMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstProgrammeBranchMap]( + [Id] [int] NOT NULL, + [ProgrammeId] [int] NOT NULL, + [SpecialisationId] [int] NOT NULL, + [SubSpecialisationId] [int] NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_MstProgrammeBranchMap] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstProgrammePart] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstProgrammePart]( + [Id] [int] NOT NULL, + [ProgrammeId] [int] NOT NULL, + [ExamPatternId] [int] NOT NULL, + [PartName] [nvarchar](100) NULL, + [PartShortName] [nvarchar](50) NULL, + [SequenceNo] [bigint] NULL, + [NoOfTerms] [bigint] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [IsActive] [bit] NULL, + [IsDeleted] [bit] NULL, + CONSTRAINT [PK_MstProgrammePart] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY], + CONSTRAINT [IX_MstProgrammePart] UNIQUE NONCLUSTERED +( + [PartName] ASC, + [PartShortName] ASC, + [ProgrammeId] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstProgrammePartTerm] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstProgrammePartTerm]( + [Id] [int] NOT NULL, + [PartId] [int] NOT NULL, + [PartTermName] [nvarchar](max) NOT NULL, + [PartTermShortName] [nvarchar](100) NOT NULL, + [SequenceNo] [int] NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [IsBranchChangeAllowed] [bit] NULL, + CONSTRAINT [PK_MstProgrammePartTerm] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstProgrammePartTermPaperMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstProgrammePartTermPaperMap]( + [Id] [bigint] NOT NULL, + [PartTermId] [int] NULL, + [PaperId] [bigint] NULL, + [GroupId] [bigint] NULL, + [IsActive] [bit] NULL, + [IsDelete] [bit] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_MstProgrammePartTermPaperMap] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstSpecialisation] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstSpecialisation]( + [Id] [int] NOT NULL, + [BranchName] [nvarchar](100) NOT NULL, + [FacultyId] [int] NOT NULL, + [InstituteId] [int] NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_MstSpecialisation] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstStudent] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstStudent]( + [PRN] [bigint] NOT NULL, + [LastName] [nvarchar](50) NULL, + [FirstName] [nvarchar](50) NULL, + [MiddleName] [nvarchar](50) NULL, + [NameAsPerMarksheet] [nvarchar](100) NULL, + [Gender] [nvarchar](25) NULL, + [ReligionId] [bigint] NULL, + [OtherReligion] [nvarchar](20) NULL, + [MaritalStatusId] [bigint] NULL, + [MotherTongueId] [bigint] NULL, + [CommunicationLanguageId] [bigint] NULL, + [DOB] [date] NULL, + [DOBDoc] [nvarchar](50) NULL, + [PhotoIdDoc] [nvarchar](100) NULL, + [BloodGroupId] [bigint] NULL, + [HeightInCms] [decimal](18, 2) NULL, + [WeightInKgs] [decimal](18, 2) NULL, + [IsMajorThelesamiaStatus] [nvarchar](30) NULL, + [IsNRI] [bit] NULL, + [CountryIdOfCitizenship] [bigint] NULL, + [Caste] [nvarchar](20) NULL, + [PlaceOfBirth] [nvarchar](20) NULL, + [PassportNumber] [nvarchar](50) NULL, + [PassportDate] [date] NULL, + [AadharNumber] [nvarchar](20) NULL, + [AadharDoc] [nvarchar](50) NULL, + [NameOnAadhar] [nvarchar](50) NULL, + [PermanentAddress] [nvarchar](max) NULL, + [PermanentCountryId] [bigint] NULL, + [PermanentStateId] [bigint] NULL, + [PermanentDistrictId] [bigint] NULL, + [PermanentCityVillage] [nvarchar](50) NULL, + [PermanentPincode] [bigint] NULL, + [IsCurrentAsPermanent] [bit] NULL, + [CurrentAddress] [nvarchar](max) NULL, + [CurrentCountryId] [bigint] NULL, + [CurrentStateId] [bigint] NULL, + [CurrentDistrictId] [bigint] NULL, + [CurrentCityVillage] [nvarchar](50) NULL, + [CurrentPincode] [bigint] NULL, + [NameOfFather] [nvarchar](50) NULL, + [NameOfMother] [nvarchar](50) NULL, + [FatherMotherContactNo] [nvarchar](20) NULL, + [SpouseName] [nvarchar](50) NULL, + [SocialCategoryId] [bigint] NULL, + [GSocialCategoryId] [bigint] NULL, + [IsSocialDocSubmitted] [bit] NULL, + [IsEWSDocSubmitted] [bit] NULL, + [IsPCDocSubmitted] [bit] NULL, + [IsReservationDocSubmitted] [bit] NULL, + [SocialCategoryDoc] [nvarchar](50) NULL, + [ReservationCategoryDoc] [nvarchar](max) NULL, + [ApplicationCategoryId] [bigint] NULL, + [GuardianName] [nvarchar](50) NULL, + [GuardianContactNo] [nvarchar](50) NULL, + [FamilyAnnualIncome] [bigint] NULL, + [OccupationIdOfFather] [bigint] NULL, + [OccupationIdOfMother] [bigint] NULL, + [OccupationIdOfGuardian] [bigint] NULL, + [IsEmp] [bit] NULL, + [CurrentEmployerName] [nvarchar](50) NULL, + [IsGuardianEbc] [bit] NULL, + [GuardianAnnualIncome] [bigint] NULL, + [EmailId] [nvarchar](50) NULL, + [MobileNo] [nvarchar](50) NULL, + [OptionalMobileNo] [nvarchar](50) NULL, + [IsSmsPermissionGiven] [bit] NULL, + [IsLocalToVadodara] [bit] NULL, + [ActivityId] [bigint] NULL, + [ActivityName] [nvarchar](50) NULL, + [ParticipationLevelsId] [bigint] NULL, + [SecuredRankId] [bigint] NULL, + [IsEWS] [nvarchar](50) NULL, + [EWSDoc] [nvarchar](max) NULL, + [IsPhysicallyChallenged] [nvarchar](50) NULL, + [PCDoc] [nvarchar](max) NULL, + [DisabilityPercentage] [bigint] NULL, + [DisabilityType] [nvarchar](50) NULL, + [StudentPhoto] [nvarchar](max) NULL, + [StudentSignature] [nvarchar](max) NULL, + [IsTransferFromApplicant] [bit] NULL, + [IsEmailSend] [bit] NULL, + [EmailSendOn] [datetime] NULL, + [IsSMSSend] [bit] NULL, + [SMSSendOn] [datetime] NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + [ABCId] [bigint] NULL, + [IsLastQualifyMS] [bit] NULL, + [FacultyId] [int] NULL, + [ProgrammeName] [nvarchar](100) NULL, + [PRNorEnrollNo] [nvarchar](30) NULL, + [PassingYear] [int] NULL, + [AdmissionYear] [int] NULL, + [NCLCerti] [nvarchar](max) NULL, + [NCLCertiNo] [nvarchar](30) NULL, + [NCLCerti_IsuueDate] [date] NULL, + [NCLCertiValidityDate] [date] NULL, + [EWS_IADoc] [nvarchar](50) NULL, + [EWSCertiNo] [nvarchar](30) NULL, + [EWSCerti_IsuueDate] [date] NULL, + [EWSCertiValidityDate] [date] NULL, + [GCAS_ApplicationNo] [nvarchar](50) NULL, + [GCAS_ApplicantName] [nvarchar](100) NULL, + [NameAsPerABCId] [nchar](100) NULL, + [DeviceToken] [nvarchar](255) NULL, + CONSTRAINT [PK_MstStudent] PRIMARY KEY CLUSTERED +( + [PRN] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO +/****** Object: Table [dbo].[MstSubSpecialisation] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[MstSubSpecialisation]( + [Id] [int] IDENTITY(1,1) NOT NULL, + [SpecialisationId] [int] NOT NULL, + [SubSpecialisationName] [nvarchar](50) NOT NULL, + [IsActive] [bit] NOT NULL, + [IsDeleted] [bit] NOT NULL, + [CreatedBy] [bigint] NULL, + [CreatedOn] [datetime] NULL, + [ModifiedBy] [bigint] NULL, + [ModifiedOn] [datetime] NULL, + CONSTRAINT [PK_MstSubSpecialisation] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePart] ADD CONSTRAINT [DF_IncProgrammeInstancePart_IsSeparatePassingHead] DEFAULT ((0)) FOR [IsSeparatePassingHead] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] ADD CONSTRAINT [DF_IncProgrammeInstancePartTerm_IsSeparatePassingHead] DEFAULT ((0)) FOR [IsSeparatePassingHead] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] ADD CONSTRAINT [DF_IncProgrammeInstancePartTermPaperGroup_SeparatePassingHead] DEFAULT ((0)) FOR [SeparatePassingHead] +GO +ALTER TABLE [dbo].[MstInstitute] ADD CONSTRAINT [DF_MstInstitute_IsConsiderForAdmission] DEFAULT ((1)) FOR [IsConsiderForAdmission] +GO +ALTER TABLE [dbo].[MstPaperTeachingLearningMap] ADD CONSTRAINT [DF_MstPaperTeachingLearningMap_AssessmentTypeMinMarks] DEFAULT ((0)) FOR [AssessmentTypeMinMarks] +GO +ALTER TABLE [dbo].[MstPaperTeachingLearningMap] ADD CONSTRAINT [DF_MstPaperTeachingLearningMap_AssessmentTypeMaxMarks] DEFAULT ((0)) FOR [AssessmentTypeMaxMarks] +GO +ALTER TABLE [dbo].[MstStudent] ADD CONSTRAINT [DF_MstStudent_IsTransferFromApplicant] DEFAULT ((0)) FOR [IsTransferFromApplicant] +GO +ALTER TABLE [dbo].[IncInstitutePartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncInstitutePartTermPaperMap_IncProgInstPartTermPaperMap] FOREIGN KEY([PartTermPaperMapId]) +REFERENCES [dbo].[IncProgInstPartTermPaperMap] ([Id]) +GO +ALTER TABLE [dbo].[IncInstitutePartTermPaperMap] CHECK CONSTRAINT [FK_IncInstitutePartTermPaperMap_IncProgInstPartTermPaperMap] +GO +ALTER TABLE [dbo].[IncInstitutePartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncInstitutePartTermPaperMap_MstInstitute] FOREIGN KEY([InstituteId]) +REFERENCES [dbo].[MstInstitute] ([Id]) +GO +ALTER TABLE [dbo].[IncInstitutePartTermPaperMap] CHECK CONSTRAINT [FK_IncInstitutePartTermPaperMap_MstInstitute] +GO +ALTER TABLE [dbo].[IncPreferanceGroupMap] WITH CHECK ADD CONSTRAINT [FK_IncPreferanceGroupMap_IncProgrammeInstancePartTermPaperGroup] FOREIGN KEY([GroupId]) +REFERENCES [dbo].[IncProgrammeInstancePartTermPaperGroup] ([Id]) +GO +ALTER TABLE [dbo].[IncPreferanceGroupMap] CHECK CONSTRAINT [FK_IncPreferanceGroupMap_IncProgrammeInstancePartTermPaperGroup] +GO +ALTER TABLE [dbo].[IncPreferanceGroupMap] WITH CHECK ADD CONSTRAINT [FK_IncPreferanceGroupMap_MstPreferenceGroup] FOREIGN KEY([PreferenceId]) +REFERENCES [dbo].[MstPreferenceGroup] ([Id]) +GO +ALTER TABLE [dbo].[IncPreferanceGroupMap] CHECK CONSTRAINT [FK_IncPreferanceGroupMap_MstPreferenceGroup] +GO +ALTER TABLE [dbo].[IncProgInstPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncProgInstPartTermPaperMap_IncProgrammeInstancePartTermPaperGroup] FOREIGN KEY([GroupId]) +REFERENCES [dbo].[IncProgrammeInstancePartTermPaperGroup] ([Id]) +GO +ALTER TABLE [dbo].[IncProgInstPartTermPaperMap] CHECK CONSTRAINT [FK_IncProgInstPartTermPaperMap_IncProgrammeInstancePartTermPaperGroup] +GO +ALTER TABLE [dbo].[IncProgInstPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncProgInstPartTermPaperMap_MstPaper] FOREIGN KEY([PaperId]) +REFERENCES [dbo].[MstPaper] ([Id]) +GO +ALTER TABLE [dbo].[IncProgInstPartTermPaperMap] CHECK CONSTRAINT [FK_IncProgInstPartTermPaperMap_MstPaper] +GO +ALTER TABLE [dbo].[IncProgrammeInstance] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstance_IncAcademicYear] FOREIGN KEY([AcademicYearId]) +REFERENCES [dbo].[IncAcademicYear] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstance] CHECK CONSTRAINT [FK_IncProgrammeInstance_IncAcademicYear] +GO +ALTER TABLE [dbo].[IncProgrammeInstance] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstance_MstFaculty] FOREIGN KEY([FacultyId]) +REFERENCES [dbo].[MstFaculty] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstance] CHECK CONSTRAINT [FK_IncProgrammeInstance_MstFaculty] +GO +ALTER TABLE [dbo].[IncProgrammeInstance] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstance_MstProgramme] FOREIGN KEY([ProgrammeId]) +REFERENCES [dbo].[MstProgramme] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstance] CHECK CONSTRAINT [FK_IncProgrammeInstance_MstProgramme] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePart] WITH CHECK ADD CONSTRAINT [FK_AdmProgramInstancePart_MstProgrammePart] FOREIGN KEY([ProgrammePartId]) +REFERENCES [dbo].[MstProgrammePart] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePart] CHECK CONSTRAINT [FK_AdmProgramInstancePart_MstProgrammePart] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePart] WITH NOCHECK ADD CONSTRAINT [FK_IncProgrammeInstancePart_IncProgrammeInstance] FOREIGN KEY([ProgrammeInstanceId]) +REFERENCES [dbo].[IncProgrammeInstance] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePart] CHECK CONSTRAINT [FK_IncProgrammeInstancePart_IncProgrammeInstance] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgramInstancePartTerm_MstProgrammePart] FOREIGN KEY([ProgrammePartId]) +REFERENCES [dbo].[MstProgrammePart] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgramInstancePartTerm_MstProgrammePart] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgramInstancePartTerm_MstProgrammePartTerm] FOREIGN KEY([ProgrammePartTermId]) +REFERENCES [dbo].[MstProgrammePartTerm] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgramInstancePartTerm_MstProgrammePartTerm] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgramInstancePartTerm_MstSpecialisation] FOREIGN KEY([SpecialisationId]) +REFERENCES [dbo].[MstSpecialisation] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgramInstancePartTerm_MstSpecialisation] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncAcademicYear] FOREIGN KEY([AcademicYearId]) +REFERENCES [dbo].[IncAcademicYear] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncAcademicYear] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncProgrammeInstance] FOREIGN KEY([ProgrammeInstanceId]) +REFERENCES [dbo].[IncProgrammeInstance] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncProgrammeInstance] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncProgrammeInstancePart] FOREIGN KEY([ProgrammeInstancePartId]) +REFERENCES [dbo].[IncProgrammeInstancePart] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncProgrammeInstancePart] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_MstFaculty] FOREIGN KEY([FacultyId]) +REFERENCES [dbo].[MstFaculty] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_MstFaculty] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_MstProgrammePartTerm] FOREIGN KEY([ProgrammePartTermId]) +REFERENCES [dbo].[MstProgrammePartTerm] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_MstProgrammePartTerm] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_IncProgramInstancePart] FOREIGN KEY([ProgrammeInstancePartId]) +REFERENCES [dbo].[IncProgrammeInstancePart] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_IncProgramInstancePart] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_IncProgrammeInstance] FOREIGN KEY([ProgrammeInstanceId]) +REFERENCES [dbo].[IncProgrammeInstance] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_IncProgrammeInstance] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_MstFaculty] FOREIGN KEY([FacultyId]) +REFERENCES [dbo].[MstFaculty] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_MstFaculty] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_MstProgramme] FOREIGN KEY([ProgrammeId]) +REFERENCES [dbo].[MstProgramme] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_MstProgramme] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_MstProgrammeBranchMap] FOREIGN KEY([ProgrammeBranchMapId]) +REFERENCES [dbo].[MstProgrammeBranchMap] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_MstProgrammeBranchMap] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTermPaperGroup_IncProgrammeInstancePartTermPaperGroup] FOREIGN KEY([MstPartTermGroupId]) +REFERENCES [dbo].[MstPartTermGroupMap] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTermPaperGroup_IncProgrammeInstancePartTermPaperGroup] +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] WITH CHECK ADD CONSTRAINT [FK_MstProgrammeInstancePaperGroup_MstProgrammeInstancePaperGroup] FOREIGN KEY([ParentGroupId]) +REFERENCES [dbo].[IncProgrammeInstancePartTermPaperGroup] ([Id]) +GO +ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] CHECK CONSTRAINT [FK_MstProgrammeInstancePaperGroup_MstProgrammeInstancePaperGroup] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_ExamEventMaster] FOREIGN KEY([DegreeExamEventId]) +REFERENCES [dbo].[ExamEventMaster] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_ExamEventMaster] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_FeeCategoryPartTermMap] FOREIGN KEY([AdmissionFeeCategoryPartTermMapId]) +REFERENCES [dbo].[FeeCategoryPartTermMap] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_FeeCategoryPartTermMap] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_IncAcademicYear] FOREIGN KEY([AcademicYearId]) +REFERENCES [dbo].[IncAcademicYear] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_IncAcademicYear] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_IncProgrammeInstancePart] FOREIGN KEY([ProgrammeInstancePartId]) +REFERENCES [dbo].[IncProgrammeInstancePart] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_IncProgrammeInstancePart] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_IncStudentAdmission] FOREIGN KEY([StudentAdmissionId]) +REFERENCES [dbo].[IncStudentAdmission] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_IncStudentAdmission] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstAdmissionCommittee] FOREIGN KEY([AdmissionCommitteeId]) +REFERENCES [dbo].[MstAdmissionCommittee] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstAdmissionCommittee] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstFaculty] FOREIGN KEY([FacultyId]) +REFERENCES [dbo].[MstFaculty] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstFaculty] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstFeeCategory] FOREIGN KEY([AdmissionFeeCategoryId]) +REFERENCES [dbo].[MstFeeCategory] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstFeeCategory] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstInstitute] FOREIGN KEY([InstituteId]) +REFERENCES [dbo].[MstInstitute] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstInstitute] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstPreferenceGroup] FOREIGN KEY([PreferenceGroupId]) +REFERENCES [dbo].[MstPreferenceGroup] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstPreferenceGroup] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstProgramme] FOREIGN KEY([ProgrammeId]) +REFERENCES [dbo].[MstProgramme] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstProgramme] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstSpecialisation] FOREIGN KEY([SpecialisationId]) +REFERENCES [dbo].[MstSpecialisation] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstSpecialisation] +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstStudent] FOREIGN KEY([PRN]) +REFERENCES [dbo].[MstStudent] ([PRN]) +GO +ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstStudent] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_ExamEventMaster] FOREIGN KEY([DegreeExamEventId]) +REFERENCES [dbo].[ExamEventMaster] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_ExamEventMaster] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_FeeCategoryPartTermMap] FOREIGN KEY([AdmissionFeeCategoryPartTermMapId]) +REFERENCES [dbo].[FeeCategoryPartTermMap] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_FeeCategoryPartTermMap] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_IncAcademicYear] FOREIGN KEY([AcademicYearId]) +REFERENCES [dbo].[IncAcademicYear] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_IncAcademicYear] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_IncProgrammeInstancePart] FOREIGN KEY([ProgrammeInstancePartId]) +REFERENCES [dbo].[IncProgrammeInstancePart] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_IncProgrammeInstancePart] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_IncProgrammeInstancePartTerm] FOREIGN KEY([SpecialisationId]) +REFERENCES [dbo].[MstSpecialisation] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_IncProgrammeInstancePartTerm] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstFaculty] FOREIGN KEY([FacultyId]) +REFERENCES [dbo].[MstFaculty] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstFaculty] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstFeeCategory] FOREIGN KEY([AdmissionFeeCategoryId]) +REFERENCES [dbo].[MstFeeCategory] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstFeeCategory] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstInstitute] FOREIGN KEY([InstituteId]) +REFERENCES [dbo].[MstInstitute] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstInstitute] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstProgramme] FOREIGN KEY([ProgrammeId]) +REFERENCES [dbo].[MstProgramme] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstProgramme] +GO +ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstStudent] FOREIGN KEY([PRN]) +REFERENCES [dbo].[MstStudent] ([PRN]) +GO +ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstStudent] +GO +ALTER TABLE [dbo].[IncStudentPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncStudentPartTermPaperMap_IncProgInstPartTermPaperMap] FOREIGN KEY([PaperId]) +REFERENCES [dbo].[IncProgInstPartTermPaperMap] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentPartTermPaperMap] CHECK CONSTRAINT [FK_IncStudentPartTermPaperMap_IncProgInstPartTermPaperMap] +GO +ALTER TABLE [dbo].[IncStudentPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncStudentPartTermPaperMap_IncStudentAcademicInformation] FOREIGN KEY([StudentAcademicInformationId]) +REFERENCES [dbo].[IncStudentAcademicInformation] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentPartTermPaperMap] CHECK CONSTRAINT [FK_IncStudentPartTermPaperMap_IncStudentAcademicInformation] +GO +ALTER TABLE [dbo].[IncStudentPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncStudentPartTermPaperMap_MstPaper] FOREIGN KEY([MstPaperId]) +REFERENCES [dbo].[MstPaper] ([Id]) +GO +ALTER TABLE [dbo].[IncStudentPartTermPaperMap] CHECK CONSTRAINT [FK_IncStudentPartTermPaperMap_MstPaper] +GO +ALTER TABLE [dbo].[IncStudentPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncStudentPartTermPaperMap_MstStudent] FOREIGN KEY([PRN]) +REFERENCES [dbo].[MstStudent] ([PRN]) +GO +ALTER TABLE [dbo].[IncStudentPartTermPaperMap] CHECK CONSTRAINT [FK_IncStudentPartTermPaperMap_MstStudent] +GO +ALTER TABLE [dbo].[MstInstituteProgrammeMap] WITH CHECK ADD CONSTRAINT [FK_MstInstituteProgrammeMap_MstInstitute] FOREIGN KEY([InstituteId]) +REFERENCES [dbo].[MstInstitute] ([Id]) +GO +ALTER TABLE [dbo].[MstInstituteProgrammeMap] CHECK CONSTRAINT [FK_MstInstituteProgrammeMap_MstInstitute] +GO +ALTER TABLE [dbo].[MstInstituteProgrammeMap] WITH CHECK ADD CONSTRAINT [FK_MstInstituteProgrammeMap_MstProgramme] FOREIGN KEY([ProgrammeId]) +REFERENCES [dbo].[MstProgramme] ([Id]) +GO +ALTER TABLE [dbo].[MstInstituteProgrammeMap] CHECK CONSTRAINT [FK_MstInstituteProgrammeMap_MstProgramme] +GO +ALTER TABLE [dbo].[MstPaper] WITH CHECK ADD CONSTRAINT [FK_MstPaper_MstSubject] FOREIGN KEY([SubjectId]) +REFERENCES [dbo].[MstSubject] ([Id]) +GO +ALTER TABLE [dbo].[MstPaper] CHECK CONSTRAINT [FK_MstPaper_MstSubject] +GO +ALTER TABLE [dbo].[MstPaperTeachingLearningMap] WITH NOCHECK ADD CONSTRAINT [FK_MstPaperTeachingLearningMap_MstAssessmentMethod] FOREIGN KEY([AssessmentMethodId]) +REFERENCES [dbo].[MstAssessmentMethod] ([Id]) +GO +ALTER TABLE [dbo].[MstPaperTeachingLearningMap] CHECK CONSTRAINT [FK_MstPaperTeachingLearningMap_MstAssessmentMethod] +GO +ALTER TABLE [dbo].[MstPaperTeachingLearningMap] WITH CHECK ADD CONSTRAINT [FK_MstPaperTeachingLearningMap_MstPaper] FOREIGN KEY([PaperId]) +REFERENCES [dbo].[MstPaper] ([Id]) +GO +ALTER TABLE [dbo].[MstPaperTeachingLearningMap] CHECK CONSTRAINT [FK_MstPaperTeachingLearningMap_MstPaper] +GO +ALTER TABLE [dbo].[MstPaperTeachingLearningMap] WITH CHECK ADD CONSTRAINT [FK_MstPaperTeachingLearningMap_MstTeachingLearningMethod] FOREIGN KEY([TeachingLearningMethodId]) +REFERENCES [dbo].[MstTeachingLearningMethod] ([Id]) +GO +ALTER TABLE [dbo].[MstPaperTeachingLearningMap] CHECK CONSTRAINT [FK_MstPaperTeachingLearningMap_MstTeachingLearningMethod] +GO +ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstEvaluation] FOREIGN KEY([EvaluationId]) +REFERENCES [dbo].[MstEvaluation] ([Id]) +GO +ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstEvaluation] +GO +ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstFaculty] FOREIGN KEY([FacultyId]) +REFERENCES [dbo].[MstFaculty] ([Id]) +GO +ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstFaculty] +GO +ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstInstructionMedium] FOREIGN KEY([InstructionMediumId]) +REFERENCES [dbo].[MstInstructionMedium] ([Id]) +GO +ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstInstructionMedium] +GO +ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstProgrammeLevel] FOREIGN KEY([ProgrammeLevelId]) +REFERENCES [dbo].[MstProgrammeLevel] ([Id]) +GO +ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstProgrammeLevel] +GO +ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstProgrammeMode] FOREIGN KEY([ProgrammeModeId]) +REFERENCES [dbo].[MstProgrammeMode] ([Id]) +GO +ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstProgrammeMode] +GO +ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstProgrammeType] FOREIGN KEY([ProgrammeTypeId]) +REFERENCES [dbo].[MstProgrammeType] ([Id]) +GO +ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstProgrammeType] +GO +ALTER TABLE [dbo].[MstProgrammeBranchMap] WITH CHECK ADD CONSTRAINT [FK_MstProgrammeBranchMap_MstProgramme] FOREIGN KEY([ProgrammeId]) +REFERENCES [dbo].[MstProgramme] ([Id]) +GO +ALTER TABLE [dbo].[MstProgrammeBranchMap] CHECK CONSTRAINT [FK_MstProgrammeBranchMap_MstProgramme] +GO +ALTER TABLE [dbo].[MstProgrammeBranchMap] WITH CHECK ADD CONSTRAINT [FK_MstProgrammeBranchMap_MstSpecialisation] FOREIGN KEY([SpecialisationId]) +REFERENCES [dbo].[MstSpecialisation] ([Id]) +GO +ALTER TABLE [dbo].[MstProgrammeBranchMap] CHECK CONSTRAINT [FK_MstProgrammeBranchMap_MstSpecialisation] +GO +ALTER TABLE [dbo].[MstProgrammeBranchMap] WITH CHECK ADD CONSTRAINT [FK_MstProgrammeBranchMap_MstSubSpecialisation] FOREIGN KEY([SubSpecialisationId]) +REFERENCES [dbo].[MstSubSpecialisation] ([Id]) +GO +ALTER TABLE [dbo].[MstProgrammeBranchMap] CHECK CONSTRAINT [FK_MstProgrammeBranchMap_MstSubSpecialisation] +GO +ALTER TABLE [dbo].[MstProgrammePart] WITH CHECK ADD CONSTRAINT [FK_MstProgrammePart_MstExaminationPattern] FOREIGN KEY([ExamPatternId]) +REFERENCES [dbo].[MstExaminationPattern] ([Id]) +GO +ALTER TABLE [dbo].[MstProgrammePart] CHECK CONSTRAINT [FK_MstProgrammePart_MstExaminationPattern] +GO +ALTER TABLE [dbo].[MstProgrammePart] WITH CHECK ADD CONSTRAINT [FK_MstProgrammePart_MstProgramme] FOREIGN KEY([ProgrammeId]) +REFERENCES [dbo].[MstProgramme] ([Id]) +GO +ALTER TABLE [dbo].[MstProgrammePart] CHECK CONSTRAINT [FK_MstProgrammePart_MstProgramme] +GO +ALTER TABLE [dbo].[MstProgrammePartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK__MstProgrammePartTerm] FOREIGN KEY([PartTermId]) +REFERENCES [dbo].[MstProgrammePartTerm] ([Id]) +GO +ALTER TABLE [dbo].[MstProgrammePartTermPaperMap] CHECK CONSTRAINT [FK__MstProgrammePartTerm] +GO +ALTER TABLE [dbo].[MstProgrammePartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_MstPaper] FOREIGN KEY([PaperId]) +REFERENCES [dbo].[MstPaper] ([Id]) +GO +ALTER TABLE [dbo].[MstProgrammePartTermPaperMap] CHECK CONSTRAINT [FK_MstPaper] +GO +ALTER TABLE [dbo].[MstSpecialisation] WITH CHECK ADD CONSTRAINT [FK_MstSpecialisation_MstFaculty] FOREIGN KEY([FacultyId]) +REFERENCES [dbo].[MstFaculty] ([Id]) +GO +ALTER TABLE [dbo].[MstSpecialisation] CHECK CONSTRAINT [FK_MstSpecialisation_MstFaculty] +GO +ALTER TABLE [dbo].[MstSpecialisation] WITH CHECK ADD CONSTRAINT [FK_MstSpecialisation_MstInstitute] FOREIGN KEY([InstituteId]) +REFERENCES [dbo].[MstInstitute] ([Id]) +GO +ALTER TABLE [dbo].[MstSpecialisation] CHECK CONSTRAINT [FK_MstSpecialisation_MstInstitute] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_AdmExtraAct] FOREIGN KEY([ActivityId]) +REFERENCES [dbo].[AdmExtraAct] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_AdmExtraAct] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_AdmExtraCuriculam] FOREIGN KEY([ParticipationLevelsId]) +REFERENCES [dbo].[AdmExtraCuriculam] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_AdmExtraCuriculam] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_AdmExtraCuriculamActivity] FOREIGN KEY([SecuredRankId]) +REFERENCES [dbo].[AdmExtraCuriculamActivity] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_AdmExtraCuriculamActivity] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_BloodGroup] FOREIGN KEY([BloodGroupId]) +REFERENCES [dbo].[BloodGroup] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_BloodGroup] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_CommunicationLanguage] FOREIGN KEY([CommunicationLanguageId]) +REFERENCES [dbo].[CommunicationLanguage] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_CommunicationLanguage] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_CountryMaster] FOREIGN KEY([CountryIdOfCitizenship]) +REFERENCES [dbo].[CountryMaster] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_CountryMaster] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_CountryMaster1] FOREIGN KEY([PermanentCountryId]) +REFERENCES [dbo].[CountryMaster] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_CountryMaster1] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_CountryMaster2] FOREIGN KEY([CurrentCountryId]) +REFERENCES [dbo].[CountryMaster] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_CountryMaster2] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_DistrictMaster] FOREIGN KEY([PermanentDistrictId]) +REFERENCES [dbo].[DistrictMaster] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_DistrictMaster] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_DistrictMaster1] FOREIGN KEY([CurrentDistrictId]) +REFERENCES [dbo].[DistrictMaster] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_DistrictMaster1] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_GenMaritalStatus] FOREIGN KEY([MaritalStatusId]) +REFERENCES [dbo].[GenMaritalStatus] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_GenMaritalStatus] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_MaritalStatusId] FOREIGN KEY([MaritalStatusId]) +REFERENCES [dbo].[GenMaritalStatus] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_MaritalStatusId] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_MotherTongue] FOREIGN KEY([MotherTongueId]) +REFERENCES [dbo].[MotherTongue] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_MotherTongue] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_Occupation] FOREIGN KEY([OccupationIdOfFather]) +REFERENCES [dbo].[GenOccupation] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_Occupation] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_Occupation1] FOREIGN KEY([OccupationIdOfMother]) +REFERENCES [dbo].[GenOccupation] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_Occupation1] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_Occupation2] FOREIGN KEY([OccupationIdOfGuardian]) +REFERENCES [dbo].[GenOccupation] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_Occupation2] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_ReligionMaster] FOREIGN KEY([ReligionId]) +REFERENCES [dbo].[ReligionMaster] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_ReligionMaster] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_StateMaster] FOREIGN KEY([PermanentStateId]) +REFERENCES [dbo].[StateMaster] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_StateMaster] +GO +ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_StateMaster1] FOREIGN KEY([CurrentStateId]) +REFERENCES [dbo].[StateMaster] ([Id]) +GO +ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_StateMaster1] +GO +ALTER TABLE [dbo].[MstSubSpecialisation] WITH CHECK ADD CONSTRAINT [FK_MstSubSpecialisation_MstSpecialisation] FOREIGN KEY([SpecialisationId]) +REFERENCES [dbo].[MstSpecialisation] ([Id]) +GO +ALTER TABLE [dbo].[MstSubSpecialisation] CHECK CONSTRAINT [FK_MstSubSpecialisation_MstSpecialisation] +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Inactive in case name change or modified' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncInstitutePartTermPaperMap', @level2type=N'COLUMN',@level2name=N'IsActive' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Soft Delete' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncInstitutePartTermPaperMap', @level2type=N'COLUMN',@level2name=N'IsDeleted' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Academic Year' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncProgrammeInstance', @level2type=N'COLUMN',@level2name=N'AcademicYearId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Intake Capacity' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncProgrammeInstance', @level2type=N'COLUMN',@level2name=N'Intake' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Programme Instance' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncProgrammeInstancePart', @level2type=N'COLUMN',@level2name=N'ProgrammeInstanceId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Address of the Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteAddress' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Code of the city' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'CityName' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Pincode' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'Pincode' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Contact No of Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteContactNo' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Fax no of Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteFaxNo' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Email Id of Head of Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteEmail' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Website Url of the Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteUrl' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Inactive in case name change or modified' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'IsActive' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Soft Delete' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'IsDeleted' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Name of Paper' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstPaper', @level2type=N'COLUMN',@level2name=N'PaperName' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Code of paper' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstPaper', @level2type=N'COLUMN',@level2name=N'PaperCode' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Name of the Programme (Bachelor of Commerce)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeName' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Short name of the Programme (B.Com.)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeCode' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Faculty from which the programme is offered' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'FacultyId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Level of Programme like Certificate, Under Graduate, Diploma' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeLevelId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Mode of Programme: Regular or Distance ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeModeId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Type: General/Technical/Research' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeTypeId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Medium of Instruction' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'InstructionMediumId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Evaluation : Marks/Direct Grade/Indirect Grade' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'EvaluationId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Total Programme duration in Months' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeDuration' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Validity of Programme in Months' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeValidity' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Total Year or Parts of the Programme' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'TotalParts' +GO diff --git a/FRONTEND_CHANGES.md b/FRONTEND_CHANGES.md new file mode 100644 index 0000000..ec4e30f --- /dev/null +++ b/FRONTEND_CHANGES.md @@ -0,0 +1,328 @@ +# Frontend Changes Required - ClassLens Attendance System + +## Summary +Backend schema updated to support: +- **Division** model (department-level grouping) +- **API mirror tables** for MSUIS data ingestion +- **Overall + per-subject attendance** in student dashboard + +This document outlines all frontend changes needed to work with the new backend API contract. + +--- + +## 1. Admin App Changes + +### 1.1 Division Management (New Feature) +**Location:** Admin Dashboard → Division Management + +**New CRUD Endpoint:** +``` +GET /api/admin/divisions/ - List all divisions +POST /api/admin/divisions/ - Create division +GET /api/admin/divisions/{id}/ - Get division details +PUT /api/admin/divisions/{id}/ - Update division +DELETE /api/admin/divisions/{id}/ - Delete division +``` + +**Form Fields (for Create/Edit):** +- `department` (ForeignKey) - dropdown, required +- `program_name` (CharField) - e.g., "B.E Computer Science" +- `year` (IntegerField) - 1, 2, 3, 4 +- `semester` (IntegerField) - 1-8 +- `name` (CharField) - e.g., "A", "B", "C" (division code) + +**UI Changes:** +- Add "Divisions" menu item in admin sidebar +- Show table with columns: Department, Program, Year, Semester, Name +- Add "Add Division", "Edit", "Delete" buttons +- Validation: unique constraint on (department, program_name, year, semester, name) + +### 1.2 MSUIS Data Sync (New Feature) +**Location:** Admin Dashboard → Data Management → Sync MSUIS + +**New Endpoint:** +``` +POST /api/admin/sync/msuis/ +Content-Type: application/json + +Request Payload: +{ + "faculties": [ + { "Id": 1, "FacultyName": "CS Dept", "IsActive": 1, ... } + ], + "students": [ + { "PRN": 2021001, "FirstName": "John", "LastName": "Doe", + "EmailId": "john@example.com", "FacultyId": 1, "Year": 2, ... } + ], + "papers": [ + { "Id": 10, "PaperCode": "CS101", "PaperName": "Data Structures", + "SubjectId": 10, ... } + ], + "student_academic_information": [ + { "Id": 100, "PRN": 2021001, "FacultyId": 1, "AcademicYearId": 2025, ... } + ], + "student_part_term_paper_maps": [ + { "Id": 1000, "PRN": 2021001, "PaperId": 10, "Division": "A", + "Semester": 3, ... } + ], + "apply_to_core": true +} + +Response (200 OK): +{ + "message": "MSUIS payload synced via admin app", + "apply_to_core": true, + "counts": { + "faculties_synced": 1, + "students_synced": 100, + "papers_synced": 50, + "academic_records_synced": 150, + "part_term_maps_synced": 500, + "core_departments_upserted": 1, + "core_students_upserted": 100, + "core_subjects_upserted": 50, + "core_enrollments_upserted": 500, + "core_divisions_upserted": 10 + } +} +``` + +**UI Changes:** +- Add "Sync MSUIS Data" section in admin +- Large JSON text area to paste API payload (or file upload button for JSON) +- Toggle: "Apply to Core Tables" (default: checked) +- "Sync" button → POST to /api/admin/sync/msuis/ +- Show results: success/failure count, summary of upserted records +- Optional: Show mirror table counts (APIFaculty, APIStudent, etc.) + +--- + +## 2. Teacher App / Mark Attendance Changes + +### 2.1 Mark Attendance Form Update +**Location:** Teacher Dashboard → Mark Attendance + +**New Field Added:** +- **Division** (Dropdown, required) + - Fetch from: `GET /api/admin/divisions/` filtered by teacher's department + - Or fetch from: `GET /api/admin/subject-from-dept/?department={dept}&year={year}&semester={semester}` + - Display as: "Division: [A / B / C / ...]" + +**Request Update:** +```javascript +// Old request (multipart) +POST /api/markAttendance +{ + photo: [file1, file2, ...], + subjectID: 5, + teacherID: 12, + departmentName: "CSE", + year: 2 +} + +// New request (multipart) - ADD divisionID +POST /api/markAttendance +{ + photo: [file1, file2, ...], + subjectID: 5, + teacherID: 12, + departmentName: "CSE", + year: 2, + divisionID: 3 // NEW - division ID +} +``` + +**UI Changes:** +1. In the mark attendance form, add a Division dropdown **after** the Subject field +2. Populate division dropdown when subject is selected: + ``` + GET /api/admin/divisions/?department={teacher_dept}&year={selected_year} + ``` + Display: option value=division.id, text=division.name +3. Make divisionID required (validate before submit) +4. Send `divisionID` in the multipart POST request + +**Example HTML:** +```html +
+ + + + + + + +
+``` + +--- + +## 3. Student App / Dashboard Changes + +### 3.1 Student Dashboard Update +**Location:** Student Dashboard / Home + +**Endpoint Update (same endpoint, enhanced response):** +``` +POST /api/student/dashboard/ +{ + "student_id": 1 +} + +Response (200 OK): +{ + "student_name": "John Doe", + "prn": 2021001, + "overall_attendance": 85.5, // NEW - weighted average across all subjects + "subjects": [ + { + "id": 5, + "name": "Data Structures", + "code": "CS101", + "teacher": "Dr. Smith", + "total": 20, // total classes held for this subject + "attended": 17, // classes attended by student + "percentage": 85.0 // (attended / total) * 100 + }, + { + "id": 6, + "name": "Algorithms", + "code": "CS102", + "teacher": "Dr. Johnson", + "total": 18, + "attended": 15, + "percentage": 83.33 + } + ], + "recent_activity": [ + { + "subject": "Data Structures", + "status": "Present", + "date": "2026-05-10T14:30:00Z" + }, + ... + ] +} +``` + +**UI Changes:** + +#### 3.1.1 Overall Attendance Summary Card (NEW) +Add a card/section at the top of dashboard: +``` +┌─────────────────────────────────┐ +│ Overall Attendance │ +│ │ +│ 85.5% │ +│ ████████████░░░░░░░░░░░░░░░░ │ (progress bar) +│ │ +│ Across 4 subjects │ +└─────────────────────────────────┘ +``` + +**Implementation:** +- Display `response.overall_attendance` as percentage +- Show progress bar (green if >= 75%, yellow if >= 60%, red if < 60%) +- Optional: Show "Across X subjects" subtitle + +#### 3.1.2 Per-Subject Attendance List +Keep existing subject cards but enhance: + +``` +┌─────────────────────────────────────────────┐ +│ Data Structures (CS101) │ +│ Teacher: Dr. Smith │ +├─────────────────────────────────────────────┤ +│ Attendance: 17/20 (85%) │ +│ ████████████░░░░░░░░░░░░░░░░ │ +├─────────────────────────────────────────────┤ +│ • 3 classes missed │ +└─────────────────────────────────────────────┘ +``` + +**Changes:** +- Display `teacher` name (from response) +- Show `attended` and `total` (e.g., "17/20") +- Show `percentage` as progress bar color-coded: + - **Green**: >= 75% (good attendance) + - **Yellow**: 60-74% (warning) + - **Red**: < 60% (at risk) +- Calculate missed = total - attended, display + +#### 3.1.3 Recent Activity Feed +Keep existing; displayed below subjects. + +--- + +## 4. API Contract Summary + +### New/Updated Endpoints + +| Method | Endpoint | Purpose | Auth | +|--------|----------|---------|------| +| GET | `/api/admin/divisions/` | List divisions | Yes | +| POST | `/api/admin/divisions/` | Create division | Yes | +| GET | `/api/admin/divisions/{id}/` | Get division | Yes | +| PUT | `/api/admin/divisions/{id}/` | Update division | Yes | +| DELETE | `/api/admin/divisions/{id}/` | Delete division | Yes | +| POST | `/api/admin/sync/msuis/` | Sync MSUIS payload | Yes | +| POST | `/api/markAttendance` | Mark attendance (UPDATED) | No | +| POST | `/api/student/dashboard/` | Student dashboard (UPDATED) | No | + +### Field Additions +- `ClassSession.division` (ForeignKey to Division) - now passed from mark_attendance +- Student Dashboard response: `overall_attendance` (float, optional) +- Mark Attendance request: `divisionID` (integer, optional but recommended) + +--- + +## 5. Implementation Checklist + +### Admin App +- [ ] Create Division CRUD form/page +- [ ] Add Division menu item to sidebar +- [ ] Create MSUIS sync page with JSON textarea +- [ ] POST payload to /api/admin/sync/msuis/ +- [ ] Display sync results + +### Teacher App +- [ ] Add Division dropdown to mark attendance form +- [ ] Load divisions on subject selection +- [ ] Validate division is selected +- [ ] Send `divisionID` in mark attendance POST + +### Student App +- [ ] Add overall_attendance card at top of dashboard +- [ ] Style progress bars (green/yellow/red) +- [ ] Display teacher name for each subject +- [ ] Show attended/total counts +- [ ] Keep recent activity feed + +--- + +## 6. Testing Checklist + +- [ ] Create test admin account and login +- [ ] Create 2-3 divisions via admin UI +- [ ] Test mark attendance with division selection +- [ ] Verify ClassSession.division is saved +- [ ] Check student dashboard shows overall_attendance +- [ ] Verify per-subject percentages calculate correctly +- [ ] Test MSUIS sync payload import +- [ ] Verify mirror tables populated (APIStudent, APIFaculty, etc.) +- [ ] Verify core tables updated (Student, Subject, Division, etc.) + +--- + +## 7. Notes + +1. **Division is optional in mark_attendance**: If not sent, ClassSession.division will be NULL. For full functionality, always send divisionID. +2. **Overall attendance is weighted**: Calculated as (total_attended / total_classes) * 100 across all enrolled subjects. +3. **MSUIS sync is admin-only**: Use JWT auth with admin user. +4. **Mirror tables** (APIStudent, APIFaculty, etc.) store raw API data; core tables (Student, Subject, Division) store operational data. Sync can populate either or both. diff --git a/FRONTEND_CONTEXT.md b/FRONTEND_CONTEXT.md new file mode 100644 index 0000000..1e6309d --- /dev/null +++ b/FRONTEND_CONTEXT.md @@ -0,0 +1,452 @@ +# ClassLens Frontend Context & Requirements + +**Project Goal:** Attendance tracking and display system. Students see their attendance by division, subject, semester, year, and department. Admins manage enrollment sync and divisions. Teachers mark attendance via photo uploads. + +--- + +## 1. Database Schema Summary (Attendance-Focused) + +### Mirror Layer (APIEnrollment - Admin Sync) +``` +APIEnrollment { + prn: BigInt (indexed) + subject_code: String + department_name: String + program_name: String + year: Int + semester: Int + division: String (A, B, C, etc.) + raw_payload: JSON + synced_at: DateTime +} +``` + +### Core Layer (Attendance Tracking) + +**Core Entities:** +- **Department** — Department name (CS, ECE, ME, etc.) +- **Student** — prn, name, email, year, department, face_embedding, notification_token +- **Subject** — code, name, department_id +- **Division** — department_id, program_name, year, semester, name (A/B/C) — **Unique by (dept, program, year, semester, name)** +- **StudentEnrollment** — student_prn, subject_id, division_id — **Unique by (student_prn, subject, division)** +- **Teacher** — name, email, department_id +- **TeacherSubject** — teacher_id, subject_id (NO division-level control yet) + +**Attendance Tracking:** +- **ClassSession** — department_id, year, subject_id, teacher_id, division_id, class_datetime +- **AttendanceRecord** — class_session_id, student_id, status (bool), marked_at — **Unique by (class_session, student)** +- **StudentAttendancePercentage** — student_id, subject_id, present_count, attendancePercentage + +--- + +## 2. Frontend: Student Dashboard + +### What Students See + +**Overall Attendance Card:** +``` +┌─────────────────────────────────┐ +│ Your Attendance Overview │ +├─────────────────────────────────┤ +│ Overall: 82.5% │ +│ Classes Attended: 33 / 40 │ +│ Last Marked: Today, 10:30 AM │ +└─────────────────────────────────┘ +``` + +**Subject-wise Breakdown (Filtered by Division):** +``` +┌──────────────────────────────────────────┐ +│ Attendance by Subject │ +├──────────────────────────────────────────┤ +│ Subject | Attended | Total | % │ +├──────────────────────────────────────────┤ +│ Data Structures | 16/20 | 20 | 80% │ +│ Algorithms | 17/20 | 20 | 85% │ +│ DBMS | 14/18 | 18 | 78% │ +└──────────────────────────────────────────┘ +``` + +**Filter Options:** +- **By Division:** Current division (auto-selected based on enrollment) +- **By Semester:** Dropdown (1-8) +- **By Year:** Dropdown (1-4) +- **By Department:** Auto-selected from student's enrollment + +### API Endpoints (Student) + +``` +GET /api/student/dashboard/ + Returns: + { + "student": { + "prn": 2021001, + "name": "John Kumar", + "year": 2, + "department": "Computer Science" + }, + "enrollments": [ + { + "subject_id": 50, + "subject_code": "CS101", + "subject_name": "Data Structures", + "division": "A", + "semester": 3, + "year": 2 + } + ], + "overall_attendance": 82.5, + "attendance_by_subject": [ + { + "subject_code": "CS101", + "subject_name": "Data Structures", + "present_count": 16, + "total_classes": 20, + "percentage": 80.0 + } + ] + } + +GET /api/student/attendance/subject/{subject_id}/?division_id={div_id}&year={year}&semester={sem} + Returns: Detailed attendance records for that subject + +GET /api/student/divisions/ + Returns: List of divisions student is enrolled in + [ + { + "id": 1, + "name": "A", + "department": "CSE", + "program": "B.E Computer Science", + "year": 2, + "semester": 3 + } + ] +``` + +--- + +## 3. Frontend: Teacher Interface + +### What Teachers Do + +**Mark Attendance:** +1. Select Subject +2. Select Division (auto-populated from TeacherSubject, currently no division-level constraint) +3. Upload class photo +4. System recognizes faces via face_embedding (pgvector similarity search) +5. Auto-marks attendance for recognized students +6. Teacher reviews and confirms + +**View Attendance:** +- Per-subject attendance report +- Attendance history (CSV export) +- Per-student attendance breakdown + +### API Endpoints (Teacher) + +``` +POST /api/markAttendance + Input: + { + "subject_id": 50, + "division_id": 1, + "class_photo": , // Image to extract faces from + "class_datetime": "2026-05-11T10:00:00Z" + } + Returns: + { + "class_session_id": 123, + "recognized_count": 28, + "unrecognized_count": 2, + "attendance_records": [ + { + "student_prn": 2021001, + "status": true, // Present + "confidence": 0.95 + } + ] + } + +GET /api/teacher/subjects/ + Returns: List of subjects teacher teaches (via TeacherSubject) + +GET /api/teacher/subject/{subject_id}/divisions/ + Returns: Divisions this teacher teaches this subject in + +GET /api/teacher/attendance/subject/{subject_id}/?division_id={div_id} + Returns: Attendance records for that subject/division +``` + +--- + +## 4. Frontend: Admin Interface + +### What Admins Do + +**1. Sync MSUIS Enrollments** +- Upload enrollment JSON or call sync endpoint +- Enrollments must include: (prn, subject_code, division, department_name, program_name, year, semester) +- System auto-creates/updates: Department, Division, Student, Subject, StudentEnrollment + +**2. Manage Divisions** +- View all divisions by department, program, year, semester +- Create new divisions (if needed) +- Edit division name/settings + +**3. Manage Teachers & Assignments** +- Assign teachers to subjects +- ⚠️ **NOTE:** Currently TeacherSubject has no division-level control + - Teacher A can teach Subject CS101 (to all divisions) + - If needed, add division FK to TeacherSubject + +**4. View Sync Status** +- Last sync timestamp +- Number of enrollments synced +- Errors/warnings during sync + +### API Endpoints (Admin) + +``` +POST /api/admin/sync/msuis/ + Input: + { + "enrollments": [ + { + "prn": 2021001, + "subject_code": "CS101", + "department_name": "Department of Computer Science", + "program_name": "B.E Computer Science", + "year": 2, + "semester": 3, + "division": "A" + } + ], + "apply_to_core": true // Create core tables + } + Returns: + { + "status": "success", + "api_enrollments_created": 2, + "core_divisions_created": 1, + "core_students_created": 1, + "core_enrollments_created": 2, + "timestamp": "2026-05-11T12:00:00Z" + } + +GET /api/admin/divisions/ + Returns: All divisions with filters by department, program, year, semester + [ + { + "id": 1, + "department": "CSE", + "program": "B.E Computer Science", + "year": 2, + "semester": 3, + "name": "A", + "student_count": 45 + } + ] + +GET /api/admin/sync-status/ + Returns: Last sync info, error logs + +POST /api/admin/teachers/assign-subject/ + Input: + { + "teacher_id": 5, + "subject_id": 50 + // division_id: Not currently supported, consider adding + } + Returns: TeacherSubject record created +``` + +--- + +## 5. Key Data Flow + +### Enrollment Sync Workflow +``` +Admin POST /api/admin/sync/msuis/ with APIEnrollment payload + ↓ +Store in APIEnrollment mirror table + ↓ +If apply_to_core=true: + - Create/update Department (from department_name) + - Create/update Student (from prn) + - Create/update Subject (from subject_code) + - Create/update Division (from program_name, year, semester, division) + - Create/update StudentEnrollment (link student → subject → division) + - Initialize StudentAttendancePercentage (present_count=0, percentage=0.0) +``` + +### Attendance Marking Workflow +``` +Teacher POST /api/markAttendance with class photo + ↓ +Extract faces from photo (RetinaFace detector) + ↓ +Get student enrollments for that (subject, division) + ↓ +For each enrolled student: + - Compute face embedding (Facenet512 via DeepFace) + - Search pgvector for matching student.face_embedding (HNSW index) + - If match > confidence_threshold: mark present + - If no match: mark absent + ↓ +Create ClassSession record + ↓ +Create AttendanceRecord for each student + ↓ +Recompute StudentAttendancePercentage (present_count, percentage) + ↓ +Return results to teacher for review/confirmation +``` + +### Student Dashboard Query Workflow +``` +Student GET /api/student/dashboard/ + ↓ +Query Student by auth token (student.prn) + ↓ +Get StudentEnrollment records filtered by (student_prn, division_id) + ↓ +Get StudentAttendancePercentage for enrolled subjects + ↓ +Compute overall attendance: sum(present_count) / sum(total_classes) + ↓ +Return formatted response to frontend +``` + +--- + +## 6. Frontend Components Needed + +### Student App +- **Dashboard Component** + - Overall attendance card + - Subject-wise attendance table + - Filters (division, semester, year, department) + - Attendance history/timeline + +- **Subject Attendance Detail** + - Per-class attendance records + - Export to CSV/PDF + +- **Settings/Profile** + - Notification preferences + - Face registration (for attendance photo processing) + +### Teacher App +- **Mark Attendance Component** + - Subject/division selector + - Photo upload + - Face recognition preview + confirmation + - Submit attendance + +- **Attendance Reports** + - Subject-wise report + - Per-student report + - Date range filter + +### Admin App +- **Sync Dashboard** + - Upload MSUIS enrollment JSON + - Sync status/logs + - API endpoint to trigger sync + +- **Division Management** + - View all divisions (table/list) + - Create new division (if manual creation needed) + - Edit division + - View enrolled students per division + +- **Teacher Assignments** + - Assign teacher to subject + - View TeacherSubject mappings + +--- + +## 7. Important Notes + +### ⚠️ Division-Level Teacher Control +**Current Status:** TeacherSubject has NO division FK. +- Teacher A can teach Subject CS101, but system doesn't track if it's to Div A or Div B +- This is currently **flexible** (teacher can teach multiple divisions of same subject) +- If you want **stricter control** (one teacher per subject per division), add division FK to TeacherSubject + +### ⚠️ Face Recognition Setup +- **Model:** Facenet512 via DeepFace library +- **Vector Index:** pgvector with HNSW (Hierarchical Navigable Small World) +- **Embedding Dimensions:** 512 +- **Processing:** Celery task queue via RabbitMQ (async) +- **Requirements:** + - Database must have pgvector extension installed + - RabbitMQ broker running (amqp://guest:guest@localhost:5672/) + - TensorFlow/DeepFace dependencies installed + +### ⚠️ Authentication +- Students use JWT (drf-simplejwt) with student PRN +- Teachers use JWT with teacher ID +- Admins use JWT or session-based auth +- Implement refresh token rotation + +### ⚠️ Data Consistency +- Attendance is **immutable once marked** (consider adding soft-delete or review workflow) +- StudentAttendancePercentage is **computed** (updated when attendance marked) +- Division assignments are **per-student-per-enrollment** (StudentEnrollment.division_id) + +--- + +## 8. UI/UX Considerations + +### Student View +- **Simplicity:** Show only their divisions/subjects +- **Real-time:** Update attendance immediately after marking +- **Mobile-friendly:** Responsive tables, dropdown filters +- **Visual clarity:** Color-code attendance % (green ≥75%, yellow 60-74%, red <60%) + +### Teacher View +- **Ease of use:** Minimal clicks to upload and confirm attendance +- **Feedback:** Clear success/error messages +- **Batch operations:** Mark multiple classes at once if needed + +### Admin View +- **Overview:** Dashboard showing last sync time, enrollment count, error logs +- **Drill-down:** View details of specific sync batches +- **Bulk operations:** CSV export/import for divisions and teachers + +--- + +## 9. Integration Checklist + +- [ ] **Student API integration** — Dashboard, attendance details, filters +- [ ] **Teacher API integration** — Mark attendance, view reports +- [ ] **Admin API integration** — Sync enrollments, manage divisions, assign teachers +- [ ] **Authentication** — JWT tokens, refresh logic, logout +- [ ] **Error handling** — Network errors, validation errors, API errors +- [ ] **Loading states** — Show spinners during API calls +- [ ] **Notification** — Firebase FCM integration (optional, for sync notifications) +- [ ] **Testing** — API mocking, unit tests for filters and calculations + +--- + +## 10. Backend API Base URL + +``` +Development: http://localhost:8000/api/ +Production: https://api.classlens.com/api/ +``` + +All endpoints require `Authorization: Bearer ` header except public endpoints. + +--- + +## Questions for Frontend Developer + +1. **Division-level teacher control:** Should we enforce one teacher per subject per division, or allow flexibility? +2. **Face registration workflow:** Should students pre-register faces, or is on-demand recognition enough? +3. **Offline support:** Do teachers need to mark attendance offline and sync later? +4. **Multi-language support:** Required? +5. **Dark mode:** Required? + diff --git a/README.md b/README.md index 203d268..fd587de 100644 --- a/README.md +++ b/README.md @@ -175,12 +175,16 @@ RabbitMQ management UI: - Username: guest - Password: guest -Start Celery worker: +Start Celery worker on Windows: -```bash -celery -A ClassLens_DB.celery worker -l info -P gevent +```powershell +Set-Location "M:\ClassLens\classLenseBackend\ClassLens\ClassLens_DB" +$env:PYTHONPATH = "M:\ClassLens\classLenseBackend\ClassLens\ClassLens_DB" +& ".\.venv\Scripts\python.exe" -m celery -A ClassLens_DB.celery worker -l info -P solo ``` +Use `-P solo` on Windows. `gevent` is the source of the shutdown error you saw in this environment. + --- ## 🧬 GFPGAN Model Usage diff --git a/data-1778222711514.csv b/data-1778222711514.csv new file mode 100644 index 0000000..f9a6e22 --- /dev/null +++ b/data-1778222711514.csv @@ -0,0 +1,103 @@ +"table_name","column_name","data_type","is_nullable" +"Home_adminuser","id","bigint","NO" +"Home_adminuser","username","character varying","NO" +"Home_adminuser","password","character varying","NO" +"Home_adminuser","is_active","boolean","NO" +"Home_adminuser","created_at","timestamp with time zone","NO" +"Home_attendancephotos","id","bigint","NO" +"Home_attendancephotos","photo","character varying","NO" +"Home_attendancephotos","uploaded_at","timestamp with time zone","NO" +"Home_attendancephotos","class_session_id","bigint","NO" +"Home_attendancerecord","id","bigint","NO" +"Home_attendancerecord","status","boolean","NO" +"Home_attendancerecord","marked_at","timestamp with time zone","NO" +"Home_attendancerecord","class_session_id","bigint","NO" +"Home_attendancerecord","student_id","bigint","NO" +"Home_classsession","id","bigint","NO" +"Home_classsession","year","integer","NO" +"Home_classsession","class_datetime","timestamp with time zone","NO" +"Home_classsession","department_id","bigint","NO" +"Home_classsession","subject_id","bigint","NO" +"Home_classsession","teacher_id","bigint","NO" +"Home_department","id","bigint","NO" +"Home_department","name","text","NO" +"Home_student","id","bigint","NO" +"Home_student","prn","bigint","NO" +"Home_student","name","text","NO" +"Home_student","email","character varying","NO" +"Home_student","password_hash","text","YES" +"Home_student","year","integer","NO" +"Home_student","face_embedding","USER-DEFINED","YES" +"Home_student","notification_token","text","YES" +"Home_student","department_id","bigint","NO" +"Home_studentattendancepercentage","id","bigint","NO" +"Home_studentattendancepercentage","present_count","integer","NO" +"Home_studentattendancepercentage","attendancePercentage","double precision","NO" +"Home_studentattendancepercentage","student_id","bigint","NO" +"Home_studentattendancepercentage","subject_id","bigint","NO" +"Home_studentenrollment","id","bigint","NO" +"Home_studentenrollment","student_prn","bigint","NO" +"Home_studentenrollment","subject_id","bigint","NO" +"Home_subject","id","bigint","NO" +"Home_subject","code","text","NO" +"Home_subject","name","text","NO" +"Home_subjectfromdept","id","bigint","NO" +"Home_subjectfromdept","year","integer","NO" +"Home_subjectfromdept","semester","integer","NO" +"Home_subjectfromdept","department_id","bigint","NO" +"Home_subjectfromdept_subject","id","bigint","NO" +"Home_subjectfromdept_subject","subjectfromdept_id","bigint","NO" +"Home_subjectfromdept_subject","subject_id","bigint","NO" +"Home_teacher","id","bigint","NO" +"Home_teacher","name","text","NO" +"Home_teacher","email","character varying","NO" +"Home_teacher","password_hash","text","YES" +"Home_teacher","date_joined","date","YES" +"Home_teacher","department_id","bigint","NO" +"Home_teachersubject","id","bigint","NO" +"Home_teachersubject","subject_id","bigint","NO" +"Home_teachersubject","teacher_id_id","bigint","NO" +"auth_group","id","integer","NO" +"auth_group","name","character varying","NO" +"auth_group_permissions","id","bigint","NO" +"auth_group_permissions","group_id","integer","NO" +"auth_group_permissions","permission_id","integer","NO" +"auth_permission","id","integer","NO" +"auth_permission","name","character varying","NO" +"auth_permission","content_type_id","integer","NO" +"auth_permission","codename","character varying","NO" +"auth_user","id","integer","NO" +"auth_user","password","character varying","NO" +"auth_user","last_login","timestamp with time zone","YES" +"auth_user","is_superuser","boolean","NO" +"auth_user","username","character varying","NO" +"auth_user","first_name","character varying","NO" +"auth_user","last_name","character varying","NO" +"auth_user","email","character varying","NO" +"auth_user","is_staff","boolean","NO" +"auth_user","is_active","boolean","NO" +"auth_user","date_joined","timestamp with time zone","NO" +"auth_user_groups","id","bigint","NO" +"auth_user_groups","user_id","integer","NO" +"auth_user_groups","group_id","integer","NO" +"auth_user_user_permissions","id","bigint","NO" +"auth_user_user_permissions","user_id","integer","NO" +"auth_user_user_permissions","permission_id","integer","NO" +"django_admin_log","id","integer","NO" +"django_admin_log","action_time","timestamp with time zone","NO" +"django_admin_log","object_id","text","YES" +"django_admin_log","object_repr","character varying","NO" +"django_admin_log","action_flag","smallint","NO" +"django_admin_log","change_message","text","NO" +"django_admin_log","content_type_id","integer","YES" +"django_admin_log","user_id","integer","NO" +"django_content_type","id","integer","NO" +"django_content_type","app_label","character varying","NO" +"django_content_type","model","character varying","NO" +"django_migrations","id","bigint","NO" +"django_migrations","app","character varying","NO" +"django_migrations","name","character varying","NO" +"django_migrations","applied","timestamp with time zone","NO" +"django_session","session_key","character varying","NO" +"django_session","session_data","text","NO" +"django_session","expire_date","timestamp with time zone","NO" diff --git a/db-chat.txt b/db-chat.txt new file mode 100644 index 0000000..2b822db --- /dev/null +++ b/db-chat.txt @@ -0,0 +1,132 @@ + +Based on your clarification—that you're fetching data from an API with the structure of the DBMSUIS_V7.sql file (MSUIS v7 database schema), and you'll implement attendance-related services yourself—I'll provide a mapping of the exact data you can fetch and map from this file to your backend's required schema. I'll also list the remaining data/services that need to be implemented separately (e.g., attendance, admin, and other missing features). + +Key Assumptions +The MSUIS API will provide data in JSON/REST format mirroring the SQL tables (e.g., endpoints like /MstStudent, /MstFaculty, etc.). +Mapping is based on inferred fields from the SQL dump (via grep searches and references). Some fields are confirmed (e.g., PRN in MstStudent), others are assumed based on typical university schemas. +You'll need to transform/map the data during API calls (e.g., via scripts or Django views) to fit your models. +Missing tables/fields in MSUIS mean you'll skip or default them (e.g., set face_embedding to null). +No direct "teacher" table in MSUIS; faculty might serve as departments/teachers, but you'll need to adapt. +Mapped Data: What You Can Fetch and Map from MSUIS +Here's the mapping from MSUIS tables to your backend tables/fields. Only map what's available; for missing fields, use defaults or skip. + +Home_department (Map from MstFaculty) + +MSUIS Source: MstFaculty (referenced in foreign keys; CREATE TABLE not in dump, but fields inferred from usage: Id, Name, etc.). +Mapping: +id → MstFaculty.Id (primary key). +name → MstFaculty.Name (or similar field; assume it's the faculty name as department). +Notes: Faculty in MSUIS seems to represent departments/schools. If MstFaculty has more fields (e.g., code), map accordingly. No direct match for other fields. +Home_teacher (Partial Map from MstFaculty or None) + +MSUIS Source: No direct table (MstFaculty is more like departments). If faculty members are stored elsewhere, use MstFaculty; otherwise, no data. +Mapping (if using MstFaculty as proxy): +id → MstFaculty.Id. +name → MstFaculty.Name (assume name field exists). +email → Not available (default to null or generate). +password_hash → Not available (implement separately or default). +department_id → Self-reference or link to another MstFaculty if hierarchical. +date_joined → Not available (default to current date). +Notes: MSUIS may not track individual teachers. You might need to create teacher records manually or map from other sources. +Home_student (Map from MstStudent) + +MSUIS Source: MstStudent (fields inferred: PRN, FirstName, MiddleName, LastName, Email, etc.). +Mapping: +id → Auto-generated (MSUIS uses PRN as key, but map to your id). +prn → MstStudent.PRN. +name → Concatenate FirstName + MiddleName + LastName (or FullName if available). +email → MstStudent.Email. +password_hash → Not available (implement hashing separately or default). +year → From IncStudentAcademicInformation.Year (linked via PRN). +department_id → MstStudent.FacultyId (maps to Home_department). +face_embedding → Not available (implement facial recognition separately). +notification_token → Not available (implement push notifications separately). +Notes: Link to IncStudentAcademicInformation for year/department details. +Home_subject (Map from MstPaper) + +MSUIS Source: MstPaper (fields: Id, Code, Name, etc.). +Mapping: +id → MstPaper.Id. +code → MstPaper.Code. +name → MstPaper.Name. +Notes: Papers in MSUIS are subjects/courses. +Home_subjectfromdept (Partial Map from IncProgrammeInstancePartTerm or Mappings) + +MSUIS Source: IncProgrammeInstancePartTerm (links programmes, parts, terms) and MstProgrammePartTermPaperMap. +Mapping: +id → Auto-generated. +department_id → IncProgrammeInstancePartTerm.FacultyId (or from MstProgramme). +year → IncProgrammeInstancePartTerm.Year. +semester → IncProgrammeInstancePartTerm.Semester (or Term). +Subject many-to-many: From MstProgrammePartTermPaperMap.PaperId. +Notes: Complex; map programmes as departments. +Home_studentenrollment (Map from IncStudentPartTermPaperMap) + +MSUIS Source: IncStudentPartTermPaperMap (PRN, PaperId, etc.). +Mapping: +id → Auto-generated. +student_prn → IncStudentPartTermPaperMap.PRN. +subject_id → IncStudentPartTermPaperMap.PaperId. +Notes: Direct mapping for enrollments. +Home_teachersubject (No Direct Map) + +MSUIS Source: None (no teacher-subject links). +Mapping: Skip or create manually (e.g., assign based on programmes). +Notes: Implement separately. +Home_classsession (No Direct Map) + +MSUIS Source: None. +Mapping: Implement separately (your attendance service will create these). +Home_attendancephotos (No Direct Map) + +MSUIS Source: None. +Mapping: Implement separately. +Home_attendancerecord (No Direct Map) + +MSUIS Source: None. +Mapping: Implement separately. +Home_studentattendancepercentage (No Direct Map) + +MSUIS Source: None. +Mapping: Implement separately. +Home_adminuser (No Direct Map) + +MSUIS Source: None. +Mapping: Implement separately. +Home_subjectfromdept_subject (Map from Junctions) + +MSUIS Source: MstProgrammePartTermPaperMap or similar. +Mapping: subjectfromdept_id and subject_id from mappings. +Remaining Data/Services to Implement +Since MSUIS lacks attendance, admin, and some core features, you'll need to build these yourself. Here's what to implement: + +Attendance System: + +Tables: Home_classsession, Home_attendancephotos, Home_attendancerecord, Home_studentattendancepercentage. +Services: Facial recognition (DeepFace), photo upload, attendance marking, notifications (FCM), task queuing (Celery). +APIs: Mark attendance, get attendance status, teacher subjects, student dashboard, etc. +Authentication & Admin: + +Table: Home_adminuser. +Services: JWT login for admins, password hashing, user management. +APIs: Admin login, CRUD for all models. +Missing Fields/Data: + +password_hash for students/teachers (hash during registration). +face_embedding (generate via DeepFace on photo upload). +notification_token (store on app login). +date_joined for teachers (set on creation). +Teacher-subject assignments (manual or based on programmes). +Class sessions (create dynamically for attendance). +Other Services: + +OTP/email verification. +Dashboard stats (counts from fetched data). +Bulk uploads (CSV/Excel for students/teachers). +Health checks. +Implementation Steps +Fetch from MSUIS API: Use endpoints like GET /MstStudent to pull data, then map/transform in Django (e.g., in views or management commands). +Populate DB: Run scripts to insert mapped data into your models. +Build Missing Parts: Develop the attendance app as per your existing code (models, views, tasks). +Testing: Validate mappings with sample data; ensure foreign keys align. +If you share sample API responses from MSUIS or need code snippets for mapping, I can refine this! \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index f1b802b82111794acb0837532ddebe9818565b23..e30c945d0c8b590162ca50032de7f82b2c9adf78 100644 GIT binary patch delta 50 zcmdm_{!e{_2;1Zg7Bxj(hGK?HhFpdMh8%`ehAf71h7tx_AT(vr17pL@{A`PP0YsGx A1ONa4 delta 12 TcmeyTzDa$92;1fawt2h&B7Ovo diff --git a/test_sync_endpoint.py b/test_sync_endpoint.py new file mode 100644 index 0000000..411fce5 --- /dev/null +++ b/test_sync_endpoint.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +"""Test the sync_msuis_payload endpoint via Django shell.""" +import os +import sys +import django + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ClassLens_DB.settings') +sys.path.insert(0, 'ClassLens_DB') +django.setup() + +from django.test import RequestFactory +import json +from Home.models import AdminUser, Department, Student, Subject +from DatabaseAdminApp.views import sync_msuis_payload + +# Use existing admin or create one +admin = AdminUser.objects.first() +if not admin: + admin = AdminUser(username='admin', is_active=True) + admin.set_password('admin') + admin.save() + +print(f"Using admin: {admin.username} (id={admin.id})") +print(f"Departments before sync: {Department.objects.count()}") +print(f"Students before sync: {Student.objects.count()}") + +# Build mock request with payload +rf = RequestFactory() +payload = { + 'faculties': [{'Id': 100, 'FacultyName': 'Test Faculty', 'IsActive': 1}], + 'students': [{'PRN': 2025001, 'FirstName': 'John', 'MiddleName': '', 'LastName': 'Doe', 'EmailId': 'john@example.com', 'FacultyId': 100, 'Year': 2}], + 'papers': [{'Id': 500, 'PaperCode': 'TEST101', 'PaperName': 'Test Subject', 'SubjectId': 500}], + 'student_academic_information': [], + 'student_part_term_paper_maps': [{'Id': 1000, 'PRN': 2025001, 'PaperId': 500, 'Division': 'A', 'Semester': 3}], + 'apply_to_core': True +} + +req = rf.post('/api/admin/sync/msuis/', data=json.dumps(payload), content_type='application/json') +req.user = admin + +# Call the view +resp = sync_msuis_payload(req) +print(f"\nResponse status: {resp.status_code}") +print(f"Response data: {json.dumps(resp.data, indent=2)}") + +print(f"\nDepartments after sync: {Department.objects.count()}") +print(f"Students after sync: {Student.objects.count()}") +print(f"Subjects after sync: {Subject.objects.count()}") +print("\n✓ Sync endpoint test completed successfully!") From c4469f028ca4224527e8314da55189b04abe9db2 Mon Sep 17 00:00:00 2001 From: Mann Shah Date: Thu, 14 May 2026 18:42:53 +0530 Subject: [PATCH 06/14] Done some changes to make the backend working --- ClassLens_DB/ClassLens_DB/settings.py | 26 +++++++- ClassLens_DB/Home/models.py | 13 +--- setup_backend.bat | 85 +++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 setup_backend.bat diff --git a/ClassLens_DB/ClassLens_DB/settings.py b/ClassLens_DB/ClassLens_DB/settings.py index 6d4e58e..0751525 100644 --- a/ClassLens_DB/ClassLens_DB/settings.py +++ b/ClassLens_DB/ClassLens_DB/settings.py @@ -178,4 +178,28 @@ EMAIL_USE_TLS = True # Use False if using SSL (port 465) EMAIL_HOST_USER = env('EMAIL_HOST_USER') # Your email address EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD') # Your email password/app password -DEFAULT_FROM_EMAIL = env('EMAIL_HOST_USER') \ No newline at end of file +DEFAULT_FROM_EMAIL = env('EMAIL_HOST_USER') + +# Django REST Framework Configuration +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ), + 'DEFAULT_PERMISSION_CLASSES': ( + 'rest_framework.permissions.AllowAny', + ), + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'PAGE_SIZE': 100, +} + +# JWT Configuration +from datetime import timedelta + +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(hours=24), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=7), + 'ROTATE_REFRESH_TOKENS': True, + 'BLACKLIST_AFTER_ROTATION': True, + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': SECRET_KEY, +} \ No newline at end of file diff --git a/ClassLens_DB/Home/models.py b/ClassLens_DB/Home/models.py index 784f93a..6215ba0 100644 --- a/ClassLens_DB/Home/models.py +++ b/ClassLens_DB/Home/models.py @@ -1,6 +1,5 @@ from django.db import models from django.contrib.auth.hashers import make_password, check_password -from pgvector.django import HnswIndex, VectorField class Department(models.Model): name = models.TextField(unique=True, null=False) @@ -29,18 +28,8 @@ class Student(models.Model): Department, on_delete=models.CASCADE, ) - face_embedding = VectorField(dimensions=512, null=True, blank=True) + face_embedding = models.JSONField(null=True, blank=True) notification_token = models.TextField(null=True, blank=True) - class Meta: - indexes = [ - HnswIndex( - name='student_face_embedding_idx', - fields=['face_embedding'], - m=16, - ef_construction=200, - opclasses=['vector_cosine_ops'] - ), - ] def __str__(self): return f"{self.name} ({self.prn})" diff --git a/setup_backend.bat b/setup_backend.bat new file mode 100644 index 0000000..999966a --- /dev/null +++ b/setup_backend.bat @@ -0,0 +1,85 @@ +@echo off +REM ClassLens Backend Setup Script + +cd /d "m:\ClassLens\classLenseBackend\ClassLens\ClassLens_DB" + +echo. +echo ======================================== +echo ClassLens Backend Setup & Migration +echo ======================================== +echo. + +REM Activate virtual environment +echo [1/5] Activating Python virtual environment... +call .\.venv\Scripts\activate.bat + +if %ERRORLEVEL% NEQ 0 ( + echo ERROR: Failed to activate virtual environment + pause + exit /b 1 +) + +REM Make migrations +echo. +echo [2/5] Creating database migrations... +python manage.py makemigrations Home +if %ERRORLEVEL% NEQ 0 echo WARNING: makemigrations for Home had issues + +python manage.py makemigrations DatabaseAdminApp +if %ERRORLEVEL% NEQ 0 echo WARNING: makemigrations for DatabaseAdminApp had issues + +REM Run migrations +echo. +echo [3/5] Running database migrations... +python manage.py migrate +if %ERRORLEVEL% NEQ 0 ( + echo ERROR: Migration failed + echo Please check your database configuration in .env + pause + exit /b 1 +) + +REM Create default admin user +echo. +echo [4/5] Creating default admin user... +python manage.py shell << EOF +from Home.models import AdminUser +import os + +username = "admin" +password = "admin@123456" + +# Check if admin user already exists +if not AdminUser.objects.filter(username=username).exists(): + admin = AdminUser(username=username, is_active=True) + admin.set_password(password) + admin.save() + print(f"✓ Admin user created: {username}") + print(f" Password: {password}") +else: + print(f"✓ Admin user '{username}' already exists") +EOF + +REM Check Django setup +echo. +echo [5/5] Checking Django setup... +python manage.py check +if %ERRORLEVEL% NEQ 0 ( + echo WARNING: Django check reported issues +) + +echo. +echo ======================================== +echo Setup Complete! +echo ======================================== +echo. +echo Next steps: +echo 1. Ensure PostgreSQL is running +echo 2. Ensure Redis is running (for Celery results) +echo 3. Optionally start RabbitMQ (if not running, Celery will queue locally) +echo 4. Run: python manage.py runserver +echo 5. Login at http://localhost:8000/api/admin/login/ +echo Username: admin +echo Password: admin@123456 +echo. +pause From 9914095629f0cce9b68a305d9f8b1a316f30da00 Mon Sep 17 00:00:00 2001 From: Dhriti-5 Date: Fri, 15 May 2026 09:33:22 +0530 Subject: [PATCH 07/14] Update settings and requirements --- ClassLens_DB/ClassLens_DB/settings.py | 2 +- ClassLens_DB/Home/management/__init__.py | 0 .../Home/management/commands/__init__.py | 0 ClassLens_DB/requirements.txt | Bin 6126 -> 6160 bytes add_teacher_data.py | 53 ++++++++++++++++++ 5 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 ClassLens_DB/Home/management/__init__.py create mode 100644 ClassLens_DB/Home/management/commands/__init__.py create mode 100644 add_teacher_data.py diff --git a/ClassLens_DB/ClassLens_DB/settings.py b/ClassLens_DB/ClassLens_DB/settings.py index 6d4e58e..d934403 100644 --- a/ClassLens_DB/ClassLens_DB/settings.py +++ b/ClassLens_DB/ClassLens_DB/settings.py @@ -26,7 +26,7 @@ # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-x3zih9=91am0f(gkv&16y+n%7i1b91e-^mh&v*_r=_kz@y7t04" +SECRET_KEY = env("SECRET_KEY") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True diff --git a/ClassLens_DB/Home/management/__init__.py b/ClassLens_DB/Home/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ClassLens_DB/Home/management/commands/__init__.py b/ClassLens_DB/Home/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ClassLens_DB/requirements.txt b/ClassLens_DB/requirements.txt index 4ea7e0371eb36d0906bfe9dd7f37dacfd169d75d..5a299bf066884bba4933b63a9aaf44e8beeea509 100644 GIT binary patch delta 29 kcmaE-Kfz#wk~nW7LncEBLlHwNLoq|~ Date: Tue, 19 May 2026 18:31:50 +0530 Subject: [PATCH 08/14] Backend attendance processing and API updates --- .gitignore | 23 +- ClassLens_DB/ClassLens_DB/celery.py | 11 +- ClassLens_DB/ClassLens_DB/settings.py | 15 +- ClassLens_DB/DatabaseAdminApp/models.py | 101 +-- ClassLens_DB/DatabaseAdminApp/serializers.py | 30 +- ClassLens_DB/DatabaseAdminApp/urls.py | 16 +- ClassLens_DB/DatabaseAdminApp/views.py | 608 ++++++++++++------- ClassLens_DB/Home/models.py | 28 +- ClassLens_DB/Home/tasks.py | 17 +- ClassLens_DB/Home/urls.py | 66 +- ClassLens_DB/Home/views.py | 291 +++++++-- FRONTEND_CHANGES.md | 328 ---------- FRONTEND_CONTEXT.md | 452 -------------- test_sync_endpoint.py | 49 -- 14 files changed, 758 insertions(+), 1277 deletions(-) delete mode 100644 FRONTEND_CHANGES.md delete mode 100644 FRONTEND_CONTEXT.md delete mode 100644 test_sync_endpoint.py diff --git a/.gitignore b/.gitignore index 79452bd..1db6aaa 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,25 @@ gfpgan # Firebase credentials (NEVER commit these!) firebase-service-account.json -**/firebase-service-account.json \ No newline at end of file +**/firebase-service-account.json + + +# Markdown docs except README +*.md +!README.md + +# Local test/debug files +test_sync_endpoint.py + +# Local schema/docs +New_schema + +# Python virtual env +.venv/ + +# Python cache +__pycache__/ +*.pyc + +# Environment files +.env \ No newline at end of file diff --git a/ClassLens_DB/ClassLens_DB/celery.py b/ClassLens_DB/ClassLens_DB/celery.py index b6bf0e6..a37f1b1 100644 --- a/ClassLens_DB/ClassLens_DB/celery.py +++ b/ClassLens_DB/ClassLens_DB/celery.py @@ -2,6 +2,7 @@ from celery import Celery import environ #type:ignore from pathlib import Path #type:ignore +from urllib.parse import quote_plus BASE_DIR = Path(__file__).resolve().parent.parent @@ -11,11 +12,19 @@ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ClassLens_DB.settings') +# Build database result backend URL with proper password encoding +db_user = env("DB_USER") +db_password = quote_plus(env("DB_PASSWORD")) +db_host = env("DB_HOST") +db_port = env("DB_PORT") +db_name = env("DB_NAME") +db_result_backend = f'db+postgresql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}' + app = Celery('ClassLens_DB') app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks() app.conf.update( broker_url=rabbitmq_url, - result_backend='rpc://', + result_backend=db_result_backend, broker_connection_retry_on_startup=True, ) \ No newline at end of file diff --git a/ClassLens_DB/ClassLens_DB/settings.py b/ClassLens_DB/ClassLens_DB/settings.py index 83e9eb3..28fe101 100644 --- a/ClassLens_DB/ClassLens_DB/settings.py +++ b/ClassLens_DB/ClassLens_DB/settings.py @@ -13,6 +13,7 @@ from pathlib import Path import environ import os +from urllib.parse import quote_plus BASE_DIR = Path(__file__).resolve().parent.parent @@ -32,10 +33,13 @@ DEBUG = True ALLOWED_HOSTS = [ + '192.168.1.8', + '10.0.2.2', '14.139.121.110', 'localhost', '127.0.0.1', - '172.25.13.31' + '172.25.13.31', + '10.0.3.2', ] @@ -161,7 +165,13 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" CELERY_BROKER_URL = env('RABBITMQ_URL') -CELERY_RESULT_BACKEND = 'rpc://' +CELERY_RESULT_BACKEND = env('CELERY_RESULT_BACKEND', default='db+postgresql://{0}:{1}@{2}:{3}/{4}'.format( + env("DB_USER"), + quote_plus(env("DB_PASSWORD")), + env("DB_HOST"), + env("DB_PORT"), + env("DB_NAME") +)) CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json' @@ -183,6 +193,7 @@ # Django REST Framework Configuration REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'Home.authentication.CustomAdminAuthentication', 'rest_framework_simplejwt.authentication.JWTAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( diff --git a/ClassLens_DB/DatabaseAdminApp/models.py b/ClassLens_DB/DatabaseAdminApp/models.py index 3ea46b7..4f3712d 100644 --- a/ClassLens_DB/DatabaseAdminApp/models.py +++ b/ClassLens_DB/DatabaseAdminApp/models.py @@ -2,109 +2,36 @@ class APIEnrollment(models.Model): - """Simplified mirror of enrollment data from MSUIS API - attendance-only focus.""" - prn = models.BigIntegerField(db_index=True) + """Staging table for enrollment data - matches New_schema exactly.""" + prn = models.BigIntegerField() subject_code = models.CharField(max_length=100) - department_name = models.CharField(max_length=200) - program_name = models.CharField(max_length=200) + division = models.CharField(max_length=20) year = models.IntegerField() - semester = models.IntegerField() - division = models.CharField(max_length=20) # A, B, C, etc. - raw_payload = models.JSONField(default=dict) - synced_at = models.DateTimeField(auto_now=True) class Meta: - unique_together = ('prn', 'subject_code', 'division', 'semester') + unique_together = ('prn', 'subject_code', 'division', 'year') def __str__(self): return f"PRN {self.prn} - {self.subject_code} Div {self.division}" -class APIFaculty(models.Model): - """Mirror of faculty data received from MSUIS API.""" - msuis_id = models.BigIntegerField(primary_key=True) - name = models.TextField(null=True, blank=True) - is_active = models.BooleanField(null=True, blank=True) - is_deleted = models.BooleanField(null=True, blank=True) - raw_payload = models.JSONField(default=dict) - synced_at = models.DateTimeField(auto_now=True) - - def __str__(self): - return f"{self.msuis_id} - {self.name or 'Faculty'}" - - -class APIStudent(models.Model): - """Mirror of MstStudent API payloads.""" - prn = models.BigIntegerField(primary_key=True) - first_name = models.CharField(max_length=100, null=True, blank=True) - middle_name = models.CharField(max_length=100, null=True, blank=True) - last_name = models.CharField(max_length=100, null=True, blank=True) - email_id = models.CharField(max_length=150, null=True, blank=True) - mobile_no = models.CharField(max_length=50, null=True, blank=True) - faculty_id = models.BigIntegerField(null=True, blank=True) - programme_name = models.CharField(max_length=200, null=True, blank=True) - admission_year = models.IntegerField(null=True, blank=True) - passing_year = models.IntegerField(null=True, blank=True) - raw_payload = models.JSONField(default=dict) - synced_at = models.DateTimeField(auto_now=True) - - def __str__(self): - return str(self.prn) - - class APIPaper(models.Model): - """Mirror of MstPaper API payloads.""" + """Staging table for paper data - mirrors MSUIS API payloads. Matches New_schema exactly.""" msuis_id = models.BigIntegerField(primary_key=True) - subject_id = models.BigIntegerField(null=True, blank=True) - paper_name = models.CharField(max_length=1000) + paper_name = models.CharField(max_length=500) paper_code = models.CharField(max_length=100) - is_credit = models.BooleanField(null=True, blank=True) - max_marks = models.IntegerField(null=True, blank=True) - min_marks = models.IntegerField(null=True, blank=True) - credits = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) - is_active = models.BooleanField(null=True, blank=True) - is_deleted = models.BooleanField(null=True, blank=True) - raw_payload = models.JSONField(default=dict) - synced_at = models.DateTimeField(auto_now=True) + raw_payload = models.JSONField() def __str__(self): return f"{self.paper_code} - {self.paper_name}" -class APIStudentAcademicInformation(models.Model): - """Mirror of IncStudentAcademicInformation API payloads.""" - msuis_id = models.BigIntegerField(primary_key=True) - prn = models.BigIntegerField(db_index=True) - student_admission_id = models.BigIntegerField(null=True, blank=True) - programme_instance_part_term_id = models.BigIntegerField(null=True, blank=True) - programme_id = models.BigIntegerField(null=True, blank=True) - specialisation_id = models.BigIntegerField(null=True, blank=True) - academic_year_id = models.BigIntegerField(null=True, blank=True) - institute_id = models.BigIntegerField(null=True, blank=True) - faculty_id = models.BigIntegerField(null=True, blank=True) - part_term_status = models.CharField(max_length=100, null=True, blank=True) - raw_payload = models.JSONField(default=dict) - synced_at = models.DateTimeField(auto_now=True) - - def __str__(self): - return f"{self.msuis_id} - {self.prn}" - - -class APIStudentPartTermPaperMap(models.Model): - """Mirror of IncStudentPartTermPaperMap API payloads. (Legacy - use APIEnrollment instead)""" - msuis_id = models.BigIntegerField(primary_key=True) - prn = models.BigIntegerField(null=True, blank=True, db_index=True) - student_academic_information_id = models.BigIntegerField(null=True, blank=True) - programme_instance_part_term_id = models.BigIntegerField(null=True, blank=True) - paper_id = models.BigIntegerField(null=True, blank=True) - mst_paper_id = models.BigIntegerField(null=True, blank=True) - obtained_marks = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True) - obtained_grade = models.CharField(max_length=10, null=True, blank=True) - paper_status = models.CharField(max_length=100, null=True, blank=True) - part_term_status = models.CharField(max_length=100, null=True, blank=True) - division = models.CharField(max_length=20, null=True, blank=True) - raw_payload = models.JSONField(default=dict) - synced_at = models.DateTimeField(auto_now=True) +class APIStudent(models.Model): + """Staging table for student data - mirrors MSUIS API payloads. Matches New_schema exactly.""" + prn = models.BigIntegerField(primary_key=True) + email_id = models.CharField(max_length=255, null=True, blank=True) + raw_payload = models.JSONField() + full_name = models.CharField(max_length=255, null=True, blank=True) def __str__(self): - return f"{self.msuis_id} - {self.prn}" + return str(self.prn) diff --git a/ClassLens_DB/DatabaseAdminApp/serializers.py b/ClassLens_DB/DatabaseAdminApp/serializers.py index a6d82d5..92ddd9b 100644 --- a/ClassLens_DB/DatabaseAdminApp/serializers.py +++ b/ClassLens_DB/DatabaseAdminApp/serializers.py @@ -3,14 +3,12 @@ from rest_framework import serializers from Home.models import ( Department, Teacher, Student, Subject, SubjectFromDept, - StudentEnrollment, TeacherSubject, AdminUser + StudentEnrollment, TeacherSubject, AdminUser, Division ) from .models import ( - APIFaculty, APIStudent, APIPaper, - APIStudentAcademicInformation, - APIStudentPartTermPaperMap, + APIEnrollment, ) class DepartmentSerializer(serializers.ModelSerializer): @@ -28,11 +26,12 @@ class Meta: class StudentSerializer(serializers.ModelSerializer): department_name = serializers.CharField(source='department.name', read_only=True) + division_name = serializers.CharField(source='division.name', read_only=True) class Meta: model = Student fields = ['id', 'prn', 'name', 'email', 'password_hash', 'year', 'department', - 'department_name', 'face_embedding', 'notification_token'] + 'department_name', 'division', 'division_name', 'face_embedding', 'notification_token'] extra_kwargs = {'password_hash': {'write_only': True}, 'face_embedding': {'write_only': True}} class SubjectSerializer(serializers.ModelSerializer): @@ -63,10 +62,11 @@ class Meta: class TeacherSubjectSerializer(serializers.ModelSerializer): teacher_name = serializers.CharField(source='teacher_id.name', read_only=True) subject_name = serializers.CharField(source='subject.name', read_only=True) + division_name = serializers.CharField(source='division.name', read_only=True) class Meta: model = TeacherSubject - fields = ['id', 'teacher_id', 'teacher_name', 'subject', 'subject_name'] + fields = ['id', 'teacher_id', 'teacher_name', 'subject', 'subject_name', 'division', 'division_name'] # class AdminUserSerializer(serializers.ModelSerializer): # password = serializers.CharField(write_only=True) @@ -103,12 +103,6 @@ def create(self, validated_data): return user -class APIFacultySerializer(serializers.ModelSerializer): - class Meta: - model = APIFaculty - fields = "__all__" - - class APIStudentSerializer(serializers.ModelSerializer): class Meta: model = APIStudent @@ -121,15 +115,9 @@ class Meta: fields = "__all__" -class APIStudentAcademicInformationSerializer(serializers.ModelSerializer): - class Meta: - model = APIStudentAcademicInformation - fields = "__all__" - - -class APIStudentPartTermPaperMapSerializer(serializers.ModelSerializer): +class APIEnrollmentSerializer(serializers.ModelSerializer): class Meta: - model = APIStudentPartTermPaperMap + model = APIEnrollment fields = "__all__" @@ -137,4 +125,4 @@ class DivisionSerializer(serializers.ModelSerializer): class Meta: from Home.models import Division model = Division - fields = ['id', 'department', 'program_name', 'year', 'semester', 'name'] \ No newline at end of file + fields = ['id', 'department', 'year', 'name'] \ No newline at end of file diff --git a/ClassLens_DB/DatabaseAdminApp/urls.py b/ClassLens_DB/DatabaseAdminApp/urls.py index c29b166..75e7ebc 100644 --- a/ClassLens_DB/DatabaseAdminApp/urls.py +++ b/ClassLens_DB/DatabaseAdminApp/urls.py @@ -14,12 +14,10 @@ admin_login, get_dashboard_stats, AdminUserViewSet, - APIFacultyViewSet, APIStudentViewSet, APIPaperViewSet, - APIStudentAcademicInformationViewSet, - APIStudentPartTermPaperMapViewSet, sync_msuis_payload, + sync_staging_to_core, DivisionViewSet, ) @@ -35,19 +33,8 @@ r"student-enrollments", StudentEnrollmentViewSet, basename="student-enrollment" ) router.register(r"admin-users", AdminUserViewSet, basename="admin-user") -router.register(r"api-faculties", APIFacultyViewSet, basename="api-faculty") router.register(r"api-students", APIStudentViewSet, basename="api-student") router.register(r"api-papers", APIPaperViewSet, basename="api-paper") -router.register( - r"api-student-academic-info", - APIStudentAcademicInformationViewSet, - basename="api-student-academic-info", -) -router.register( - r"api-student-part-term-paper-map", - APIStudentPartTermPaperMapViewSet, - basename="api-student-part-term-paper-map", -) router.register(r"divisions", DivisionViewSet, basename="division") urlpatterns = [ @@ -55,6 +42,7 @@ path("admin/login/", admin_login, name="admin-login"), path("admin/token/refresh/", TokenRefreshView.as_view(), name="token-refresh"), path("admin/sync/msuis/", sync_msuis_payload, name="sync-msuis-payload"), + path("admin/sync/staging/", sync_staging_to_core, name="sync-staging-to-core"), # CRUD APIs path("admin/stats/", get_dashboard_stats, name="admin-stats"), path("admin/", include(router.urls)), diff --git a/ClassLens_DB/DatabaseAdminApp/views.py b/ClassLens_DB/DatabaseAdminApp/views.py index 60146f5..7999292 100644 --- a/ClassLens_DB/DatabaseAdminApp/views.py +++ b/ClassLens_DB/DatabaseAdminApp/views.py @@ -16,23 +16,22 @@ StudentEnrollment, TeacherSubject, AdminUser, StudentAttendancePercentage, Division ) from .models import ( - APIFaculty, APIStudent, APIPaper, - APIStudentAcademicInformation, - APIStudentPartTermPaperMap, + APIEnrollment, ) from .serializers import ( DepartmentSerializer, TeacherSerializer, StudentSerializer, SubjectSerializer, SubjectFromDeptSerializer, StudentEnrollmentSerializer, TeacherSubjectSerializer, AdminUserSerializer, - APIFacultySerializer, APIStudentSerializer, APIPaperSerializer, - APIStudentAcademicInformationSerializer, APIStudentPartTermPaperMapSerializer, + APIStudentSerializer, APIPaperSerializer, DivisionSerializer, ) from django.db import transaction +from django.db.models import Max from rest_framework.permissions import BasePermission +import re class IsSuperUser(BasePermission): """ @@ -46,6 +45,78 @@ def has_permission(self, request, view): and getattr(request.user, "is_superuser", False) ) + +def _normalize_department_label(value): + if value is None: + return "" + normalized = str(value).strip().lower() + normalized = normalized.replace("&", "and") + normalized = re.sub(r"[().,/_-]", " ", normalized) + normalized = re.sub(r"\s+", " ", normalized) + return normalized.strip() + + +def _resolve_department(department_name): + normalized_name = _normalize_department_label(department_name) + if not normalized_name: + return None + + exact_match = Department.objects.filter(name__iexact=str(department_name).strip()).first() + if exact_match is not None: + return exact_match + + alias_map = { + "computer science and engineering": [ + "Bachelor in Computer Science and Engineering (B.E)", + "Computer Science and Engineering", + "CSE", + ], + "cse": [ + "Bachelor in Computer Science and Engineering (B.E)", + "Computer Science and Engineering", + "CSE", + ], + } + + for alias in alias_map.get(normalized_name, []): + department = Department.objects.filter(name__iexact=alias).first() + if department is not None: + return department + + candidate = Department.objects.all() + for department in candidate: + department_label = _normalize_department_label(department.name) + if normalized_name == department_label: + return department + if normalized_name in department_label or department_label in normalized_name: + return department + + tokens = [token for token in normalized_name.split(" ") if len(token) > 2] + if tokens: + query = candidate + for token in tokens: + query = query.filter(name__icontains=token) + department = query.first() + if department is not None: + return department + + return None + + +def _normalize_password_value(value, fallback): + if value is None: + return fallback + if pd is not None: + try: + if pd.isna(value): + return fallback + except Exception: + pass + if isinstance(value, str): + password = value.strip() + return password or fallback + return str(value) + @api_view(['POST']) @permission_classes([AllowAny]) def admin_login(request): @@ -161,9 +232,9 @@ def bulk_upload(self, request): try: department = Department.objects.get(name=row['department_name']) teacher_data = { - 'name': row['name'], - 'email': row['email'], - 'password_hash': make_password(row.get('password', 'default123')), + 'name': name, + 'email': email, + 'password_hash': make_password(_normalize_password_value(row.get('password'), 'default123')), 'department': department } Teacher.objects.create(**teacher_data) @@ -225,28 +296,59 @@ def bulk_upload(self, request): df = pd.read_excel(file) else: return Response({'error': 'Invalid file format'}, status=status.HTTP_400_BAD_REQUEST) + + df.columns = [str(column).strip() for column in df.columns] + + required_columns = {'prn', 'name', 'email', 'year', 'department_name'} + missing_columns = required_columns.difference(df.columns) + if missing_columns: + return Response( + {'error': f"Missing required columns: {', '.join(sorted(missing_columns))}"}, + status=status.HTTP_400_BAD_REQUEST, + ) created_count = 0 + updated_count = 0 errors = [] for index, row in df.iterrows(): try: - department = Department.objects.get(name=row['department_name']) - student_data = { - 'prn': int(row['prn']), - 'name': row['name'], - 'email': row['email'], - 'password_hash': make_password(row.get('password', 'student123')), - 'year': int(row['year']), - 'department': department + prn = int(row['prn']) + full_name = str(row['name']).strip() + email = str(row['email']).strip() + year = int(row['year']) + department_name = str(row['department_name']).strip() + if not department_name: + raise ValueError('department_name is required') + + department = _resolve_department(department_name) + + staging_defaults = { + 'full_name': full_name, + 'email_id': email, + 'raw_payload': { + 'department_name': department_name, + 'year': year, + 'name': full_name, + }, } - Student.objects.create(**student_data) - created_count += 1 + + _, created = APIStudent.objects.update_or_create( + prn=prn, + defaults=staging_defaults, + ) + if created: + created_count += 1 + else: + updated_count += 1 except Exception as e: errors.append(f"Row {index + 1}: {str(e)}") return Response({ - 'message': f'Successfully created {created_count} students', + 'message': f'Successfully processed {created_count + updated_count} staging students', + 'created_count': created_count, + 'updated_count': updated_count, + 'skipped_count': len(errors), 'errors': errors }, status=status.HTTP_201_CREATED) @@ -297,20 +399,45 @@ def bulk_upload(self, request): return Response({'error': 'Invalid file format'}, status=status.HTTP_400_BAD_REQUEST) created_count = 0 + updated_count = 0 errors = [] - + + current_max = APIPaper.objects.aggregate(max_id=Max("msuis_id")).get("max_id") or 0 + next_id = int(current_max) + 1 + for index, row in df.iterrows(): try: - Subject.objects.create( - code=row['code'], - name=row['name'] - ) - created_count += 1 + paper_code = str(row['code']).strip() + paper_name = str(row['name']).strip() + if not paper_code: + raise ValueError("code is required") + + existing = APIPaper.objects.filter(paper_code=paper_code).first() + if existing: + existing.paper_name = paper_name or existing.paper_name + existing.raw_payload = { + "code": paper_code, + "name": paper_name, + } + existing.save(update_fields=["paper_name", "raw_payload"]) + updated_count += 1 + else: + APIPaper.objects.create( + msuis_id=next_id, + subject_id=None, + paper_name=paper_name or paper_code, + paper_code=paper_code, + raw_payload={"code": paper_code, "name": paper_name}, + ) + next_id += 1 + created_count += 1 except Exception as e: errors.append(f"Row {index + 1}: {str(e)}") return Response({ - 'message': f'Successfully created {created_count} subjects', + 'message': f'Successfully processed {created_count + updated_count} staging subjects', + 'created_count': created_count, + 'updated_count': updated_count, 'errors': errors }, status=status.HTTP_201_CREATED) @@ -409,7 +536,9 @@ def download_template(self, request): """Download Excel template for bulk student enrollment upload""" data = { 'student_prn': [2021001, 2021001, 2021002], - 'subject_code': ['CS101', 'CS102', 'EE201'] + 'subject_code': ['CS101', 'CS102', 'EE201'], + 'year': [2, 2, 3], + 'division': ['A', 'A', 'B'], } df = pd.DataFrame(data) @@ -419,10 +548,11 @@ def download_template(self, request): # Add instructions instructions = pd.DataFrame({ 'Instructions': [ - '1. student_prn must exist in students table', - '2. subject_code must exist in subjects table', - '3. Each student-subject combination must be unique', - '4. One student can enroll in multiple subjects' + '1. student_prn must match staging students PRN', + '2. subject_code must match staging subjects code', + '3. year and division are required', + '4. Each student-subject-division-year combination must be unique', + '5. One student can enroll in multiple subjects' ] }) instructions.to_excel(writer, index=False, sheet_name='Instructions') @@ -439,7 +569,7 @@ def download_template(self, request): def bulk_upload(self, request): """ Bulk upload student enrollments from CSV/Excel - Expected columns: student_prn, subject_code + Expected columns: student_prn, subject_code, year, division """ file = request.FILES.get('file') if not file: @@ -453,28 +583,55 @@ def bulk_upload(self, request): else: return Response({'error': 'Invalid file format'}, status=status.HTTP_400_BAD_REQUEST) + df.columns = [str(column).strip() for column in df.columns] + + required_columns = { + 'student_prn', + 'subject_code', + 'year', + 'division', + } + missing_columns = required_columns.difference(df.columns) + if missing_columns: + return Response( + {'error': f"Missing required columns: {', '.join(sorted(missing_columns))}"}, + status=status.HTTP_400_BAD_REQUEST, + ) + created_count = 0 + updated_count = 0 errors = [] for index, row in df.iterrows(): try: - subject = Subject.objects.get(code=row['subject_code']) - StudentEnrollment.objects.create( - student_prn=int(row['student_prn']), - subject=subject + prn = int(row['student_prn']) + subject_code = str(row['subject_code']).strip() + year = int(row['year']) + division = str(row['division']).strip() + + if not subject_code: + raise ValueError('subject_code is required') + if not division: + raise ValueError('division is required') + + _, created = APIEnrollment.objects.update_or_create( + prn=prn, + subject_code=subject_code, + division=division, + year=year, + defaults={}, ) - StudentAttendancePercentage.objects.create( - student=Student.objects.get(prn=int(row['student_prn'])), - subject=subject, - present_count=0, - attendancePercentage=0.0 - ) - created_count += 1 + if created: + created_count += 1 + else: + updated_count += 1 except Exception as e: errors.append(f"Row {index + 1}: {str(e)}") return Response({ - 'message': f'Successfully created {created_count} enrollments', + 'message': f'Successfully processed {created_count + updated_count} staging enrollments', + 'created_count': created_count, + 'updated_count': updated_count, 'errors': errors }, status=status.HTTP_201_CREATED) @@ -482,12 +639,6 @@ def bulk_upload(self, request): return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) -class APIFacultyViewSet(viewsets.ModelViewSet): - queryset = APIFaculty.objects.all().order_by("msuis_id") - serializer_class = APIFacultySerializer - permission_classes = [IsAuthenticated] - - class APIStudentViewSet(viewsets.ModelViewSet): queryset = APIStudent.objects.all().order_by("prn") serializer_class = APIStudentSerializer @@ -500,18 +651,6 @@ class APIPaperViewSet(viewsets.ModelViewSet): permission_classes = [IsAuthenticated] -class APIStudentAcademicInformationViewSet(viewsets.ModelViewSet): - queryset = APIStudentAcademicInformation.objects.all().order_by("msuis_id") - serializer_class = APIStudentAcademicInformationSerializer - permission_classes = [IsAuthenticated] - - -class APIStudentPartTermPaperMapViewSet(viewsets.ModelViewSet): - queryset = APIStudentPartTermPaperMap.objects.all().order_by("msuis_id") - serializer_class = APIStudentPartTermPaperMapSerializer - permission_classes = [IsAuthenticated] - - class DivisionViewSet(viewsets.ModelViewSet): queryset = Division.objects.all().select_related('department') serializer_class = DivisionSerializer @@ -539,138 +678,45 @@ def _to_bool(value): @api_view(["POST"]) -@permission_classes([IsAuthenticated]) +@permission_classes([AllowAny]) def sync_msuis_payload(request): """ - Single entrypoint for API-sourced data ingestion through admin app. - This keeps external-source writes centralized for future DB merge workflows. + Sync student and paper data to staging tables for later promotion to core. """ payload = request.data or {} - apply_to_core = bool(payload.get("apply_to_core", True)) - faculties = payload.get("faculties", []) students = payload.get("students", []) papers = payload.get("papers", []) - academic_records = payload.get("student_academic_information", []) - part_term_maps = payload.get("student_part_term_paper_maps", []) counters = { - "faculties_synced": 0, "students_synced": 0, "papers_synced": 0, - "academic_records_synced": 0, - "part_term_maps_synced": 0, - "core_departments_upserted": 0, - "core_students_upserted": 0, - "core_subjects_upserted": 0, - "core_enrollments_upserted": 0, - "core_divisions_upserted": 0, } - # Use the latest academic snapshot to derive student year/faculty defaults. - latest_academic_by_prn = {} - with transaction.atomic(): - for row in faculties: - msuis_id = row.get("Id") or row.get("id") - if msuis_id is None: - continue - - name = row.get("FacultyName") or row.get("Name") or row.get("name") - APIFaculty.objects.update_or_create( - msuis_id=msuis_id, - defaults={ - "name": name, - "is_active": _to_bool(row.get("IsActive")), - "is_deleted": _to_bool(row.get("IsDeleted")), - "raw_payload": row, - }, - ) - counters["faculties_synced"] += 1 - - if apply_to_core and name: - Department.objects.update_or_create( - id=msuis_id, - defaults={"name": name}, - ) - counters["core_departments_upserted"] += 1 - - for row in academic_records: - msuis_id = row.get("Id") or row.get("id") - if msuis_id is None: - continue - - prn = row.get("PRN") or row.get("Prn") or row.get("prn") - APIStudentAcademicInformation.objects.update_or_create( - msuis_id=msuis_id, - defaults={ - "prn": prn, - "student_admission_id": row.get("StudentAdmissionId"), - "programme_instance_part_term_id": row.get("ProgrammeInstancePartTermId"), - "programme_id": row.get("ProgrammeId"), - "specialisation_id": row.get("SpecialisationId"), - "academic_year_id": row.get("AcademicYearId"), - "institute_id": row.get("InstituteId"), - "faculty_id": row.get("FacultyId"), - "part_term_status": row.get("PartTermStatus"), - "raw_payload": row, - }, - ) - counters["academic_records_synced"] += 1 - - if prn is not None: - latest_academic_by_prn[prn] = row - for row in students: prn = row.get("PRN") or row.get("Prn") or row.get("prn") if prn is None: continue + # Build full_name from first/middle/last name components + first_name = row.get("FirstName") or "" + middle_name = row.get("MiddleName") or "" + last_name = row.get("LastName") or "" + full_name = " ".join([n.strip() for n in [first_name, middle_name, last_name] if n.strip()]) + if not full_name: + full_name = row.get("NameAsPerMarksheet") or f"PRN {prn}" + APIStudent.objects.update_or_create( prn=prn, defaults={ - "first_name": row.get("FirstName"), - "middle_name": row.get("MiddleName"), - "last_name": row.get("LastName"), + "full_name": full_name, "email_id": row.get("EmailId"), - "mobile_no": row.get("MobileNo"), - "faculty_id": row.get("FacultyId"), - "programme_name": row.get("ProgrammeName"), - "admission_year": row.get("AdmissionYear"), - "passing_year": row.get("PassingYear"), "raw_payload": row, }, ) counters["students_synced"] += 1 - if apply_to_core: - academic = latest_academic_by_prn.get(prn, {}) - faculty_id = row.get("FacultyId") or academic.get("FacultyId") - if not faculty_id: - continue - - dept = Department.objects.filter(id=faculty_id).first() - if dept is None: - dept = Department.objects.create( - id=faculty_id, - name=f"Faculty-{faculty_id}", - ) - counters["core_departments_upserted"] += 1 - - # When exact year is unavailable from API, keep a stable fallback. - year = row.get("Year") or 1 - - Student.objects.update_or_create( - prn=prn, - defaults={ - "name": _full_name(row), - "email": row.get("EmailId") or f"{prn}@classlens.local", - "year": year, - "department": dept, - }, - ) - counters["core_students_upserted"] += 1 - for row in papers: msuis_id = row.get("Id") or row.get("id") if msuis_id is None: @@ -682,84 +728,192 @@ def sync_msuis_payload(request): APIPaper.objects.update_or_create( msuis_id=msuis_id, defaults={ - "subject_id": row.get("SubjectId"), "paper_name": paper_name, "paper_code": paper_code, - "is_credit": _to_bool(row.get("IsCredit")), - "max_marks": row.get("MaxMarks"), - "min_marks": row.get("MinMarks"), - "credits": row.get("Credits"), - "is_active": _to_bool(row.get("IsActive")), - "is_deleted": _to_bool(row.get("IsDeleted")), "raw_payload": row, }, ) counters["papers_synced"] += 1 - if apply_to_core: - Subject.objects.update_or_create( - id=msuis_id, - defaults={"code": paper_code, "name": paper_name}, - ) - counters["core_subjects_upserted"] += 1 + return Response( + { + "message": "MSUIS payload synced to staging tables", + "counts": counters, + }, + status=status.HTTP_200_OK, + ) - for row in part_term_maps: - msuis_id = row.get("Id") or row.get("id") - if msuis_id is None: + +@api_view(["POST"]) +@permission_classes([AllowAny]) +def sync_staging_to_core(request): + """ + Process staging data into live Home_* tables. + Reads DatabaseAdminApp_* tables and writes to Home_* only. + """ + counters = { + "core_students_upserted": 0, + "core_subjects_upserted": 0, + "core_enrollments_upserted": 0, + "core_divisions_upserted": 0, + "students_skipped": 0, + "enrollments_skipped": 0, + } + + def _department_from_payload(raw_payload): + if not raw_payload: + return None + for key in ("department_name", "Department", "department", "FacultyName"): + value = raw_payload.get(key) + if value: + return str(value).strip() + return None + + def _year_from_payload(raw_payload): + if not raw_payload: + return None + for key in ("year", "Year", "YearOfStudy"): + value = raw_payload.get(key) + if value is None: + continue + try: + return int(value) + except Exception: + return None + return None + + def _student_display_name(api_student): + # APIStudent now stores `full_name` per new_schema + if getattr(api_student, 'full_name', None): + return api_student.full_name + raw_payload = api_student.raw_payload or {} + return raw_payload.get("name") or raw_payload.get("NameAsPerMarksheet") or f"PRN {api_student.prn}" + + api_students = list(APIStudent.objects.all()) + api_papers = list(APIPaper.objects.all()) + api_enrollments = list(APIEnrollment.objects.all()) + + year_by_prn = {} + for enrollment in api_enrollments: + if enrollment.prn is None: + continue + try: + year_value = int(enrollment.year) + except Exception: + continue + current = year_by_prn.get(enrollment.prn) + if current is None or year_value > current: + year_by_prn[enrollment.prn] = year_value + + with transaction.atomic(): + for paper in api_papers: + paper_code = (paper.paper_code or "").strip() + if not paper_code: + continue + paper_name = (paper.paper_name or paper_code).strip() + Subject.objects.update_or_create( + code=paper_code, + defaults={"name": paper_name}, + ) + counters["core_subjects_upserted"] += 1 + + for api_student in api_students: + prn = api_student.prn + if prn is None: + counters["students_skipped"] += 1 continue - prn = row.get("PRN") or row.get("Prn") - paper_id = row.get("MstPaperId") or row.get("PaperId") + raw_payload = api_student.raw_payload or {} + department_name = _department_from_payload(raw_payload) + department = None + if department_name: + department = _resolve_department(department_name) + if department is None: + department, _ = Department.objects.get_or_create(name=department_name) - APIStudentPartTermPaperMap.objects.update_or_create( - msuis_id=msuis_id, + if department is None and getattr(api_student, 'faculty_id', None): + department = Department.objects.filter(id=api_student.faculty_id).first() + + if department is None: + counters["students_skipped"] += 1 + continue + + year_value = ( + year_by_prn.get(prn) + or _year_from_payload(raw_payload) + ) + if year_value is None: + year_value = 1 + + Student.objects.update_or_create( + prn=prn, defaults={ - "prn": prn, - "student_academic_information_id": row.get("StudentAcademicInformationId"), - "programme_instance_part_term_id": row.get("ProgrammeInstancePartTermId"), - "paper_id": row.get("PaperId"), - "mst_paper_id": row.get("MstPaperId"), - "obtained_marks": row.get("ObtainedMarks"), - "obtained_grade": row.get("ObtainedGrade"), - "paper_status": row.get("PaperStatus"), - "part_term_status": row.get("PartTermStatus"), - "division": row.get("Division"), - "raw_payload": row, + "name": _student_display_name(api_student), + "email": api_student.email_id or raw_payload.get("email") or f"{prn}@classlens.local", + "year": int(year_value), + "department": department, }, ) - counters["part_term_maps_synced"] += 1 - - if apply_to_core and prn and paper_id: - student = Student.objects.filter(prn=prn).first() - subject = Subject.objects.filter(id=paper_id).first() - if student and subject: - StudentEnrollment.objects.update_or_create( - student_prn=student.prn, - subject=subject, - ) - StudentAttendancePercentage.objects.get_or_create( - student=student, - subject=subject, - defaults={"present_count": 0, "attendancePercentage": 0.0}, - ) - counters["core_enrollments_upserted"] += 1 - - division_name = row.get("Division") - semester = row.get("Semester") - if division_name and semester: - division_obj, _ = Division.objects.get_or_create( - department=student.department, - program_name=(row.get("ProgrammeName") or "Program"), - year=student.year, - semester=int(semester), - name=str(division_name), - ) - counters["core_divisions_upserted"] += 1 + counters["core_students_upserted"] += 1 + + for enrollment in api_enrollments: + if enrollment.prn is None or not enrollment.subject_code: + counters["enrollments_skipped"] += 1 + continue + + student = Student.objects.filter(prn=enrollment.prn).first() + if student is None: + counters["enrollments_skipped"] += 1 + continue + + subject_code = enrollment.subject_code.strip() + subject, created = Subject.objects.get_or_create( + code=subject_code, + defaults={"name": subject_code} + ) + if created: + counters["core_subjects_upserted"] += 1 + + department = None + if enrollment.department_name: + department = _resolve_department(enrollment.department_name) + if department is None: + department, _ = Department.objects.get_or_create(name=enrollment.department_name) + if department is None: + department = student.department + + division_obj = None + if ( + department + and enrollment.division + and enrollment.year is not None + ): + division_obj, created = Division.objects.get_or_create( + department=department, + year=int(enrollment.year), + name=str(enrollment.division).strip(), + ) + if created: + counters["core_divisions_upserted"] += 1 + + if division_obj is not None and student.division_id != division_obj.id: + student.division = division_obj + student.save(update_fields=["division"]) + + StudentEnrollment.objects.update_or_create( + student_prn=student.prn, + subject=subject, + ) + StudentAttendancePercentage.objects.get_or_create( + student=student, + subject=subject, + defaults={"present_count": 0, "attendancePercentage": 0.0}, + ) + counters["core_enrollments_upserted"] += 1 return Response( { - "message": "MSUIS payload synced via admin app", - "apply_to_core": apply_to_core, + "message": "Staging data processed into core tables", "counts": counters, }, status=status.HTTP_200_OK, diff --git a/ClassLens_DB/Home/models.py b/ClassLens_DB/Home/models.py index 6215ba0..1c81276 100644 --- a/ClassLens_DB/Home/models.py +++ b/ClassLens_DB/Home/models.py @@ -1,5 +1,6 @@ from django.db import models from django.contrib.auth.hashers import make_password, check_password +from pgvector.django import VectorField class Department(models.Model): name = models.TextField(unique=True, null=False) @@ -28,7 +29,13 @@ class Student(models.Model): Department, on_delete=models.CASCADE, ) - face_embedding = models.JSONField(null=True, blank=True) + division = models.ForeignKey( + 'Division', + on_delete=models.SET_NULL, + null=True, + blank=True, + ) + face_embedding = VectorField(dimensions=512, null=True, blank=True) notification_token = models.TextField(null=True, blank=True) def __str__(self): return f"{self.name} ({self.prn})" @@ -59,47 +66,44 @@ class Division(models.Model): Local teaching division metadata, e.g. BE CSE 4th year Sem 8 Division A. """ department = models.ForeignKey(Department, on_delete=models.CASCADE) - program_name = models.TextField(null=False, default="") year = models.IntegerField(null=False) - semester = models.IntegerField(null=False) name = models.CharField(max_length=20, null=False) class Meta: - unique_together = ("department", "program_name", "year", "semester", "name") + unique_together = ("department", "year", "name") def __str__(self): return ( - f"{self.program_name} {self.year}th year {self.semester}th Sem " - f"Division {self.name}" + f"{self.year}th year Division {self.name}" ) class StudentEnrollment(models.Model): student_prn = models.BigIntegerField(null=False) subject = models.ForeignKey(Subject, on_delete=models.CASCADE) - division = models.ForeignKey(Division, on_delete=models.SET_NULL, null=True, blank=True) class Meta: - unique_together = ('student_prn', 'subject', 'division') + unique_together = ('student_prn', 'subject') def __str__(self): - return f"{self.student_prn} enrolled in {self.subject} Division {self.division.name if self.division else 'N/A'}" + return f"{self.student_prn} enrolled in {self.subject}" class TeacherSubject(models.Model): teacher_id = models.ForeignKey(Teacher, on_delete=models.CASCADE) subject = models.ForeignKey(Subject, on_delete=models.CASCADE) + division = models.ForeignKey(Division, on_delete=models.SET_NULL, null=True, blank=True) class Meta: - unique_together = ('teacher_id', 'subject') + unique_together = ('teacher_id', 'subject', 'division') def __str__(self): - return f"{self.teacher_id.name} teaches {self.subject.name}" + division_name = self.division.name if self.division else 'All Divisions' + return f"{self.teacher_id.name} teaches {self.subject.name} ({division_name})" class ClassSession(models.Model): department = models.ForeignKey(Department, on_delete=models.CASCADE) year = models.IntegerField(null=False) subject = models.ForeignKey(Subject, on_delete=models.CASCADE) teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE) - division = models.ForeignKey(Division, on_delete=models.SET_NULL, null=True, blank=True) class_datetime = models.DateTimeField(null=False) def __str__(self): diff --git a/ClassLens_DB/Home/tasks.py b/ClassLens_DB/Home/tasks.py index 4193f45..c03a9b5 100644 --- a/ClassLens_DB/Home/tasks.py +++ b/ClassLens_DB/Home/tasks.py @@ -149,18 +149,26 @@ def send_attendance_notifications(student_records, subject_name, class_datetime) print(f"Failed to send notification to {student.name}: {e}") @shared_task -def evaluate_attendance(total_sessions,class_session_id:int,scheme, host): +def evaluate_attendance(total_sessions, class_session_id: int, scheme, host, division_id=None): session = ClassSession.objects.get(id=class_session_id) images=session.photos.all() image_urls=[] total_faces=0 - enrolled_prns = list(StudentEnrollment.objects.filter( + enrolled_prns_qs = StudentEnrollment.objects.filter( subject=session.subject - ).values_list('student_prn', flat=True)) + ).values_list('student_prn', flat=True) - all_students_qs = Student.objects.filter(prn__in=enrolled_prns) + all_students_qs = Student.objects.filter( + prn__in=enrolled_prns_qs, + year=session.year, + department=session.department, + ) + if division_id: + all_students_qs = all_students_qs.filter(division_id=division_id) + + enrolled_prns = list(all_students_qs.values_list('prn', flat=True)) student_obj_map = {s.prn: s for s in all_students_qs} @@ -306,6 +314,7 @@ def evaluate_attendance(total_sessions,class_session_id:int,scheme, host): "num_faces": total_faces, "image_url": image_urls[0] if image_urls else None, "class_session_id": class_session_id, + "division_id": division_id, "present_count": len(present_student_prns), "absent_count": len(enrolled_prns) - len(present_student_prns), "subject": session.subject.name diff --git a/ClassLens_DB/Home/urls.py b/ClassLens_DB/Home/urls.py index 720e04b..d8845d5 100644 --- a/ClassLens_DB/Home/urls.py +++ b/ClassLens_DB/Home/urls.py @@ -1,33 +1,51 @@ -from django.urls import path +from django.urls import path, re_path from django.urls import include -from Home.views import getDepartments,registerNewStudent,mark_attendance,teacher_profile,registerNewTeacher,validateStudent,validateTeacher,send_otp,verify_otp,set_password,get_subject_details,verify_email, verify_prn, get_student_attendance,attendance_status,teacher_subjects, get_present_absent_list,change_attendance,get_student_dashboard,update_notification_token,remove_notification_token +from Home.views import getDepartments,mark_attendance,teacher_profile,registerNewTeacher,validateStudent,validateTeacher,send_otp,verify_otp,set_password,get_subject_details,verify_email, verify_prn, get_student_attendance,attendance_status,teacher_subjects, get_present_absent_list,change_attendance,get_student_dashboard,update_notification_token,remove_notification_token, register_student, get_student_subject_attendance from django.conf import settings from django.conf.urls.static import static urlpatterns = [ - path("getDepartments/", getDepartments, name="get_departments"), - path("registerNewStudent", registerNewStudent, name="register_new_student"), - path("registerNewTeacher", registerNewTeacher, name="register_new_teacher"), - path("validateStudent", validateStudent, name="validate_student"), - path("validateTeacher", validateTeacher, name="validate_teacher"), - path("sendOtp", send_otp, name="send_otp"), - path("verifyOtp", verify_otp, name="verify_otp"), - path("setPassword", set_password, name="set_password"), - path("getSubjectDetails", get_subject_details, name="get_subject_details"), - path("verifyEmail", verify_email, name="verify_email"), - path("students/attendance/", get_student_attendance, name="get_student_attendance"), - path('verifyPRN',verify_prn, name='verify_prn'), - path('markAttendance',mark_attendance, name='mark_attendance'), - path('attendanceStatus//',attendance_status, name='attendance_status'), - path('getSubjects/',teacher_subjects, name='get_teacher_subjects'), - path('getPresentAbsentList/',get_present_absent_list, name='get_present_absent_list'), - path('changeAttendance/',change_attendance, name='change_attendance'), - path('teacherProfile//',teacher_profile, name='teacher_profile'), - path('student/dashboard/', get_student_dashboard, name='get_student_dashboard'), - path('student/notification-token/', update_notification_token, name='update_notification_token'), - path('student/notification-token/remove/', remove_notification_token, name='remove_notification_token'), - + re_path(r"^getDepartments/?$", getDepartments, name="get_departments"), + re_path(r"^registerNewStudent/?$", register_student, name="register_new_student"), + re_path(r"^registerStudent/?$", register_student, name="register_student"), + re_path(r"^registerNewTeacher/?$", registerNewTeacher, name="register_new_teacher"), + re_path(r"^validateStudent/?$", validateStudent, name="validate_student"), + re_path(r"^validateTeacher/?$", validateTeacher, name="validate_teacher"), + re_path(r"^sendOtp/?$", send_otp, name="send_otp"), + re_path(r"^verifyOtp/?$", verify_otp, name="verify_otp"), + re_path(r"^setPassword/?$", set_password, name="set_password"), + re_path(r"^getSubjectDetails/?$", get_subject_details, name="get_subject_details"), + re_path(r"^verifyEmail/?$", verify_email, name="verify_email"), + re_path(r"^students/attendance/?$", get_student_attendance, name="get_student_attendance"), + re_path( + r"^student/attendance/subject/(?P\d+)/?$", + get_student_subject_attendance, + name="get_student_subject_attendance", + ), + re_path(r"^verifyPRN/?$", verify_prn, name="verify_prn"), + re_path(r"^markAttendance/?$", mark_attendance, name="mark_attendance"), + re_path( + r"^attendanceStatus/(?P[^/]+)/?$", + attendance_status, + name="attendance_status", + ), + re_path(r"^teacher/subjects/?$", teacher_subjects, name="teacher_subjects"), + re_path(r"^getSubjects/?$", teacher_subjects, name="get_teacher_subjects"), + re_path(r"^getPresentAbsentList/?$", get_present_absent_list, name="get_present_absent_list"), + re_path(r"^changeAttendance/?$", change_attendance, name="change_attendance"), + re_path( + r"^teacherProfile/(?P\d+)/?$", + teacher_profile, + name="teacher_profile", + ), + re_path(r"^student/dashboard/?$", get_student_dashboard, name="get_student_dashboard"), + re_path(r"^student/notification-token/?$", update_notification_token, name="update_notification_token"), + re_path( + r"^student/notification-token/remove/?$", + remove_notification_token, + name="remove_notification_token", + ), ] if settings.DEBUG: diff --git a/ClassLens_DB/Home/views.py b/ClassLens_DB/Home/views.py index 0dd9810..5d7e716 100644 --- a/ClassLens_DB/Home/views.py +++ b/ClassLens_DB/Home/views.py @@ -91,7 +91,7 @@ def registerNewTeacher(request, *args, **kwargs): except Exception as e: traceback.print_exc() return Response( - {"detail": "Method not allowed"}, status=status.HTTP_405_METHOD_NOT_ALLOWED + {"detail": f"Error registering teacher: {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR ) @api_view(["POST"]) @@ -107,6 +107,14 @@ def validateStudent(request, *args, **kwargs): try: student = Student.objects.get(prn=prn) + + # Check if password_hash exists before attempting to verify + if student.password_hash is None: + return Response( + {"detail": "Student account not fully registered. Please set a password first."}, + status=status.HTTP_400_BAD_REQUEST, + ) + if not check_password(password, student.password_hash): return Response( {"detail": "Invalid password"}, status=status.HTTP_400_BAD_REQUEST @@ -123,8 +131,8 @@ def validateStudent(request, *args, **kwargs): except Exception as e: traceback.print_exc() return Response( - {"detail": "Method not allowed"}, - status=status.HTTP_405_METHOD_NOT_ALLOWED, + {"detail": f"Error validating student: {str(e)}"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) @api_view(["POST"]) @@ -161,7 +169,8 @@ def validateTeacher(request, *args, **kwargs): except Exception as e: traceback.print_exc() return Response( - {"detail": "Method not allowed"}, status=status.HTTP_405_METHOD_NOT_ALLOWED + {"detail": f"Error validating teacher: {str(e)}"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR ) @api_view(["POST"]) @@ -177,12 +186,27 @@ def get_subject_details(request, *args, **kwargs): ) subjects = subject_from_dept.subject.all() subjects = SubjectSerializer(subjects, many=True).data - return Response({"subjects": subjects,"message":"subject details"}, status=status.HTTP_200_OK) + divisions = Division.objects.filter( + department=department, + year=year, + ).order_by("name") + divisions_data = [ + { + "id": division.id, + "name": division.name, + "year": division.year, + } + for division in divisions + ] + return Response( + {"subjects": subjects, "divisions": divisions_data, "message": "subject details"}, + status=status.HTTP_200_OK, + ) except Exception as e: traceback.print_exc() return Response( - {"detail": "Something went wrong"}, - status=status.HTTP_405_METHOD_NOT_ALLOWED, + {"detail": f"Error getting subject details: {str(e)}"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) @api_view(["POST"]) @@ -371,6 +395,46 @@ def verify_otp(request, *args, **kwargs): status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) +def _update_student_password(prn, password, photo): + if prn is None or password is None: + return Response( + {"detail": "PRN and Password are required"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + student = Student.objects.filter(prn=prn).first() + if not student: + return Response( + {"detail": "No Student found with this prn"}, + status=status.HTTP_404_NOT_FOUND, + ) + + student.password_hash = make_password(password) + + if photo is not None: + try: + embedding = registerNewStudent(photo) + if isinstance(embedding, Exception): + raise Exception("Face embedding error: " + str(embedding)) + student.face_embedding = [float(value) for value in embedding] + except Exception: + return Response( + {"error": "Face Not Detected, Upload A New Image"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + student.save() + print(f"✓ Student password set successfully for PRN {prn}") + print(f" Hash (first 20 chars): {student.password_hash[:20]}...") + + verify = Student.objects.get(prn=prn) + if verify.password_hash: + print(f"✓ Verified: Password hash persisted in database for PRN {prn}") + return Response({"message": "Student password set successfully"}, status=200) + + print(f"✗ ERROR: Password hash is None after save for PRN {prn}!") + return Response({"detail": "Failed to persist password"}, status=500) + @api_view(["POST"]) def set_password(request, *args, **kwargs): try: @@ -386,42 +450,39 @@ def set_password(request, *args, **kwargs): if teacher : teacher.password_hash = make_password(password) teacher.save() - print("Teacher password set successfully") - return Response({"message": "Teacher password set successfully"}, status=200) + print(f"✓ Teacher password set successfully for {email}") + print(f" Hash (first 20 chars): {teacher.password_hash[:20]}...") + + # Verify it was saved to DB + verify = Teacher.objects.get(email=email) + if verify.password_hash: + print(f"✓ Verified: Password hash persisted in database") + return Response({"message": "Teacher password set successfully"}, status=200) + else: + print(f"✗ ERROR: Password hash is None after save!") + return Response({"detail": "Failed to persist password"}, status=500) else : return Response({"detail": "No Teacher found with this email"}, status=status.HTTP_404_NOT_FOUND) elif request.data.get("prn"): - prn=request.data.get("prn") - if prn is None or password is None: - return Response( - {"detail": "PRN and Password are required"}, - status=status.HTTP_400_BAD_REQUEST, - ) - - student = Student.objects.filter(prn=prn).first() - if student : - student.password_hash = make_password(password) - try : - embedding=registerNewStudent(request.FILES.get("photo")) - if not isinstance(embedding,Exception): - student.face_embedding = embedding - else : - raise Exception("Face embedding error: " + str(embedding)) - except Exception as e : - return Response({"error": "Face Not Detected, Upload A New Image"}, status=status.HTTP_400_BAD_REQUEST) - student.save() - print("Student password set successfully") - return Response({"message": "Student password set successfully"}, status=200) - else: - return Response({"detail": "No Student found with this prn"}, status=status.HTTP_404_NOT_FOUND) + prn = request.data.get("prn") + photo = request.FILES.get("photo") + return _update_student_password(prn, password, photo) except Exception as e: traceback.print_exc() + print(f"✗ Exception in set_password: {str(e)}") return Response( - {"detail": "An error occurred while updating the password"}, + {"detail": f"An error occurred while updating the password: {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) + +@api_view(["POST"]) +def register_student(request, *args, **kwargs): + prn = request.data.get("prn") + password = request.data.get("password") + photo = request.FILES.get("photo") + return _update_student_password(prn, password, photo) def registerNewStudent(photo): @@ -441,7 +502,7 @@ def registerNewStudent(photo): enforce_detection=True, )[0]["embedding"] - return image_embedding + return [float(value) for value in image_embedding] except ValueError as ve: return ValueError(ve) @@ -484,6 +545,54 @@ def get_student_attendance(request, *args, **kwargs): status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) +@api_view(["GET"]) +def get_student_subject_attendance(request, subject_id, *args, **kwargs): + try: + division_id = request.query_params.get("division_id") + year = request.query_params.get("year") + semester = request.query_params.get("semester") + + records = AttendanceRecord.objects.filter( + class_session__subject_id=subject_id + ).select_related( + "student", + "student__division", + "class_session", + ) + + if division_id: + records = records.filter(student__division_id=division_id) + if year: + records = records.filter(class_session__year=year) + # Division no longer stores semester; skip filtering by division.semester + + results = [] + for record in records: + results.append( + { + "class_session_id": record.class_session_id, + "student_id": record.student_id, + "student_name": record.student.name, + "student_prn": record.student.prn, + "status": record.status, + "marked_at": record.marked_at.isoformat(), + "class_datetime": record.class_session.class_datetime.isoformat(), + "division_id": record.student.division_id, + } + ) + + return Response( + {"attendance_records": results}, + status=status.HTTP_200_OK, + ) + + except Exception as e: + traceback.print_exc() + return Response( + {"detail": "Something went wrong"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + @api_view(["POST"]) @parser_classes([MultiPartParser]) def mark_attendance(request, *args, **kwargs): @@ -523,16 +632,29 @@ def mark_attendance(request, *args, **kwargs): return Response({"error": "Invalid teacher ID (0). Please log in again."}, status=400) try: - division = None + teacher_subject_qs = TeacherSubject.objects.filter( + teacher_id=teacher_id, + subject_id=subject_id, + ) + if division_id: - division = get_object_or_404(Division, id=division_id) + teacher_subject_qs = teacher_subject_qs.filter(division_id=division_id) + + if not teacher_subject_qs.exists(): + return Response( + {"error": "Teacher is not mapped to this subject/division"}, + status=400, + ) + + resolved_division_id = int(division_id) if division_id else None + if resolved_division_id is None and teacher_subject_qs.count() == 1: + resolved_division_id = teacher_subject_qs.first().division_id class_session = ClassSession.objects.create( department = get_object_or_404(Department, name=departmentName), year = year, subject = get_object_or_404(Subject, id=subject_id), teacher = get_object_or_404(Teacher, id=teacher_id), - division=division, class_datetime = datetime.now(), ) @@ -546,7 +668,13 @@ def mark_attendance(request, *args, **kwargs): photo=photo ) - task = evaluate_attendance.delay(total_sessions,class_session.id,request.scheme,"14.139.121.110:11020") + task = evaluate_attendance.delay( + total_sessions, + class_session.id, + request.scheme, + "14.139.121.110:11020", + resolved_division_id, + ) return Response({ "message": "Attendance processing started. You will be notified once it's done.", @@ -567,26 +695,34 @@ def mark_attendance(request, *args, **kwargs): # "task_id": task.id # }, status=202) -@api_view(["POST"]) -def teacher_subjects(request,*args, **kwargs): - teacher_id = request.data.get("teacher_id") +@api_view(["GET", "POST"]) +def teacher_subjects(request, *args, **kwargs): + teacher_id = ( + request.query_params.get("teacher_id") + if request.method == "GET" + else request.data.get("teacher_id") + ) if not teacher_id: return Response({"error": "Teacher ID is required"}, status=400) try: - subjects = TeacherSubject.objects.filter(teacher_id=teacher_id).values( - 'subject__id', - 'subject__code', - 'subject__name' + subjects = TeacherSubject.objects.filter(teacher_id=teacher_id).select_related( + "subject", + "division", ) clean_subjects = [ { - 'id': s['subject__id'], - 'code': s['subject__code'], - 'name': s['subject__name'], - 'strength': StudentEnrollment.objects.filter(subject_id=s['subject__id']).count() + "id": row.subject_id, + "code": row.subject.code, + "name": row.subject.name, + "division_id": row.division_id, + "division_name": row.division.name if row.division else None, + "strength": StudentEnrollment.objects.filter( + subject_id=row.subject_id, + student_prn__in=Student.objects.filter(division_id=row.division_id).values_list("prn", flat=True), + ).count() if row.division_id else StudentEnrollment.objects.filter(subject_id=row.subject_id).count(), } - for s in subjects + for row in subjects ] return Response({"subjects": clean_subjects}, status=200) except Exception as e: @@ -673,10 +809,16 @@ def teacher_profile(request,teacher_id, *args, **kwargs): return Response({"error": "Teacher ID is required"}, status=400) try: teacher = get_object_or_404(Teacher, id=teacher_id) - total_Subject=TeacherSubject.objects.filter(teacher_id_id=teacher_id).count() - total_Student=StudentEnrollment.objects.filter( - subject_id__in=TeacherSubject.objects.filter(teacher_id_id=teacher_id).values_list('subject_id', flat=True) - ).count() + teacher_subject_qs = TeacherSubject.objects.filter(teacher_id_id=teacher_id).select_related("division") + total_Subject = teacher_subject_qs.count() + total_Student = 0 + for teacher_subject in teacher_subject_qs: + enrollment_qs = StudentEnrollment.objects.filter(subject_id=teacher_subject.subject_id) + if teacher_subject.division_id: + enrollment_qs = enrollment_qs.filter( + student_prn__in=Student.objects.filter(division_id=teacher_subject.division_id).values_list("prn", flat=True) + ) + total_Student += enrollment_qs.count() department = teacher.department.name if teacher.department else None profile_data = { "name": teacher.name, @@ -693,6 +835,34 @@ def teacher_profile(request,teacher_id, *args, **kwargs): {"detail": "Something went wrong"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) + + +def _resolve_student_semester(student): + subject_ids = set( + StudentEnrollment.objects.filter(student_prn=student.prn).values_list("subject_id", flat=True) + ) + subject_mappings = ( + SubjectFromDept.objects.filter(department=student.department, year=student.year) + .prefetch_related("subject") + .order_by("semester") + ) + + best_semester = None + best_score = -1 + + for subject_mapping in subject_mappings: + mapped_subject_ids = set(subject_mapping.subject.values_list("id", flat=True)) + score = len(subject_ids.intersection(mapped_subject_ids)) + + if score > best_score: + best_score = score + best_semester = subject_mapping.semester + + if best_score > 0: + return best_semester + + first_mapping = subject_mappings.first() + return first_mapping.semester if first_mapping else None @api_view(['POST']) @permission_classes([AllowAny]) @@ -735,6 +905,7 @@ def get_student_dashboard(request, *args, **kwargs): ) student = get_object_or_404(Student, id=student_id) + semester = _resolve_student_semester(student) enrollments = StudentEnrollment.objects.filter(student_prn=student.prn).select_related('subject') @@ -751,7 +922,11 @@ def get_student_dashboard(request, *args, **kwargs): percentage=data.attendancePercentage - teacher = TeacherSubject.objects.filter(subject=subject).select_related('teacher_id').first() + teacher = TeacherSubject.objects.filter(subject=subject, division=student.division).select_related('teacher_id').first() + if teacher is None and student.division is not None: + teacher = TeacherSubject.objects.filter(subject=subject, division__isnull=True).select_related('teacher_id').first() + if teacher is None: + teacher = TeacherSubject.objects.filter(subject=subject).select_related('teacher_id').first() teacher_name = teacher.teacher_id.name if teacher else "N/A" subjects_data.append({ @@ -786,6 +961,12 @@ def get_student_dashboard(request, *args, **kwargs): return Response({ "student_name": student.name, "prn": student.prn, + "email": student.email, + "year": student.year, + "department_name": student.department.name if student.department else None, + "division_id": student.division_id, + "division_name": student.division.name if student.division else None, + "semester": semester, "overall_attendance": overall_percentage, "subjects": subjects_data, "recent_activity": recent_activity, diff --git a/FRONTEND_CHANGES.md b/FRONTEND_CHANGES.md deleted file mode 100644 index ec4e30f..0000000 --- a/FRONTEND_CHANGES.md +++ /dev/null @@ -1,328 +0,0 @@ -# Frontend Changes Required - ClassLens Attendance System - -## Summary -Backend schema updated to support: -- **Division** model (department-level grouping) -- **API mirror tables** for MSUIS data ingestion -- **Overall + per-subject attendance** in student dashboard - -This document outlines all frontend changes needed to work with the new backend API contract. - ---- - -## 1. Admin App Changes - -### 1.1 Division Management (New Feature) -**Location:** Admin Dashboard → Division Management - -**New CRUD Endpoint:** -``` -GET /api/admin/divisions/ - List all divisions -POST /api/admin/divisions/ - Create division -GET /api/admin/divisions/{id}/ - Get division details -PUT /api/admin/divisions/{id}/ - Update division -DELETE /api/admin/divisions/{id}/ - Delete division -``` - -**Form Fields (for Create/Edit):** -- `department` (ForeignKey) - dropdown, required -- `program_name` (CharField) - e.g., "B.E Computer Science" -- `year` (IntegerField) - 1, 2, 3, 4 -- `semester` (IntegerField) - 1-8 -- `name` (CharField) - e.g., "A", "B", "C" (division code) - -**UI Changes:** -- Add "Divisions" menu item in admin sidebar -- Show table with columns: Department, Program, Year, Semester, Name -- Add "Add Division", "Edit", "Delete" buttons -- Validation: unique constraint on (department, program_name, year, semester, name) - -### 1.2 MSUIS Data Sync (New Feature) -**Location:** Admin Dashboard → Data Management → Sync MSUIS - -**New Endpoint:** -``` -POST /api/admin/sync/msuis/ -Content-Type: application/json - -Request Payload: -{ - "faculties": [ - { "Id": 1, "FacultyName": "CS Dept", "IsActive": 1, ... } - ], - "students": [ - { "PRN": 2021001, "FirstName": "John", "LastName": "Doe", - "EmailId": "john@example.com", "FacultyId": 1, "Year": 2, ... } - ], - "papers": [ - { "Id": 10, "PaperCode": "CS101", "PaperName": "Data Structures", - "SubjectId": 10, ... } - ], - "student_academic_information": [ - { "Id": 100, "PRN": 2021001, "FacultyId": 1, "AcademicYearId": 2025, ... } - ], - "student_part_term_paper_maps": [ - { "Id": 1000, "PRN": 2021001, "PaperId": 10, "Division": "A", - "Semester": 3, ... } - ], - "apply_to_core": true -} - -Response (200 OK): -{ - "message": "MSUIS payload synced via admin app", - "apply_to_core": true, - "counts": { - "faculties_synced": 1, - "students_synced": 100, - "papers_synced": 50, - "academic_records_synced": 150, - "part_term_maps_synced": 500, - "core_departments_upserted": 1, - "core_students_upserted": 100, - "core_subjects_upserted": 50, - "core_enrollments_upserted": 500, - "core_divisions_upserted": 10 - } -} -``` - -**UI Changes:** -- Add "Sync MSUIS Data" section in admin -- Large JSON text area to paste API payload (or file upload button for JSON) -- Toggle: "Apply to Core Tables" (default: checked) -- "Sync" button → POST to /api/admin/sync/msuis/ -- Show results: success/failure count, summary of upserted records -- Optional: Show mirror table counts (APIFaculty, APIStudent, etc.) - ---- - -## 2. Teacher App / Mark Attendance Changes - -### 2.1 Mark Attendance Form Update -**Location:** Teacher Dashboard → Mark Attendance - -**New Field Added:** -- **Division** (Dropdown, required) - - Fetch from: `GET /api/admin/divisions/` filtered by teacher's department - - Or fetch from: `GET /api/admin/subject-from-dept/?department={dept}&year={year}&semester={semester}` - - Display as: "Division: [A / B / C / ...]" - -**Request Update:** -```javascript -// Old request (multipart) -POST /api/markAttendance -{ - photo: [file1, file2, ...], - subjectID: 5, - teacherID: 12, - departmentName: "CSE", - year: 2 -} - -// New request (multipart) - ADD divisionID -POST /api/markAttendance -{ - photo: [file1, file2, ...], - subjectID: 5, - teacherID: 12, - departmentName: "CSE", - year: 2, - divisionID: 3 // NEW - division ID -} -``` - -**UI Changes:** -1. In the mark attendance form, add a Division dropdown **after** the Subject field -2. Populate division dropdown when subject is selected: - ``` - GET /api/admin/divisions/?department={teacher_dept}&year={selected_year} - ``` - Display: option value=division.id, text=division.name -3. Make divisionID required (validate before submit) -4. Send `divisionID` in the multipart POST request - -**Example HTML:** -```html -
- - - - - - - -
-``` - ---- - -## 3. Student App / Dashboard Changes - -### 3.1 Student Dashboard Update -**Location:** Student Dashboard / Home - -**Endpoint Update (same endpoint, enhanced response):** -``` -POST /api/student/dashboard/ -{ - "student_id": 1 -} - -Response (200 OK): -{ - "student_name": "John Doe", - "prn": 2021001, - "overall_attendance": 85.5, // NEW - weighted average across all subjects - "subjects": [ - { - "id": 5, - "name": "Data Structures", - "code": "CS101", - "teacher": "Dr. Smith", - "total": 20, // total classes held for this subject - "attended": 17, // classes attended by student - "percentage": 85.0 // (attended / total) * 100 - }, - { - "id": 6, - "name": "Algorithms", - "code": "CS102", - "teacher": "Dr. Johnson", - "total": 18, - "attended": 15, - "percentage": 83.33 - } - ], - "recent_activity": [ - { - "subject": "Data Structures", - "status": "Present", - "date": "2026-05-10T14:30:00Z" - }, - ... - ] -} -``` - -**UI Changes:** - -#### 3.1.1 Overall Attendance Summary Card (NEW) -Add a card/section at the top of dashboard: -``` -┌─────────────────────────────────┐ -│ Overall Attendance │ -│ │ -│ 85.5% │ -│ ████████████░░░░░░░░░░░░░░░░ │ (progress bar) -│ │ -│ Across 4 subjects │ -└─────────────────────────────────┘ -``` - -**Implementation:** -- Display `response.overall_attendance` as percentage -- Show progress bar (green if >= 75%, yellow if >= 60%, red if < 60%) -- Optional: Show "Across X subjects" subtitle - -#### 3.1.2 Per-Subject Attendance List -Keep existing subject cards but enhance: - -``` -┌─────────────────────────────────────────────┐ -│ Data Structures (CS101) │ -│ Teacher: Dr. Smith │ -├─────────────────────────────────────────────┤ -│ Attendance: 17/20 (85%) │ -│ ████████████░░░░░░░░░░░░░░░░ │ -├─────────────────────────────────────────────┤ -│ • 3 classes missed │ -└─────────────────────────────────────────────┘ -``` - -**Changes:** -- Display `teacher` name (from response) -- Show `attended` and `total` (e.g., "17/20") -- Show `percentage` as progress bar color-coded: - - **Green**: >= 75% (good attendance) - - **Yellow**: 60-74% (warning) - - **Red**: < 60% (at risk) -- Calculate missed = total - attended, display - -#### 3.1.3 Recent Activity Feed -Keep existing; displayed below subjects. - ---- - -## 4. API Contract Summary - -### New/Updated Endpoints - -| Method | Endpoint | Purpose | Auth | -|--------|----------|---------|------| -| GET | `/api/admin/divisions/` | List divisions | Yes | -| POST | `/api/admin/divisions/` | Create division | Yes | -| GET | `/api/admin/divisions/{id}/` | Get division | Yes | -| PUT | `/api/admin/divisions/{id}/` | Update division | Yes | -| DELETE | `/api/admin/divisions/{id}/` | Delete division | Yes | -| POST | `/api/admin/sync/msuis/` | Sync MSUIS payload | Yes | -| POST | `/api/markAttendance` | Mark attendance (UPDATED) | No | -| POST | `/api/student/dashboard/` | Student dashboard (UPDATED) | No | - -### Field Additions -- `ClassSession.division` (ForeignKey to Division) - now passed from mark_attendance -- Student Dashboard response: `overall_attendance` (float, optional) -- Mark Attendance request: `divisionID` (integer, optional but recommended) - ---- - -## 5. Implementation Checklist - -### Admin App -- [ ] Create Division CRUD form/page -- [ ] Add Division menu item to sidebar -- [ ] Create MSUIS sync page with JSON textarea -- [ ] POST payload to /api/admin/sync/msuis/ -- [ ] Display sync results - -### Teacher App -- [ ] Add Division dropdown to mark attendance form -- [ ] Load divisions on subject selection -- [ ] Validate division is selected -- [ ] Send `divisionID` in mark attendance POST - -### Student App -- [ ] Add overall_attendance card at top of dashboard -- [ ] Style progress bars (green/yellow/red) -- [ ] Display teacher name for each subject -- [ ] Show attended/total counts -- [ ] Keep recent activity feed - ---- - -## 6. Testing Checklist - -- [ ] Create test admin account and login -- [ ] Create 2-3 divisions via admin UI -- [ ] Test mark attendance with division selection -- [ ] Verify ClassSession.division is saved -- [ ] Check student dashboard shows overall_attendance -- [ ] Verify per-subject percentages calculate correctly -- [ ] Test MSUIS sync payload import -- [ ] Verify mirror tables populated (APIStudent, APIFaculty, etc.) -- [ ] Verify core tables updated (Student, Subject, Division, etc.) - ---- - -## 7. Notes - -1. **Division is optional in mark_attendance**: If not sent, ClassSession.division will be NULL. For full functionality, always send divisionID. -2. **Overall attendance is weighted**: Calculated as (total_attended / total_classes) * 100 across all enrolled subjects. -3. **MSUIS sync is admin-only**: Use JWT auth with admin user. -4. **Mirror tables** (APIStudent, APIFaculty, etc.) store raw API data; core tables (Student, Subject, Division) store operational data. Sync can populate either or both. diff --git a/FRONTEND_CONTEXT.md b/FRONTEND_CONTEXT.md deleted file mode 100644 index 1e6309d..0000000 --- a/FRONTEND_CONTEXT.md +++ /dev/null @@ -1,452 +0,0 @@ -# ClassLens Frontend Context & Requirements - -**Project Goal:** Attendance tracking and display system. Students see their attendance by division, subject, semester, year, and department. Admins manage enrollment sync and divisions. Teachers mark attendance via photo uploads. - ---- - -## 1. Database Schema Summary (Attendance-Focused) - -### Mirror Layer (APIEnrollment - Admin Sync) -``` -APIEnrollment { - prn: BigInt (indexed) - subject_code: String - department_name: String - program_name: String - year: Int - semester: Int - division: String (A, B, C, etc.) - raw_payload: JSON - synced_at: DateTime -} -``` - -### Core Layer (Attendance Tracking) - -**Core Entities:** -- **Department** — Department name (CS, ECE, ME, etc.) -- **Student** — prn, name, email, year, department, face_embedding, notification_token -- **Subject** — code, name, department_id -- **Division** — department_id, program_name, year, semester, name (A/B/C) — **Unique by (dept, program, year, semester, name)** -- **StudentEnrollment** — student_prn, subject_id, division_id — **Unique by (student_prn, subject, division)** -- **Teacher** — name, email, department_id -- **TeacherSubject** — teacher_id, subject_id (NO division-level control yet) - -**Attendance Tracking:** -- **ClassSession** — department_id, year, subject_id, teacher_id, division_id, class_datetime -- **AttendanceRecord** — class_session_id, student_id, status (bool), marked_at — **Unique by (class_session, student)** -- **StudentAttendancePercentage** — student_id, subject_id, present_count, attendancePercentage - ---- - -## 2. Frontend: Student Dashboard - -### What Students See - -**Overall Attendance Card:** -``` -┌─────────────────────────────────┐ -│ Your Attendance Overview │ -├─────────────────────────────────┤ -│ Overall: 82.5% │ -│ Classes Attended: 33 / 40 │ -│ Last Marked: Today, 10:30 AM │ -└─────────────────────────────────┘ -``` - -**Subject-wise Breakdown (Filtered by Division):** -``` -┌──────────────────────────────────────────┐ -│ Attendance by Subject │ -├──────────────────────────────────────────┤ -│ Subject | Attended | Total | % │ -├──────────────────────────────────────────┤ -│ Data Structures | 16/20 | 20 | 80% │ -│ Algorithms | 17/20 | 20 | 85% │ -│ DBMS | 14/18 | 18 | 78% │ -└──────────────────────────────────────────┘ -``` - -**Filter Options:** -- **By Division:** Current division (auto-selected based on enrollment) -- **By Semester:** Dropdown (1-8) -- **By Year:** Dropdown (1-4) -- **By Department:** Auto-selected from student's enrollment - -### API Endpoints (Student) - -``` -GET /api/student/dashboard/ - Returns: - { - "student": { - "prn": 2021001, - "name": "John Kumar", - "year": 2, - "department": "Computer Science" - }, - "enrollments": [ - { - "subject_id": 50, - "subject_code": "CS101", - "subject_name": "Data Structures", - "division": "A", - "semester": 3, - "year": 2 - } - ], - "overall_attendance": 82.5, - "attendance_by_subject": [ - { - "subject_code": "CS101", - "subject_name": "Data Structures", - "present_count": 16, - "total_classes": 20, - "percentage": 80.0 - } - ] - } - -GET /api/student/attendance/subject/{subject_id}/?division_id={div_id}&year={year}&semester={sem} - Returns: Detailed attendance records for that subject - -GET /api/student/divisions/ - Returns: List of divisions student is enrolled in - [ - { - "id": 1, - "name": "A", - "department": "CSE", - "program": "B.E Computer Science", - "year": 2, - "semester": 3 - } - ] -``` - ---- - -## 3. Frontend: Teacher Interface - -### What Teachers Do - -**Mark Attendance:** -1. Select Subject -2. Select Division (auto-populated from TeacherSubject, currently no division-level constraint) -3. Upload class photo -4. System recognizes faces via face_embedding (pgvector similarity search) -5. Auto-marks attendance for recognized students -6. Teacher reviews and confirms - -**View Attendance:** -- Per-subject attendance report -- Attendance history (CSV export) -- Per-student attendance breakdown - -### API Endpoints (Teacher) - -``` -POST /api/markAttendance - Input: - { - "subject_id": 50, - "division_id": 1, - "class_photo": , // Image to extract faces from - "class_datetime": "2026-05-11T10:00:00Z" - } - Returns: - { - "class_session_id": 123, - "recognized_count": 28, - "unrecognized_count": 2, - "attendance_records": [ - { - "student_prn": 2021001, - "status": true, // Present - "confidence": 0.95 - } - ] - } - -GET /api/teacher/subjects/ - Returns: List of subjects teacher teaches (via TeacherSubject) - -GET /api/teacher/subject/{subject_id}/divisions/ - Returns: Divisions this teacher teaches this subject in - -GET /api/teacher/attendance/subject/{subject_id}/?division_id={div_id} - Returns: Attendance records for that subject/division -``` - ---- - -## 4. Frontend: Admin Interface - -### What Admins Do - -**1. Sync MSUIS Enrollments** -- Upload enrollment JSON or call sync endpoint -- Enrollments must include: (prn, subject_code, division, department_name, program_name, year, semester) -- System auto-creates/updates: Department, Division, Student, Subject, StudentEnrollment - -**2. Manage Divisions** -- View all divisions by department, program, year, semester -- Create new divisions (if needed) -- Edit division name/settings - -**3. Manage Teachers & Assignments** -- Assign teachers to subjects -- ⚠️ **NOTE:** Currently TeacherSubject has no division-level control - - Teacher A can teach Subject CS101 (to all divisions) - - If needed, add division FK to TeacherSubject - -**4. View Sync Status** -- Last sync timestamp -- Number of enrollments synced -- Errors/warnings during sync - -### API Endpoints (Admin) - -``` -POST /api/admin/sync/msuis/ - Input: - { - "enrollments": [ - { - "prn": 2021001, - "subject_code": "CS101", - "department_name": "Department of Computer Science", - "program_name": "B.E Computer Science", - "year": 2, - "semester": 3, - "division": "A" - } - ], - "apply_to_core": true // Create core tables - } - Returns: - { - "status": "success", - "api_enrollments_created": 2, - "core_divisions_created": 1, - "core_students_created": 1, - "core_enrollments_created": 2, - "timestamp": "2026-05-11T12:00:00Z" - } - -GET /api/admin/divisions/ - Returns: All divisions with filters by department, program, year, semester - [ - { - "id": 1, - "department": "CSE", - "program": "B.E Computer Science", - "year": 2, - "semester": 3, - "name": "A", - "student_count": 45 - } - ] - -GET /api/admin/sync-status/ - Returns: Last sync info, error logs - -POST /api/admin/teachers/assign-subject/ - Input: - { - "teacher_id": 5, - "subject_id": 50 - // division_id: Not currently supported, consider adding - } - Returns: TeacherSubject record created -``` - ---- - -## 5. Key Data Flow - -### Enrollment Sync Workflow -``` -Admin POST /api/admin/sync/msuis/ with APIEnrollment payload - ↓ -Store in APIEnrollment mirror table - ↓ -If apply_to_core=true: - - Create/update Department (from department_name) - - Create/update Student (from prn) - - Create/update Subject (from subject_code) - - Create/update Division (from program_name, year, semester, division) - - Create/update StudentEnrollment (link student → subject → division) - - Initialize StudentAttendancePercentage (present_count=0, percentage=0.0) -``` - -### Attendance Marking Workflow -``` -Teacher POST /api/markAttendance with class photo - ↓ -Extract faces from photo (RetinaFace detector) - ↓ -Get student enrollments for that (subject, division) - ↓ -For each enrolled student: - - Compute face embedding (Facenet512 via DeepFace) - - Search pgvector for matching student.face_embedding (HNSW index) - - If match > confidence_threshold: mark present - - If no match: mark absent - ↓ -Create ClassSession record - ↓ -Create AttendanceRecord for each student - ↓ -Recompute StudentAttendancePercentage (present_count, percentage) - ↓ -Return results to teacher for review/confirmation -``` - -### Student Dashboard Query Workflow -``` -Student GET /api/student/dashboard/ - ↓ -Query Student by auth token (student.prn) - ↓ -Get StudentEnrollment records filtered by (student_prn, division_id) - ↓ -Get StudentAttendancePercentage for enrolled subjects - ↓ -Compute overall attendance: sum(present_count) / sum(total_classes) - ↓ -Return formatted response to frontend -``` - ---- - -## 6. Frontend Components Needed - -### Student App -- **Dashboard Component** - - Overall attendance card - - Subject-wise attendance table - - Filters (division, semester, year, department) - - Attendance history/timeline - -- **Subject Attendance Detail** - - Per-class attendance records - - Export to CSV/PDF - -- **Settings/Profile** - - Notification preferences - - Face registration (for attendance photo processing) - -### Teacher App -- **Mark Attendance Component** - - Subject/division selector - - Photo upload - - Face recognition preview + confirmation - - Submit attendance - -- **Attendance Reports** - - Subject-wise report - - Per-student report - - Date range filter - -### Admin App -- **Sync Dashboard** - - Upload MSUIS enrollment JSON - - Sync status/logs - - API endpoint to trigger sync - -- **Division Management** - - View all divisions (table/list) - - Create new division (if manual creation needed) - - Edit division - - View enrolled students per division - -- **Teacher Assignments** - - Assign teacher to subject - - View TeacherSubject mappings - ---- - -## 7. Important Notes - -### ⚠️ Division-Level Teacher Control -**Current Status:** TeacherSubject has NO division FK. -- Teacher A can teach Subject CS101, but system doesn't track if it's to Div A or Div B -- This is currently **flexible** (teacher can teach multiple divisions of same subject) -- If you want **stricter control** (one teacher per subject per division), add division FK to TeacherSubject - -### ⚠️ Face Recognition Setup -- **Model:** Facenet512 via DeepFace library -- **Vector Index:** pgvector with HNSW (Hierarchical Navigable Small World) -- **Embedding Dimensions:** 512 -- **Processing:** Celery task queue via RabbitMQ (async) -- **Requirements:** - - Database must have pgvector extension installed - - RabbitMQ broker running (amqp://guest:guest@localhost:5672/) - - TensorFlow/DeepFace dependencies installed - -### ⚠️ Authentication -- Students use JWT (drf-simplejwt) with student PRN -- Teachers use JWT with teacher ID -- Admins use JWT or session-based auth -- Implement refresh token rotation - -### ⚠️ Data Consistency -- Attendance is **immutable once marked** (consider adding soft-delete or review workflow) -- StudentAttendancePercentage is **computed** (updated when attendance marked) -- Division assignments are **per-student-per-enrollment** (StudentEnrollment.division_id) - ---- - -## 8. UI/UX Considerations - -### Student View -- **Simplicity:** Show only their divisions/subjects -- **Real-time:** Update attendance immediately after marking -- **Mobile-friendly:** Responsive tables, dropdown filters -- **Visual clarity:** Color-code attendance % (green ≥75%, yellow 60-74%, red <60%) - -### Teacher View -- **Ease of use:** Minimal clicks to upload and confirm attendance -- **Feedback:** Clear success/error messages -- **Batch operations:** Mark multiple classes at once if needed - -### Admin View -- **Overview:** Dashboard showing last sync time, enrollment count, error logs -- **Drill-down:** View details of specific sync batches -- **Bulk operations:** CSV export/import for divisions and teachers - ---- - -## 9. Integration Checklist - -- [ ] **Student API integration** — Dashboard, attendance details, filters -- [ ] **Teacher API integration** — Mark attendance, view reports -- [ ] **Admin API integration** — Sync enrollments, manage divisions, assign teachers -- [ ] **Authentication** — JWT tokens, refresh logic, logout -- [ ] **Error handling** — Network errors, validation errors, API errors -- [ ] **Loading states** — Show spinners during API calls -- [ ] **Notification** — Firebase FCM integration (optional, for sync notifications) -- [ ] **Testing** — API mocking, unit tests for filters and calculations - ---- - -## 10. Backend API Base URL - -``` -Development: http://localhost:8000/api/ -Production: https://api.classlens.com/api/ -``` - -All endpoints require `Authorization: Bearer ` header except public endpoints. - ---- - -## Questions for Frontend Developer - -1. **Division-level teacher control:** Should we enforce one teacher per subject per division, or allow flexibility? -2. **Face registration workflow:** Should students pre-register faces, or is on-demand recognition enough? -3. **Offline support:** Do teachers need to mark attendance offline and sync later? -4. **Multi-language support:** Required? -5. **Dark mode:** Required? - diff --git a/test_sync_endpoint.py b/test_sync_endpoint.py deleted file mode 100644 index 411fce5..0000000 --- a/test_sync_endpoint.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -"""Test the sync_msuis_payload endpoint via Django shell.""" -import os -import sys -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ClassLens_DB.settings') -sys.path.insert(0, 'ClassLens_DB') -django.setup() - -from django.test import RequestFactory -import json -from Home.models import AdminUser, Department, Student, Subject -from DatabaseAdminApp.views import sync_msuis_payload - -# Use existing admin or create one -admin = AdminUser.objects.first() -if not admin: - admin = AdminUser(username='admin', is_active=True) - admin.set_password('admin') - admin.save() - -print(f"Using admin: {admin.username} (id={admin.id})") -print(f"Departments before sync: {Department.objects.count()}") -print(f"Students before sync: {Student.objects.count()}") - -# Build mock request with payload -rf = RequestFactory() -payload = { - 'faculties': [{'Id': 100, 'FacultyName': 'Test Faculty', 'IsActive': 1}], - 'students': [{'PRN': 2025001, 'FirstName': 'John', 'MiddleName': '', 'LastName': 'Doe', 'EmailId': 'john@example.com', 'FacultyId': 100, 'Year': 2}], - 'papers': [{'Id': 500, 'PaperCode': 'TEST101', 'PaperName': 'Test Subject', 'SubjectId': 500}], - 'student_academic_information': [], - 'student_part_term_paper_maps': [{'Id': 1000, 'PRN': 2025001, 'PaperId': 500, 'Division': 'A', 'Semester': 3}], - 'apply_to_core': True -} - -req = rf.post('/api/admin/sync/msuis/', data=json.dumps(payload), content_type='application/json') -req.user = admin - -# Call the view -resp = sync_msuis_payload(req) -print(f"\nResponse status: {resp.status_code}") -print(f"Response data: {json.dumps(resp.data, indent=2)}") - -print(f"\nDepartments after sync: {Department.objects.count()}") -print(f"Students after sync: {Student.objects.count()}") -print(f"Subjects after sync: {Subject.objects.count()}") -print("\n✓ Sync endpoint test completed successfully!") From 1f88e8da060ebbefd4fe3e4474f2e717dcd1a34e Mon Sep 17 00:00:00 2001 From: Dhriti-5 Date: Mon, 25 May 2026 17:29:11 +0530 Subject: [PATCH 09/14] resolve the timestamp mismatch between class_session_time and attendance_mark_time --- ClassLens_DB/ClassLens_DB/settings.py | 2 +- ClassLens_DB/Home/tasks.py | 3 ++- ClassLens_DB/Home/views.py | 16 +++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ClassLens_DB/ClassLens_DB/settings.py b/ClassLens_DB/ClassLens_DB/settings.py index 28fe101..760a60f 100644 --- a/ClassLens_DB/ClassLens_DB/settings.py +++ b/ClassLens_DB/ClassLens_DB/settings.py @@ -33,7 +33,7 @@ DEBUG = True ALLOWED_HOSTS = [ - '192.168.1.8', + '172.26.12.236', '10.0.2.2', '14.139.121.110', 'localhost', diff --git a/ClassLens_DB/Home/tasks.py b/ClassLens_DB/Home/tasks.py index c03a9b5..e32ceea 100644 --- a/ClassLens_DB/Home/tasks.py +++ b/ClassLens_DB/Home/tasks.py @@ -62,6 +62,7 @@ def patched_torch_load(f, *args, **kwargs): torch.load = patched_torch_load from .models import Student, AttendanceRecord, ClassSession, StudentEnrollment, StudentAttendancePercentage +from django.utils import timezone # Defer GFPGAN restorer initialization until a task runs to avoid import-time file access restorer = None @@ -285,7 +286,7 @@ def evaluate_attendance(total_sessions, class_session_id: int, scheme, host, div class_session=session, student=student_obj, status=is_present, - marked_at=session.class_datetime + marked_at=timezone.now() ) ) diff --git a/ClassLens_DB/Home/views.py b/ClassLens_DB/Home/views.py index 5d7e716..759216e 100644 --- a/ClassLens_DB/Home/views.py +++ b/ClassLens_DB/Home/views.py @@ -26,6 +26,7 @@ from django.core.cache import cache from django.core.mail import send_mail from django.conf import settings +from django.utils import timezone import environ import os from pathlib import Path @@ -655,7 +656,7 @@ def mark_attendance(request, *args, **kwargs): year = year, subject = get_object_or_404(Subject, id=subject_id), teacher = get_object_or_404(Teacher, id=teacher_id), - class_datetime = datetime.now(), + class_datetime = timezone.now(), ) total_sessions=ClassSession.objects.filter( @@ -920,7 +921,12 @@ def get_student_dashboard(request, *args, **kwargs): subject=subject ).first() - percentage=data.attendancePercentage + if data is None: + percentage = 0 + present_count = 0 + else: + percentage = data.attendancePercentage + present_count = data.present_count teacher = TeacherSubject.objects.filter(subject=subject, division=student.division).select_related('teacher_id').first() if teacher is None and student.division is not None: @@ -935,20 +941,20 @@ def get_student_dashboard(request, *args, **kwargs): "code": subject.code, "teacher": teacher_name, "total": total_sessions, - "attended": data.present_count, + "attended": present_count, "percentage": round(float(percentage), 2) }) recent_records = AttendanceRecord.objects.filter( student=student - ).select_related('class_session__subject').order_by('-class_session__class_datetime')[:5] + ).select_related('class_session__subject').order_by('-marked_at')[:5] recent_activity = [] for record in recent_records: recent_activity.append({ "subject": record.class_session.subject.name, "status": "Present" if record.status else "Absent", - "date": record.class_session.class_datetime.isoformat() + "date": record.marked_at.isoformat() }) # compute overall attendance across all subjects (weighted by total sessions) From 9f0a84f8c2558714d56c6eb0194f62c21c644445 Mon Sep 17 00:00:00 2001 From: Dhriti-5 Date: Wed, 27 May 2026 16:27:46 +0530 Subject: [PATCH 10/14] create api endpoint for retriving attendance data at teacher-side --- ClassLens_DB/Home/tests.py | 109 ++++++++++++++++++++++++++++++++++++- ClassLens_DB/Home/urls.py | 4 +- ClassLens_DB/Home/views.py | 91 +++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 2 deletions(-) diff --git a/ClassLens_DB/Home/tests.py b/ClassLens_DB/Home/tests.py index 7ce503c..aadf281 100644 --- a/ClassLens_DB/Home/tests.py +++ b/ClassLens_DB/Home/tests.py @@ -1,3 +1,110 @@ from django.test import TestCase +from django.urls import reverse +from django.utils import timezone +from rest_framework.test import APIClient -# Create your tests here. +from .models import ( + AttendanceRecord, + ClassSession, + Department, + Division, + Student, + StudentEnrollment, + Subject, + Teacher, + TeacherSubject, +) + + +class TeacherClassSessionsEndpointTests(TestCase): + def setUp(self): + self.client = APIClient() + + self.department = Department.objects.create(name="Computer Science") + self.teacher = Teacher.objects.create( + name="Teacher One", + email="teacher.one@example.com", + department=self.department, + ) + self.subject = Subject.objects.create( + code="CS101", + name="Object Oriented Programming with Java-CSE", + department=self.department, + ) + self.division = Division.objects.create( + department=self.department, + year=2, + name="SFI", + ) + self.teacher_subject = TeacherSubject.objects.create( + teacher_id=self.teacher, + subject=self.subject, + division=self.division, + ) + + self.student_one = Student.objects.create( + prn=1001, + name="Student One", + email="student.one@example.com", + year=2, + department=self.department, + division=self.division, + ) + self.student_two = Student.objects.create( + prn=1002, + name="Student Two", + email="student.two@example.com", + year=2, + department=self.department, + division=self.division, + ) + + StudentEnrollment.objects.create(student_prn=self.student_one.prn, subject=self.subject) + StudentEnrollment.objects.create(student_prn=self.student_two.prn, subject=self.subject) + + self.class_session = ClassSession.objects.create( + department=self.department, + year=2, + subject=self.subject, + teacher=self.teacher, + class_datetime=timezone.now(), + ) + + AttendanceRecord.objects.create( + class_session=self.class_session, + student=self.student_one, + status=True, + ) + AttendanceRecord.objects.create( + class_session=self.class_session, + student=self.student_two, + status=False, + ) + + def test_get_teacher_class_sessions_returns_expected_payload(self): + response = self.client.get( + reverse("teacher_class_sessions"), + {"teacher_id": self.teacher.id, "limit": 5}, + ) + + self.assertEqual(response.status_code, 200) + self.assertIn("class_sessions", response.data) + self.assertEqual(len(response.data["class_sessions"]), 1) + + session_data = response.data["class_sessions"][0] + self.assertEqual(session_data["class_session_id"], self.class_session.id) + self.assertEqual(session_data["subject_name"], self.subject.name) + self.assertEqual(session_data["division_name"], self.division.name) + self.assertEqual(session_data["present_count"], 1) + self.assertEqual(session_data["absent_count"], 1) + self.assertEqual(session_data["total_count"], 2) + + def test_post_teacher_class_sessions_fallback_works(self): + response = self.client.post( + reverse("get_teacher_class_sessions"), + {"teacher_id": self.teacher.id, "limit": 5}, + format="json", + ) + + self.assertEqual(response.status_code, 200) + self.assertIn("class_sessions", response.data) diff --git a/ClassLens_DB/Home/urls.py b/ClassLens_DB/Home/urls.py index d8845d5..dcca9ea 100644 --- a/ClassLens_DB/Home/urls.py +++ b/ClassLens_DB/Home/urls.py @@ -1,7 +1,7 @@ from django.urls import path, re_path from django.urls import include -from Home.views import getDepartments,mark_attendance,teacher_profile,registerNewTeacher,validateStudent,validateTeacher,send_otp,verify_otp,set_password,get_subject_details,verify_email, verify_prn, get_student_attendance,attendance_status,teacher_subjects, get_present_absent_list,change_attendance,get_student_dashboard,update_notification_token,remove_notification_token, register_student, get_student_subject_attendance +from Home.views import getDepartments,mark_attendance,teacher_profile,registerNewTeacher,validateStudent,validateTeacher,send_otp,verify_otp,set_password,get_subject_details,verify_email, verify_prn, get_student_attendance,attendance_status,teacher_subjects,teacher_class_sessions, get_present_absent_list,change_attendance,get_student_dashboard,update_notification_token,remove_notification_token, register_student, get_student_subject_attendance from django.conf import settings from django.conf.urls.static import static @@ -32,6 +32,8 @@ ), re_path(r"^teacher/subjects/?$", teacher_subjects, name="teacher_subjects"), re_path(r"^getSubjects/?$", teacher_subjects, name="get_teacher_subjects"), + re_path(r"^teacher/class-sessions/?$", teacher_class_sessions, name="teacher_class_sessions"), + re_path(r"^getTeacherClassSessions/?$", teacher_class_sessions, name="get_teacher_class_sessions"), re_path(r"^getPresentAbsentList/?$", get_present_absent_list, name="get_present_absent_list"), re_path(r"^changeAttendance/?$", change_attendance, name="change_attendance"), re_path( diff --git a/ClassLens_DB/Home/views.py b/ClassLens_DB/Home/views.py index 759216e..d2ad830 100644 --- a/ClassLens_DB/Home/views.py +++ b/ClassLens_DB/Home/views.py @@ -733,6 +733,97 @@ def teacher_subjects(request, *args, **kwargs): status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) + +@api_view(["GET", "POST"]) +def teacher_class_sessions(request, *args, **kwargs): + teacher_id = ( + request.query_params.get("teacher_id") + if request.method == "GET" + else request.data.get("teacher_id") + ) + limit = ( + request.query_params.get("limit") + if request.method == "GET" + else request.data.get("limit") + ) + + if not teacher_id: + return Response({"error": "Teacher ID is required"}, status=400) + + try: + teacher = get_object_or_404(Teacher, id=teacher_id) + + limit_value = 10 + if limit not in (None, ""): + limit_value = int(limit) + if limit_value <= 0: + limit_value = 10 + + sessions_qs = ( + ClassSession.objects.filter(teacher=teacher) + .select_related("subject", "teacher", "department") + .prefetch_related("attendancerecord_set__student__division") + .order_by("-class_datetime") + ) + + if limit_value: + sessions_qs = sessions_qs[:limit_value] + + class_sessions = [] + for session in sessions_qs: + attendance_records = list(session.attendancerecord_set.all()) + present_count = sum(1 for record in attendance_records if record.status) + total_count = len(attendance_records) + absent_count = total_count - present_count + + division_names = sorted( + { + record.student.division.name + for record in attendance_records + if record.student and record.student.division_id + } + ) + + division_name = division_names[0] if len(division_names) == 1 else None + if division_name is None: + teacher_subject = ( + TeacherSubject.objects.filter( + teacher_id=teacher, + subject_id=session.subject_id, + ) + .select_related("division") + .order_by("id") + .first() + ) + division_name = ( + teacher_subject.division.name + if teacher_subject and teacher_subject.division + else None + ) + + class_sessions.append( + { + "class_session_id": session.id, + "subject_name": session.subject.name, + "division_name": division_name or "All Divisions", + "class_datetime": session.class_datetime.isoformat(), + "present_count": present_count, + "absent_count": absent_count, + "total_count": total_count, + } + ) + + return Response({"class_sessions": class_sessions}, status=status.HTTP_200_OK) + + except ValueError: + return Response({"error": "limit must be an integer"}, status=400) + except Exception: + traceback.print_exc() + return Response( + {"detail": "Something went wrong"}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + @api_view(["POST"]) def get_present_absent_list(request, *args, **kwargs): class_session_id = request.data.get("class_session_id") From fdbcb9049e972de66085cfb21dcb9ce27b8e2067 Mon Sep 17 00:00:00 2001 From: Dhriti-5 Date: Fri, 29 May 2026 17:25:00 +0530 Subject: [PATCH 11/14] cretae endpoint for updating face id and uploading attendance result to teacher side after marking it --- ClassLens_DB/ClassLens_DB/settings.py | 1 + ClassLens_DB/DatabaseAdminApp/serializers.py | 40 +++++- ClassLens_DB/DatabaseAdminApp/tests.py | 57 +++++++++ ClassLens_DB/Home/face_utils.py | 43 +++++++ ClassLens_DB/Home/tasks.py | 6 +- ClassLens_DB/Home/urls.py | 3 +- ClassLens_DB/Home/views.py | 123 +++++++++++++------ 7 files changed, 234 insertions(+), 39 deletions(-) create mode 100644 ClassLens_DB/Home/face_utils.py diff --git a/ClassLens_DB/ClassLens_DB/settings.py b/ClassLens_DB/ClassLens_DB/settings.py index 760a60f..e8ba4da 100644 --- a/ClassLens_DB/ClassLens_DB/settings.py +++ b/ClassLens_DB/ClassLens_DB/settings.py @@ -33,6 +33,7 @@ DEBUG = True ALLOWED_HOSTS = [ + '172.16.141.247', '172.26.12.236', '10.0.2.2', '14.139.121.110', diff --git a/ClassLens_DB/DatabaseAdminApp/serializers.py b/ClassLens_DB/DatabaseAdminApp/serializers.py index 92ddd9b..bd64ab6 100644 --- a/ClassLens_DB/DatabaseAdminApp/serializers.py +++ b/ClassLens_DB/DatabaseAdminApp/serializers.py @@ -1,10 +1,12 @@ # serializers.py +from django.db import transaction from rest_framework import serializers from Home.models import ( Department, Teacher, Student, Subject, SubjectFromDept, StudentEnrollment, TeacherSubject, AdminUser, Division ) +from Home.face_utils import extract_face_embedding from .models import ( APIStudent, APIPaper, @@ -27,13 +29,49 @@ class Meta: class StudentSerializer(serializers.ModelSerializer): department_name = serializers.CharField(source='department.name', read_only=True) division_name = serializers.CharField(source='division.name', read_only=True) + photo = serializers.ImageField(write_only=True, required=False, allow_null=True) class Meta: model = Student fields = ['id', 'prn', 'name', 'email', 'password_hash', 'year', 'department', - 'department_name', 'division', 'division_name', 'face_embedding', 'notification_token'] + 'department_name', 'division', 'division_name', 'face_embedding', 'notification_token', 'photo'] extra_kwargs = {'password_hash': {'write_only': True}, 'face_embedding': {'write_only': True}} + def _apply_face_photo(self, instance, photo): + if photo is None: + return + + embedding = extract_face_embedding(photo) + instance.face_embedding = [float(value) for value in embedding] + + def create(self, validated_data): + photo = validated_data.pop('photo', None) + try: + with transaction.atomic(): + student = super().create(validated_data) + + if photo is not None: + self._apply_face_photo(student, photo) + student.save(update_fields=['face_embedding']) + + return student + except ValueError as exc: + raise serializers.ValidationError({'photo': str(exc)}) from exc + + def update(self, instance, validated_data): + photo = validated_data.pop('photo', None) + try: + with transaction.atomic(): + student = super().update(instance, validated_data) + + if photo is not None: + self._apply_face_photo(student, photo) + student.save(update_fields=['face_embedding']) + + return student + except ValueError as exc: + raise serializers.ValidationError({'photo': str(exc)}) from exc + class SubjectSerializer(serializers.ModelSerializer): class Meta: model = Subject diff --git a/ClassLens_DB/DatabaseAdminApp/tests.py b/ClassLens_DB/DatabaseAdminApp/tests.py index 7ce503c..9adbf67 100644 --- a/ClassLens_DB/DatabaseAdminApp/tests.py +++ b/ClassLens_DB/DatabaseAdminApp/tests.py @@ -1,3 +1,60 @@ +from io import BytesIO + from django.test import TestCase +from django.urls import reverse +from PIL import Image +from rest_framework.test import APIClient +from unittest.mock import patch + +from Home.models import Department, Student +from .serializers import StudentSerializer # Create your tests here. + + +class StudentFaceUpdateTests(TestCase): + def setUp(self): + self.client = APIClient() + self.department = Department.objects.create(name="Computer Science") + self.student = Student.objects.create( + prn=1001, + name="Student One", + email="student.one@example.com", + year=2, + department=self.department, + ) + + def _make_image_file(self, name="face.jpg", color=(255, 0, 0)): + image = Image.new("RGB", (8, 8), color) + buffer = BytesIO() + image.save(buffer, format="JPEG") + buffer.seek(0) + buffer.name = name + return buffer + + @patch("Home.views.extract_face_embedding", return_value=[0.1] * 512) + def test_register_student_accepts_photo_only_update(self, _mock_embedding): + response = self.client.post( + reverse("register_student"), + {"prn": self.student.prn, "photo": self._make_image_file()}, + format="multipart", + ) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data["message"], "Student face updated successfully") + self.student.refresh_from_db() + self.assertEqual(len(self.student.face_embedding), 512) + self.assertAlmostEqual(self.student.face_embedding[0], 0.1) + + @patch("DatabaseAdminApp.serializers.extract_face_embedding", return_value=[0.2] * 512) + def test_student_serializer_updates_face_from_photo(self, _mock_embedding): + serializer = StudentSerializer( + instance=self.student, + data={"photo": self._make_image_file()}, + partial=True, + ) + + self.assertTrue(serializer.is_valid(), serializer.errors) + updated_student = serializer.save() + self.assertEqual(len(updated_student.face_embedding), 512) + self.assertAlmostEqual(updated_student.face_embedding[0], 0.2) diff --git a/ClassLens_DB/Home/face_utils.py b/ClassLens_DB/Home/face_utils.py new file mode 100644 index 0000000..4c7a17f --- /dev/null +++ b/ClassLens_DB/Home/face_utils.py @@ -0,0 +1,43 @@ +try: + from deepface import DeepFace +except Exception: + DeepFace = None + +try: + from PIL import Image +except Exception: + Image = None + +import numpy as np + + +def extract_face_embedding(photo): + if not photo: + raise ValueError("No photo uploaded") + + if DeepFace is None: + raise ValueError("Face embedding dependencies are unavailable") + + if Image is None: + raise ValueError("Face image processing dependencies are unavailable") + + try: + if hasattr(photo, "seek"): + photo.seek(0) + + image = Image.open(photo) + image = image.convert("RGB") + img_arr = np.array(image) + + image_embedding = DeepFace.represent( + img_path=img_arr, + model_name="Facenet512", + detector_backend="retinaface", + enforce_detection=True, + )[0]["embedding"] + + return [float(value) for value in image_embedding] + except ValueError as exc: + raise ValueError(str(exc)) from exc + except Exception as exc: + raise ValueError(f"Face Not Detected, Upload A New Image: {exc}") from exc \ No newline at end of file diff --git a/ClassLens_DB/Home/tasks.py b/ClassLens_DB/Home/tasks.py index e32ceea..b0cabef 100644 --- a/ClassLens_DB/Home/tasks.py +++ b/ClassLens_DB/Home/tasks.py @@ -4,6 +4,7 @@ import uuid from django.conf import settings from django.http import request +from urllib.parse import urljoin import numpy as np from scipy.spatial.distance import cosine import json @@ -271,8 +272,9 @@ def evaluate_attendance(total_sessions, class_session_id: int, scheme, host, div filename = f"detected_{unique_id}.jpg" save_path = output_dir / filename cv2.imwrite(str(save_path), img_bgr) - - image_urls.append(f"{scheme}://{host}/media/images/{filename}") + + base_url = f"{scheme}://{host.rstrip('/')}" + image_urls.append(urljoin(f"{base_url}/", f"media/images/{filename}")) records_to_create = [] student_notification_list = [] diff --git a/ClassLens_DB/Home/urls.py b/ClassLens_DB/Home/urls.py index dcca9ea..b78f5df 100644 --- a/ClassLens_DB/Home/urls.py +++ b/ClassLens_DB/Home/urls.py @@ -1,7 +1,7 @@ from django.urls import path, re_path from django.urls import include -from Home.views import getDepartments,mark_attendance,teacher_profile,registerNewTeacher,validateStudent,validateTeacher,send_otp,verify_otp,set_password,get_subject_details,verify_email, verify_prn, get_student_attendance,attendance_status,teacher_subjects,teacher_class_sessions, get_present_absent_list,change_attendance,get_student_dashboard,update_notification_token,remove_notification_token, register_student, get_student_subject_attendance +from Home.views import getDepartments,mark_attendance,teacher_profile,registerNewTeacher,validateStudent,validateTeacher,send_otp,verify_otp,set_password,get_subject_details,verify_email, verify_prn, get_student_attendance,attendance_status,teacher_subjects,teacher_class_sessions, get_present_absent_list,change_attendance,get_student_dashboard,update_notification_token,remove_notification_token, register_student, get_student_subject_attendance, update_face from django.conf import settings from django.conf.urls.static import static @@ -9,6 +9,7 @@ re_path(r"^getDepartments/?$", getDepartments, name="get_departments"), re_path(r"^registerNewStudent/?$", register_student, name="register_new_student"), re_path(r"^registerStudent/?$", register_student, name="register_student"), + re_path(r"^updateFace/?$", update_face, name="update_face"), re_path(r"^registerNewTeacher/?$", registerNewTeacher, name="register_new_teacher"), re_path(r"^validateStudent/?$", validateStudent, name="validate_student"), re_path(r"^validateTeacher/?$", validateTeacher, name="validate_teacher"), diff --git a/ClassLens_DB/Home/views.py b/ClassLens_DB/Home/views.py index d2ad830..7efe5d4 100644 --- a/ClassLens_DB/Home/views.py +++ b/ClassLens_DB/Home/views.py @@ -2,22 +2,12 @@ import string from django.db.models import F from rest_framework.decorators import api_view, parser_classes,permission_classes -# defer heavy/optional imports so Django can run management commands without GPU/deep libs -try: - from deepface import DeepFace -except Exception: - DeepFace = None -try: - from PIL import Image -except Exception: - Image = None -import numpy as np from rest_framework.response import Response from .models import Department, Student, Teacher, SubjectFromDept, StudentAttendancePercentage,AttendanceRecord, StudentEnrollment,TeacherSubject, ClassSession, Subject,AttendancePhotos,AdminUser, Division from django.db.models import Count, Q from .serializers import DepartmentSerializer,SubjectSerializer from rest_framework.parsers import MultiPartParser -from rest_framework_simplejwt.tokens import RefreshToken +from rest_framework_simplejwt.tokens import RefreshToken, AccessToken from django.contrib.auth.hashers import make_password, check_password from django.shortcuts import get_object_or_404 import traceback @@ -38,6 +28,8 @@ import matplotlib.pyplot as plt except Exception: plt = None + +from .face_utils import extract_face_embedding import uuid from .tasks import evaluate_attendance, send_attendance_notifications from django.core.files.storage import default_storage @@ -121,8 +113,20 @@ def validateStudent(request, *args, **kwargs): {"detail": "Invalid password"}, status=status.HTTP_400_BAD_REQUEST ) else: + # Issue a simple JWT-like token so frontend can authenticate subsequent requests + refresh = RefreshToken() + refresh['student_id'] = student.id + refresh['prn'] = student.prn + return Response( - {"message": "Student validated successfully", "student_id": student.id, 'student_name': student.name, 'prn': student.prn}, + { + "message": "Student validated successfully", + "student_id": student.id, + "student_name": student.name, + "prn": student.prn, + "access": str(refresh.access_token), + "refresh": str(refresh), + }, status=status.HTTP_200_OK, ) except Student.DoesNotExist: @@ -414,13 +418,11 @@ def _update_student_password(prn, password, photo): if photo is not None: try: - embedding = registerNewStudent(photo) - if isinstance(embedding, Exception): - raise Exception("Face embedding error: " + str(embedding)) + embedding = extract_face_embedding(photo) student.face_embedding = [float(value) for value in embedding] - except Exception: + except ValueError as exc: return Response( - {"error": "Face Not Detected, Upload A New Image"}, + {"error": str(exc)}, status=status.HTTP_400_BAD_REQUEST, ) @@ -483,29 +485,80 @@ def register_student(request, *args, **kwargs): prn = request.data.get("prn") password = request.data.get("password") photo = request.FILES.get("photo") + + if password is None and photo is not None: + student = Student.objects.filter(prn=prn).first() + if not student: + return Response( + {"detail": "No Student found with this prn"}, + status=status.HTTP_404_NOT_FOUND, + ) + + try: + embedding = extract_face_embedding(photo) + student.face_embedding = [float(value) for value in embedding] + student.save(update_fields=["face_embedding"]) + return Response({"message": "Student face updated successfully"}, status=200) + except ValueError as exc: + return Response({"error": str(exc)}, status=status.HTTP_400_BAD_REQUEST) + return _update_student_password(prn, password, photo) def registerNewStudent(photo): + return extract_face_embedding(photo) - if not photo: - return Response( - {"error": "No photo uploaded"}, status=status.HTTP_400_BAD_REQUEST - ) +@api_view(["POST"]) +def update_face(request, *args, **kwargs): + """POST /api/updateFace/ - multipart/form-data: prn, photo + + Updates only the student's `face_embedding` without changing password or other fields. + """ try: - image = Image.open(photo) - image = image.convert("RGB") - img_arr = np.array(image) - image_embedding = DeepFace.represent( - img_path=img_arr, - model_name="Facenet512", - detector_backend="retinaface", - enforce_detection=True, - )[0]["embedding"] - - return [float(value) for value in image_embedding] - except ValueError as ve: - return ValueError(ve) + # Prefer authenticated student identity if provided via Bearer token + prn = None + auth_header = request.META.get('HTTP_AUTHORIZATION') or request.headers.get('Authorization') + if auth_header: + parts = auth_header.split() + if len(parts) == 2 and parts[0].lower() == 'bearer': + token = parts[1] + try: + payload = AccessToken(token) + prn = payload.get('prn') or payload.get('student_prn') or payload.get('student_id') + # If student_id found, map to prn + if isinstance(prn, int) and not payload.get('prn'): + # prn may be student id - fetch actual prn + student_obj = Student.objects.filter(id=prn).first() + if student_obj: + prn = student_obj.prn + except Exception: + prn = None + + if prn is None: + prn = request.POST.get("prn") or request.data.get("prn") + photo = request.FILES.get("photo") + + if prn is None: + return Response({"detail": "prn is required"}, status=status.HTTP_400_BAD_REQUEST) + + if photo is None: + return Response({"detail": "photo file is required"}, status=status.HTTP_400_BAD_REQUEST) + + student = Student.objects.filter(prn=prn).first() + if not student: + return Response({"detail": "No Student found with this prn"}, status=status.HTTP_404_NOT_FOUND) + + try: + embedding = extract_face_embedding(photo) + student.face_embedding = [float(value) for value in embedding] + student.save(update_fields=["face_embedding"]) + return Response({"message": "Student face updated successfully"}, status=200) + except ValueError as exc: + return Response({"error": str(exc)}, status=status.HTTP_400_BAD_REQUEST) + + except Exception as e: + traceback.print_exc() + return Response({"detail": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @api_view(["POST"]) def get_student_attendance(request, *args, **kwargs): @@ -673,7 +726,7 @@ def mark_attendance(request, *args, **kwargs): total_sessions, class_session.id, request.scheme, - "14.139.121.110:11020", + request.get_host(), resolved_division_id, ) From db1a4247aea300c62a01250dc2b615faa0797cf3 Mon Sep 17 00:00:00 2001 From: Dhriti-5 Date: Wed, 3 Jun 2026 10:51:33 +0530 Subject: [PATCH 12/14] Update gitignore and remove local files from tracking --- .gitignore | 9 + DATABASE_SCHEMA.md | 683 -------------------- DBMSUIS_V7.sql | Bin 129752 -> 0 bytes DBMSUIS_V7_utf8.sql | 1335 ---------------------------------------- RABBITMQ_MIGRATION.md | 57 -- data-1778222711514.csv | 103 ---- db-chat.txt | 132 ---- setup_backend.bat | 85 --- 8 files changed, 9 insertions(+), 2395 deletions(-) delete mode 100644 DATABASE_SCHEMA.md delete mode 100644 DBMSUIS_V7.sql delete mode 100644 DBMSUIS_V7_utf8.sql delete mode 100644 RABBITMQ_MIGRATION.md delete mode 100644 data-1778222711514.csv delete mode 100644 db-chat.txt delete mode 100644 setup_backend.bat diff --git a/.gitignore b/.gitignore index 1db6aaa..51b01c6 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,15 @@ test_sync_endpoint.py # Local schema/docs New_schema +data-1778222711514.csv +API_ENDPOINTS.md +ARCHITECTURE_RULES.md +DATABASE_SCHEMA.md +db-chat.txt +DBMSUIS_V7_utf8.sql +DBMSUIS_V7.sql +RABBITMQ_MIGRATION.md +setup_backend.bat # Python virtual env .venv/ diff --git a/DATABASE_SCHEMA.md b/DATABASE_SCHEMA.md deleted file mode 100644 index b6390e2..0000000 --- a/DATABASE_SCHEMA.md +++ /dev/null @@ -1,683 +0,0 @@ -# ClassLens Attendance Tracking Database Schema - -## Overview - -ClassLens uses a **focused database architecture optimized for attendance tracking**. Students can view their attendance grouped by divisions, subjects, semesters, years, and departments. - -``` -┌─────────────────────────────────────┐ -│ MSUIS External API │ -│ (Faculty, Student, Subject) │ -│ (Enrollment & Division Info) │ -└──────────────┬──────────────────────┘ - │ (Sync Payload) - ▼ -┌──────────────────────────────────────────┐ -│ LAYER 1: ENROLLMENT DATA (Mirror) │ -│ (Enrollment & Division mapping only) │ -├──────────────────────────────────────────┤ -│ • APIEnrollment (student-subject-div) │ -└──────────────┬───────────────────────────┘ - │ (Project to Core) - ▼ -┌──────────────────────────────────────────┐ -│ LAYER 2: ATTENDANCE CORE TABLES │ -│ (Attendance tracking & statistics) │ -├──────────────────────────────────────────┤ -│ • Department │ -│ • Student │ -│ • Subject │ -│ • Division │ -│ • StudentEnrollment │ -│ • Teacher │ -│ • TeacherSubject │ -│ • ClassSession │ -│ • AttendanceRecord │ -│ • StudentAttendancePercentage │ -│ • AdminUser │ -└──────────────────────────────────────────┘ -``` - ---- - -## Layer 1: Enrollment Data Mirror (Simplified) - -This minimal mirror table stores enrollment data from MSUIS used to sync divisions and student enrollments. Focus is on attendance information only. - -### 1. APIEnrollment — Student Enrollment with Division & Semester - -**Location:** `DatabaseAdminApp/models.py` - -```python -class APIEnrollment(models.Model): - """Mirrors student enrollment with division and semester info from MSUIS.""" - prn = models.BigIntegerField(db_index=True) - subject_code = models.CharField(max_length=100) - department_name = models.CharField(max_length=200) - program_name = models.CharField(max_length=200) - year = models.IntegerField() - semester = models.IntegerField() - division = models.CharField(max_length=20) # A, B, C, etc. - raw_payload = models.JSONField(default=dict) - synced_at = models.DateTimeField(auto_now=True) - - class Meta: - unique_together = ('prn', 'subject_code', 'division', 'semester') -``` - -| Field | Type | Purpose | -|-------|------|---------| -| `prn` | BigInt (indexed) | Student PRN | -| `subject_code` | Char(100) | Subject code (e.g., "CS101") | -| `department_name` | Char(200) | Department name | -| `program_name` | Char(200) | Program/degree name | -| `year` | Int | Student year (1, 2, 3, 4) | -| `semester` | Int | Semester (1-8) | -| `division` | Char(20) | Division code (A, B, C, etc.) | -| `raw_payload` | JSON | Original API data | -| `synced_at` | DateTime | Last sync timestamp | - -**Why needed:** -- Store enrollment info with division and semester -- Minimal data for division and enrollment creation in core tables -- No academic grades, marks, or specialized fields -- Focus purely on attendance grouping - -**Example data:** -``` -prn: 2021001 -subject_code: "CS101" -department_name: "Department of Computer Science" -program_name: "B.E Computer Science" -year: 2 -semester: 3 -division: "A" -synced_at: 2026-05-11 12:00:00 -``` - ---- - -## Layer 2: Core Attendance Tracking Tables (Home App) - -These tables are **optimized for attendance tracking**. They contain only the essential data for recording and displaying attendance by divisions, subjects, semesters, years, and departments. - -### 6. Department — Core Department Entity - -**Location:** `Home/models.py` - -```python -class Department(models.Model): - name = models.TextField(unique=True, null=False) -``` - -| Field | Type | Purpose | -|-------|------|---------| -| `id` | AutoInt (PK) | Unique identifier | -| `name` | Text (unique) | Department name; must be unique | - -**Source:** Created from `APIFaculty.name` during MSUIS sync -**Purpose:** Core reference for all department-related data in ClassLens -**Example:** -``` -id: 10 -name: "Department of Computer Science" -``` - ---- - -### 7. Student — Core Student Entity - -**Location:** `Home/models.py` - -```python -class Student(models.Model): - prn = models.BigIntegerField(unique=True, null=False) - name = models.TextField(null=False) - email = models.EmailField(unique=True, null=False) - password_hash = models.TextField(null=True, blank=True) - year = models.IntegerField(null=False) - department = models.ForeignKey(Department, on_delete=models.CASCADE) - face_embedding = VectorField(dimensions=512, null=True, blank=True) - notification_token = models.TextField(null=True, blank=True) -``` - -| Field | Type | Purpose | -|-------|------|---------| -| `prn` | BigInt (unique) | Student PRN; primary identifier | -| `name` | Text | Full student name | -| `email` | Email (unique) | Student email for login | -| `password_hash` | Text | Hashed password for authentication | -| `year` | Int | Academic year (1, 2, 3, 4) | -| `department` | FK to Department | Department enrollment | -| `face_embedding` | Vector(512) | Face recognition during attendance photo processing | -| `notification_token` | Text | Firebase FCM token for push notifications | - -**Source:** Created/updated from `APIEnrollment` during sync -**Purpose:** Core student entity for attendance tracking -**Example:** -``` -prn: 2021001 -name: "John Kumar Singh" -email: "john@example.com" -year: 2 -department_id: 10 -``` - ---- - -### 8. Subject — Course/Paper Entity - -**Location:** `Home/models.py` - -```python -class Subject(models.Model): - code = models.TextField(unique=True, null=False) - name = models.TextField(null=False) - department = models.ForeignKey(Department, on_delete=models.CASCADE) -``` - -| Field | Type | Purpose | -|-------|------|---------| -| `id` | AutoInt (PK) | Unique identifier | -| `code` | Text (unique) | Subject code (e.g., "CS101") | -| `name` | Text | Subject name (e.g., "Data Structures") | -| `department` | FK to Department | Department offering this subject | - -**Source:** Extracted from `APIEnrollment` during sync -**Purpose:** Defines subjects for attendance tracking -**Example:** -``` -id: 50 -code: "CS101" -name: "Data Structures and Algorithms" -department_id: 10 -``` - ---- - -### 9. Division — ⭐ NEW — Teaching Division Classification - -**Location:** `Home/models.py` - -```python -class Division(models.Model): - department = models.ForeignKey(Department, on_delete=models.CASCADE) - program_name = models.TextField(null=False, default="") - year = models.IntegerField(null=False) - semester = models.IntegerField(null=False) - name = models.CharField(max_length=20, null=False) - - class Meta: - unique_together = ("department", "program_name", "year", "semester", "name") -``` - -| Field | Type | Purpose | -|-------|------|---------| -| `id` | AutoInt (PK) | Unique identifier | -| `department` | FK to Department | Which department offers this division | -| `program_name` | Text | Degree program name (e.g., "B.E Computer Science") | -| `year` | Int | Academic year (1, 2, 3, 4) | -| `semester` | Int | Semester (1-8, where 1-2=year1, 3-4=year2, etc.) | -| `name` | Char(20) | Division code (A, B, C, D, etc.) | - -**Why this table was added:** -- **Requirement**: Group students by division for attendance tracking -- Students in the same division attend the same class sessions together -- Teachers mark attendance per division -- Each division can have separate schedules/teachers - -**Uniqueness constraint:** `(department, program_name, year, semester, name)` ensures no duplicates like "CSE B.E 2nd year Sem 3 Division A" - -**Example data:** -``` -id: 1 -department_id: 10 -program_name: "B.E Computer Science" -year: 2 -semester: 3 -name: "A" - -id: 2 -department_id: 10 -program_name: "B.E Computer Science" -year: 2 -semester: 3 -name: "B" -``` - -This creates two parallel divisions (A and B) for the same year/semester, allowing independent attendance tracking. - ---- - -### 10. StudentEnrollment — Student-Subject-Division Mapping - -**Location:** `Home/models.py` - -```python -class StudentEnrollment(models.Model): - student_prn = models.BigIntegerField(null=False) - subject = models.ForeignKey(Subject, on_delete=models.CASCADE) - division = models.ForeignKey(Division, on_delete=models.CASCADE) - - class Meta: - unique_together = ('student_prn', 'subject', 'division') -``` - -| Field | Type | Purpose | -|-------|------|---------| -| `student_prn` | BigInt | Student's PRN | -| `subject` | FK to Subject | Enrolled subject | -| `division` | FK to Division | Division (A, B, C, etc.) | - -**Source:** Created from `APIEnrollment` during sync -**Purpose:** Track which students are enrolled in which subjects within specific divisions -**Example:** -``` -student_prn: 2021001, subject_id: 50, division_id: 1 # John in CS101, Division A -student_prn: 2021001, subject_id: 51, division_id: 1 # John in CS102, Division A -``` - ---- - -### 11. TeacherSubject — Teacher-Subject Mapping - -**Location:** `Home/models.py` - -```python -class TeacherSubject(models.Model): - teacher_id = models.ForeignKey(Teacher, on_delete=models.CASCADE) - subject = models.ForeignKey(Subject, on_delete=models.CASCADE) - - class Meta: - unique_together = ('teacher_id', 'subject') -``` - -**Purpose:** Track which teacher teaches which subject -**Example:** -``` -teacher_id: 5, subject_id: 50 # Dr. Smith teaches CS101 -``` - ---- - -### 12. ClassSession — ⭐ MODIFIED — Attendance Session Record - -**Location:** `Home/models.py` - -```python -class ClassSession(models.Model): - department = models.ForeignKey(Department, on_delete=models.CASCADE) - year = models.IntegerField(null=False) - subject = models.ForeignKey(Subject, on_delete=models.CASCADE) - teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE) - division = models.ForeignKey(Division, on_delete=models.SET_NULL, null=True, blank=True) # ⭐ NEW - class_datetime = models.DateTimeField(null=False) -``` - -| Field | Type | Purpose | -|-------|------|---------| -| `id` | AutoInt (PK) | Unique session identifier | -| `department` | FK to Department | Which department | -| `year` | Int | Student year | -| `subject` | FK to Subject | Subject taught | -| `teacher` | FK to Teacher | Teacher who taught | -| `division` | FK to Division | ⭐ **NEW** — Which division attended | -| `class_datetime` | DateTime | When the class happened | - -**Why `division` field was added:** -- **Before:** Couldn't distinguish "Class of CS101 for Div A" from "Class of CS101 for Div B" -- **After:** Can track separate class sessions for each division -- When teacher marks attendance, they specify division -- Attendance only applies to that division's students - -**Example:** -``` -ClassSession 1: - subject_id: 50 (CS101) - teacher_id: 5 (Dr. Smith) - division_id: 1 (CSE B.E 2nd year Sem 3 Div A) - class_datetime: 2026-05-11 10:00 AM - -ClassSession 2: - subject_id: 50 (CS101) - teacher_id: 5 (Dr. Smith) - division_id: 2 (CSE B.E 2nd year Sem 3 Div B) - class_datetime: 2026-05-11 12:00 PM -``` - ---- - -### 13. AttendanceRecord — Individual Student Attendance - -**Location:** `Home/models.py` - -```python -class AttendanceRecord(models.Model): - class_session = models.ForeignKey(ClassSession, on_delete=models.CASCADE) - student = models.ForeignKey(Student, on_delete=models.CASCADE) - status = models.BooleanField() # True = Present, False = Absent - marked_at = models.DateTimeField(auto_now_add=True) - - class Meta: - unique_together = ('class_session', 'student') -``` - -**Purpose:** One record per student per class session -**Example:** -``` -class_session_id: 1 -student_id: 1001 -status: True # Student was present -marked_at: 2026-05-11 10:30 AM -``` - ---- - -### 14. StudentAttendancePercentage — Aggregated Per-Subject Attendance - -**Location:** `Home/models.py` - -```python -class StudentAttendancePercentage(models.Model): - student = models.ForeignKey(Student, on_delete=models.CASCADE) - subject = models.ForeignKey(Subject, on_delete=models.CASCADE) - present_count = models.IntegerField(null=False, default=0) - attendancePercentage = models.FloatField(null=False, default=0.0) -``` - -| Field | Type | Purpose | -|-------|------|---------| -| `student` | FK to Student | Which student | -| `subject` | FK to Subject | For which subject | -| `present_count` | Int | Number of classes attended | -| `attendancePercentage` | Float | (present_count / total_classes) * 100 | - -**Purpose:** Quick lookup of per-subject attendance without recalculating -**Used by:** Student dashboard to show per-subject attendance breakdown -**Example:** -``` -student_id: 1001 -subject_id: 50 -present_count: 17 -attendancePercentage: 85.0 # (17 / 20) * 100 -``` - ---- - -### 15. Teacher — Existing Core Table - -**Location:** `Home/models.py` - -```python -class Teacher(models.Model): - name = models.TextField(null=False) - email = models.EmailField(unique=True, null=False) - password_hash = models.TextField(null=True) - department = models.ForeignKey(Department, on_delete=models.CASCADE) - date_joined = models.DateField(null=True, auto_now_add=True) -``` - -**Purpose:** Core teacher entity for ClassLens -**No changes in this release** - ---- - -### 16. AdminUser — Admin Authentication - -**Location:** `Home/models.py` - -```python -class AdminUser(models.Model): - username = models.CharField(max_length=150, unique=True) - password = models.CharField(max_length=128) - is_active = models.BooleanField(default=True) - created_at = models.DateTimeField(auto_now_add=True) - - @property - def is_authenticated(self): - return True -``` - -**Purpose:** Admin users for managing MSUIS sync and system configuration - ---- - -## Data Flow: Attendance-Only Sync Workflow - -### Scenario: Sync 1 student enrolled in 2 subjects in Division A - -#### Input: Enrollment API Payload - -```json -{ - "enrollments": [ - { - "prn": 2021001, - "subject_code": "CS101", - "department_name": "Department of Computer Science", - "program_name": "B.E Computer Science", - "year": 2, - "semester": 3, - "division": "A" - }, - { - "prn": 2021001, - "subject_code": "CS102", - "department_name": "Department of Computer Science", - "program_name": "B.E Computer Science", - "year": 2, - "semester": 3, - "division": "A" - } - ], - "apply_to_core": true -} -``` - -#### Step 1: Mirror Storage (APIEnrollment) - -**APIEnrollment table (2 records):** -``` -prn: 2021001 -subject_code: "CS101" -department_name: "Department of Computer Science" -program_name: "B.E Computer Science" -year: 2 -semester: 3 -division: "A" -synced_at: 2026-05-11 12:00:00 - -prn: 2021001 -subject_code: "CS102" -department_name: "Department of Computer Science" -program_name: "B.E Computer Science" -year: 2 -semester: 3 -division: "A" -synced_at: 2026-05-11 12:00:00 -``` - -#### Step 2: Core Table Projection (When apply_to_core=true) -programme_name: "B.E Computer Science" -part_term_status: "Active" -``` - -**APIStudentPartTermPaperMap table (2 records):** -``` -msuis_id: 1000, prn: 2021001, paper_id: 50, division: "A" -msuis_id: 1001, prn: 2021001, paper_id: 51, division: "A" -``` - -#### Step 2: Projection → Core Operational Tables - -**Department table (if not exists):** -``` -id: 10 -name: "Department of Computer Science" -``` - -**Student table (create/update):** -``` -prn: 2021001 -name: "John Kumar Singh" # Merged from first/middle/last -email: "john.singh@example.com" -year: 2 -department_id: 10 -``` - -**Subject table (2 records, if not exist):** -``` -id: 50, code: "CS101", name: "Data Structures" -id: 51, code: "CS102", name: "Algorithms" -``` - -**Division table (create/update):** -``` -id: 1 -department_id: 10 -program_name: "B.E Computer Science" -year: 2 -semester: 3 -name: "A" -``` - -**StudentEnrollment table (2 records):** -``` -student_prn: 2021001, subject_id: 50, division_id: 1 -student_prn: 2021001, subject_id: 51, division_id: 1 -``` - -**StudentAttendancePercentage table (2 records, initialized):** -``` -student_id: 1001, subject_id: 50, present_count: 0, attendancePercentage: 0.0 -student_id: 1001, subject_id: 51, present_count: 0, attendancePercentage: 0.0 -``` - ---- - -## Why Two Layers? - -| Aspect | Mirror Layer | Core Layer | -|--------|--------------|-----------| -| **Purpose** | Store enrollment data from API exactly | Track attendance and display to students | -| **Data Retention** | Keep enrollment records | Keep attendance records and metrics | -| **Transformations** | None—raw API data | Normalized enrollments + attendance aggregations | -| **Update Pattern** | Upsert (idempotent) | Insert attendance records, update percentages | -| **Key Focus** | Enrollment data (student-subject-division) | Attendance metrics (present%, per-subject, per-division) | -| **Access Pattern** | Historical sync lookup | Real-time attendance dashboard queries | - -### Real-world Scenario: - -1. API sends enrollment: PRN 2021001 in CS101 Division A Semester 3 -2. Mirror table (APIEnrollment) stores exactly as received -3. Core creates: Student, Subject, Division, StudentEnrollment -4. Teacher marks attendance for 20 classes of this division -5. Student dashboard shows: "Overall: 85%, CS101: 85%, CS102: 90%" - ---- - -## Summary of Attendance-Focused Architecture - -### Core Purpose -**Track and display student attendance by division, subject, semester, year, and department** - -### Key Components - -**Mirror Layer (DatabaseAdminApp):** -- APIEnrollment — Stores enrollment data with division and semester info - -**Core Layer (Home app):** -- Division — Groups students by year, semester, program, department -- StudentEnrollment — Links student to subject + division -- ClassSession — Records when a class session occurs (per division) -- AttendanceRecord — Individual student attendance in each session -- StudentAttendancePercentage — Computed per-subject attendance % - -**Data Flow:** -1. Admin syncs enrollments via `POST /api/admin/sync/msuis/` -2. API data stored in APIEnrollment mirror table -3. Core tables auto-created/updated (Division, Student, Subject, StudentEnrollment) -4. Teachers use app to mark attendance (upload class photos) -5. System recognizes faces and marks attendance in AttendanceRecord -6. StudentAttendancePercentage automatically computed -7. Students see dashboard: Overall attendance + per-subject breakdown + by division/semester/year - ---- - -## Database Diagrams - -### Entity Relationship: Core Layer - -``` -Department - ├─ Student - ├─ Teacher - ├─ Subject - │ ├─ TeacherSubject - │ └─ StudentEnrollment - └─ Division - └─ ClassSession - ├─ AttendanceRecord - │ └─ Student - └─ AttendancePhotos -``` - -### Data Flow: API → Mirror → Core - -``` -MSUIS API - ↓ -APIFaculty, APIStudent, APIPaper, APIStudentAcademicInformation, APIStudentPartTermPaperMap - ↓ (Projection with apply_to_core=true) -Department, Student, Subject, Division, StudentEnrollment - ↓ -ClassSession → AttendanceRecord → StudentAttendancePercentage -``` - ---- - -## Indexing Strategy - -- **APIStudent.prn**: Primary key, used for lookups -- **APIStudentAcademicInformation.prn**: Indexed for joins -- **APIStudentPartTermPaperMap.prn**: Indexed for lookups -- **Student.face_embedding**: HNSW vector index for face recognition similarity search -- **AttendanceRecord**: Unique constraint (class_session, student) -- **StudentEnrollment**: Unique constraint (student_prn, subject) - ---- - -## Access Patterns - -### Admin Operations -``` -POST /api/admin/sync/msuis/ → Populates all mirror tables → Projects to core tables -GET /api/admin/divisions/ → Lists Division records -``` - -### Teacher Operations -``` -POST /api/markAttendance → Creates ClassSession with division → Creates AttendanceRecords -GET /api/teacher/subjects/ → Lists Teacher's subjects via TeacherSubject -``` - -### Student Operations -``` -POST /api/student/dashboard/ → Queries: - - Student by prn - - StudentEnrollment by student_prn - - StudentAttendancePercentage per subject - - AttendanceRecord recent activity -``` - ---- - -## Notes - -1. **Mirror tables use MSUIS IDs as primary keys** — ensures idempotent upserts during sync -2. **Core tables use auto-increment IDs** — standard ClassLens references -3. **Division is unique by (dept, program, year, semester, name)** — prevents duplicates -4. **StudentAttendancePercentage is computed** — updated when attendance is marked -5. **face_embedding uses pgvector** — enables similarity-based student identification during attendance photo processing -6. **RABBITMQ_URL required in .env** — settings.py imports it at module load time - diff --git a/DBMSUIS_V7.sql b/DBMSUIS_V7.sql deleted file mode 100644 index e4001424db19e4147e3063b3801e4e21901ad023..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 129752 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 ZlhL5$0CcXvpXt2%)#}&$)ZDYB{{JJMBJcnJ diff --git a/DBMSUIS_V7_utf8.sql b/DBMSUIS_V7_utf8.sql deleted file mode 100644 index 3e7cb13..0000000 --- a/DBMSUIS_V7_utf8.sql +++ /dev/null @@ -1,1335 +0,0 @@ -USE [MSUISv7_0] -GO -/****** Object: Table [dbo].[IncAcademicYear] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncAcademicYear]( - [Id] [int] NOT NULL, - [AcademicYearCode] [nvarchar](20) NOT NULL, - [SequenceNo] [int] NULL, - [FromDate] [datetime] NULL, - [ToDate] [datetime] NULL, - [IsOpen] [bit] NULL, - [IsActive] [bit] NULL, - [IsDeleted] [bit] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [CancellationFeeRefundEndDate] [datetime] NULL, - [AdmissionEndDate] [datetime] NULL, - [IsCurrentYear] [bit] NULL, - [IsDSWApplicationStart] [bit] NULL, - [DSWStartDate] [datetime] NULL, - [DSWEndDate] [datetime] NULL, - [DSWApplicationFee] [decimal](7, 2) NULL, - [DSWYearlyBudget] [decimal](10, 2) NULL, - CONSTRAINT [PK_IncAcademicYear] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncInstitutePartTermPaperMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncInstitutePartTermPaperMap]( - [Id] [bigint] NOT NULL, - [InstituteId] [int] NOT NULL, - [ProgInstPartTermId] [bigint] NOT NULL, - [PartTermPaperMapId] [bigint] NOT NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_IncInstitutePartTermPaperMap] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncPreferanceGroupMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncPreferanceGroupMap]( - [Id] [bigint] NOT NULL, - [PreferenceId] [int] NOT NULL, - [GroupId] [bigint] NOT NULL, - [ProgrammeInstancePartTermId] [bigint] NOT NULL, - [IsActive] [bit] NULL, - [IsDeleted] [bit] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_IncPreferanceGroupMap] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncProgInstPartTermPaperMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncProgInstPartTermPaperMap]( - [Id] [bigint] NOT NULL, - [ProgrammeInstancePartTermId] [bigint] NOT NULL, - [PaperId] [bigint] NOT NULL, - [GroupId] [bigint] NULL, - [IsActive] [bit] NULL, - [IsDelete] [bit] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_IncProgInstPartTermPaperMap] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncProgrammeInstance] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncProgrammeInstance]( - [Id] [bigint] NOT NULL, - [ProgrammeId] [int] NOT NULL, - [AcademicYearId] [int] NOT NULL, - [FacultyId] [int] NOT NULL, - [InstanceName] [nvarchar](500) NOT NULL, - [Intake] [int] NULL, - [AdmissionRight] [nvarchar](50) NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_IncProgrammeInstance] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncProgrammeInstancePart] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncProgrammeInstancePart]( - [Id] [bigint] NOT NULL, - [InstancePartName] [nvarchar](1000) NULL, - [ProgrammeInstanceId] [bigint] NOT NULL, - [ProgrammePartId] [int] NOT NULL, - [MaxMarks] [int] NULL, - [MinMarks] [int] NULL, - [IsSeparatePassingHead] [bit] NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [IsAllowPaperSelByStudent] [bit] NULL, - [AcademicYearId] [int] NULL, - CONSTRAINT [PK_AdmProgramInstancePart] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncProgrammeInstancePartTerm] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncProgrammeInstancePartTerm]( - [Id] [int] NOT NULL, - [InstancePartTermName] [nvarchar](max) NULL, - [ProgrammeBranchMapId] [int] NOT NULL, - [SpecialisationId] [int] NOT NULL, - [ProgrammePartId] [int] NOT NULL, - [ProgrammeInstancePartId] [bigint] NOT NULL, - [ProgrammePartTermId] [int] NOT NULL, - [FacultyId] [int] NOT NULL, - [ProgrammeId] [int] NOT NULL, - [AcademicYearId] [int] NOT NULL, - [ProgrammeInstanceId] [bigint] NOT NULL, - [MinPapers] [int] NOT NULL, - [MaxPapers] [int] NOT NULL, - [MinMarks] [int] NULL, - [MaxMarks] [int] NULL, - [IsForApplication] [bit] NULL, - [IsForAdmission] [bit] NULL, - [Intake] [int] NULL, - [InstanceYearId] [int] NULL, - [IsSeparatePassingHead] [bit] NULL, - [IsLaunch] [bit] NULL, - [LaunchedBy] [bigint] NULL, - [LaunchedOn] [datetime] NULL, - [UnLaunchedBy] [bigint] NULL, - [UnLaunchedOn] [datetime] NULL, - [IsVerify] [bit] NULL, - [VerifiedBy] [bigint] NULL, - [StructureReportRemark] [nvarchar](max) NULL, - [IsApprovedStructureReport] [bit] NULL, - [ApprovedStructureReportBy] [bigint] NULL, - [ApprovedStructureReportOn] [datetime] NULL, - [AssessmentReportRemark] [nvarchar](max) NULL, - [IsApprovedAssessmentReport] [bit] NULL, - [ApprovedAssessmentReportBy] [bigint] NULL, - [ApprovedAssessmentReportOn] [datetime] NULL, - [VerifiedOn] [datetime] NULL, - [IsAssessmentLaunched] [bit] NULL, - [AssessmentLaunchedBy] [bigint] NULL, - [AssessmentLaunchedOn] [datetime] NULL, - [IsAssessmentVerified] [bit] NULL, - [AssessmentVerifiedBy] [bigint] NULL, - [AssessmentVerifiedOn] [datetime] NULL, - [IsCentrallyAdmission] [bit] NULL, - [IsCompleted] [bit] NULL, - [CompletedBy] [bigint] NULL, - [CompletedOn] [datetime] NULL, - [IsCompletedAssessment] [bit] NULL, - [AssessmentCompletedBy] [bigint] NULL, - [AssessmentCompletedOn] [datetime] NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [IsPaperSelByStudent] [bit] NULL, - [IsPaperSelBeforeFees] [bit] NULL, - [IsPreferenceRequired] [bit] NULL, - [IsAdmThroughGCAS] [bit] NULL, - [IsPrerequisiteRequired] [bit] NULL, - CONSTRAINT [PK_MstProgramInstancePartTerm] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncProgrammeInstancePartTermPaperGroup] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup]( - [Id] [bigint] NOT NULL, - [ProgrammeInstancePartTermId] [bigint] NOT NULL, - [MstPartTermGroupId] [bigint] NOT NULL, - [ContainsSubgroup] [bit] NOT NULL, - [IsSubGroup] [bit] NULL, - [ParentGroupId] [bigint] NULL, - [MinPapers] [int] NULL, - [MaxPapers] [int] NULL, - [MinSubgroup] [int] NULL, - [MaxSubgroup] [int] NULL, - [SeparatePassingHead] [bit] NULL, - [MinMarks] [int] NULL, - [MaxMarks] [int] NULL, - [MinCredits] [decimal](5, 2) NULL, - [MaxCredits] [decimal](5, 2) NULL, - [IsActive] [bit] NULL, - [IsDeleted] [bit] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_MstProgrammeInstancePaperGroup] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncStudentAcademicInformation] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncStudentAcademicInformation]( - [Id] [bigint] NOT NULL, - [PRN] [bigint] NOT NULL, - [StudentAdmissionId] [bigint] NOT NULL, - [ProgrammeInstancePartId] [bigint] NULL, - [ProgrammeInstancePartTermId] [bigint] NOT NULL, - [ProgrammeId] [int] NOT NULL, - [SpecialisationId] [int] NOT NULL, - [AcademicYearId] [int] NOT NULL, - [InstituteId] [int] NOT NULL, - [FacultyId] [int] NOT NULL, - [AdmissionFeeCategoryId] [int] NULL, - [AdmissionFeeCategoryPartTermMapId] [bigint] NULL, - [PreferenceGroupId] [int] NULL, - [AdmissionCommitteeId] [int] NULL, - [AllotmentNo] [nvarchar](50) NULL, - [MeritNo] [nvarchar](50) NULL, - [PartTermStatus] [nvarchar](50) NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [IsDeleted] [bit] NULL, - [PartStatus] [nvarchar](50) NULL, - [CancelForReAdmission] [bit] NULL, - [IsMarkedAsTransfered] [bit] NULL, - [IsEligibleForDegree] [bit] NULL, - [IsLateral] [bit] NULL, - [IsExempted] [bit] NULL, - [DegreeExamEventId] [int] NULL, - [IsAdmissionCancelled] [bit] NULL, - [ExamMasterId] [int] NULL, - CONSTRAINT [PK_IncStudentAcademicInformation] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncStudentAdmission] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncStudentAdmission]( - [Id] [bigint] NOT NULL, - [PRN] [bigint] NOT NULL, - [ProgrammeInstancePartId] [bigint] NOT NULL, - [ProgrammeInstancePartTermId] [bigint] NOT NULL, - [ProgrammeId] [int] NOT NULL, - [SpecialisationId] [int] NOT NULL, - [AcademicYearId] [int] NOT NULL, - [InstituteId] [int] NOT NULL, - [FacultyId] [int] NOT NULL, - [AdmissionFeeCategoryId] [int] NOT NULL, - [AdmissionFeeCategoryPartTermMapId] [bigint] NOT NULL, - [EligibilityByFaculty] [nvarchar](500) NULL, - [ApprovedByFaculty] [bigint] NULL, - [ApprovedOnFaculty] [datetime] NULL, - [AdminRemarkByFaculty] [nvarchar](3000) NULL, - [EligibilityByAcademics] [nvarchar](100) NULL, - [ApprovedByAcademics] [bigint] NULL, - [ApprovedOnAcademics] [datetime] NULL, - [AdminRemarkByAcademics] [nvarchar](3000) NULL, - [AdmissionStatus] [nvarchar](50) NULL, - [IsDualAdmission] [bit] NULL, - [DualAdmissionDoc] [nvarchar](3000) NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [IsDeleted] [bit] NULL, - [IsTransferAdmission] [bit] NULL, - [TransferAdmissionRemarksByFaculty] [nvarchar](3000) NULL, - [TransferAdmissionRemarksByAcademic] [nvarchar](3000) NULL, - [TransferAdmissionDoc] [nvarchar](3000) NULL, - [CancelForReAdmission] [bit] NULL, - [IsMarkedAsTransfered] [bit] NULL, - [IsEligibleForDegree] [bit] NULL, - [IsLateral] [bit] NULL, - [DegreeExamEventId] [int] NULL, - [IsAdmissionCancelled] [bit] NULL, - [GCAS_ApplicationNo] [nvarchar](50) NULL, - [AdmittedGenResCategoryId] [int] NULL, - [IsAdmittedInPHDisabled] [bit] NULL, - [MSUIS_DisabilityId] [tinyint] NULL, - CONSTRAINT [PK_IncStudentAdmission] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[IncStudentPartTermPaperMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[IncStudentPartTermPaperMap]( - [Id] [bigint] NOT NULL, - [PRN] [bigint] NULL, - [StudentAcademicInformationId] [bigint] NULL, - [ProgrammeInstancePartTermId] [bigint] NULL, - [PaperId] [bigint] NULL, - [MstPaperId] [bigint] NULL, - [ObtainedMarks] [decimal](4, 0) NULL, - [ObtainedGrade] [nvarchar](4) NULL, - [PaperStatus] [nvarchar](50) NULL, - [PartTermStatus] [nvarchar](50) NULL, - [IsExempted] [bit] NULL, - [ResultStatus] [nvarchar](50) NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [IsDeleted] [bit] NULL, - [IsLateral] [bit] NULL, - [IsAdmissionCancelled] [bit] NULL, - [Division] [nvarchar](10) NULL, - [ExamMasterId] [int] NULL, - CONSTRAINT [PK_IncStudentPartTermPaperMap] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstInstitute] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstInstitute]( - [Id] [int] NOT NULL, - [InstituteName] [nvarchar](200) NOT NULL, - [InstituteCode] [nvarchar](20) NOT NULL, - [InstituteType] [nvarchar](20) NULL, - [InstituteAddress] [nvarchar](max) NULL, - [CityName] [nvarchar](50) NULL, - [Pincode] [int] NULL, - [InstituteContactNo] [nvarchar](15) NULL, - [InstituteFaxNo] [nvarchar](20) NULL, - [InstituteEmail] [nvarchar](150) NULL, - [InstituteUrl] [nvarchar](max) NULL, - [IsConsiderForAdmission] [bit] NOT NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_MstInstitute] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstInstituteProgrammeMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstInstituteProgrammeMap]( - [Id] [int] NOT NULL, - [InstituteId] [int] NULL, - [ProgrammeId] [int] NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedOn] [datetime] NULL, - [CreatedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - CONSTRAINT [PK_MstInstituteProgramMap] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstPaper] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstPaper]( - [Id] [bigint] NOT NULL, - [SubjectId] [int] NOT NULL, - [PaperName] [nvarchar](1000) NOT NULL, - [PaperCode] [nvarchar](30) NOT NULL, - [IsCredit] [bit] NOT NULL, - [MaxMarks] [int] NULL, - [MinMarks] [int] NULL, - [Credits] [decimal](5, 2) NULL, - [IsSeparatePassingHead] [bit] NOT NULL, - [EvaluationId] [int] NULL, - [ClassGradeTemplateId] [int] NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_MstPaper] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstPaperTeachingLearningMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstPaperTeachingLearningMap]( - [Id] [bigint] NOT NULL, - [PaperId] [bigint] NOT NULL, - [TeachingLearningMethodId] [int] NOT NULL, - [AssessmentMethodId] [int] NOT NULL, - [AssessmentType] [nvarchar](15) NULL, - [AssessmentMethodMarks] [int] NULL, - [AssessmentTypeMinMarks] [int] NULL, - [AssessmentTypeMaxMarks] [int] NULL, - [IsExemption] [bit] NULL, - [IsCarryForwarded] [bit] NULL, - [NoOfLecturesPerWeek] [int] NULL, - [NoOfHoursPerWeek] [decimal](5, 2) NULL, - [NoOfCredits] [decimal](5, 2) NULL, - [IsActive] [bit] NULL, - [IsDeleted] [bit] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_MstPaperTeachingLearningMap] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstProgramme] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstProgramme]( - [Id] [int] NOT NULL, - [ProgrammeName] [nvarchar](300) NOT NULL, - [ProgrammeCode] [nvarchar](100) NOT NULL, - [FacultyId] [int] NOT NULL, - [ProgrammeDescription] [nvarchar](max) NULL, - [ProgrammeLevelId] [int] NOT NULL, - [ProgrammeModeId] [int] NOT NULL, - [ProgrammeTypeId] [int] NOT NULL, - [InstructionMediumId] [int] NOT NULL, - [EvaluationId] [int] NOT NULL, - [IsCBCS] [bit] NOT NULL, - [IsSepartePassingHead] [bit] NULL, - [MaxMarks] [int] NULL, - [MinMarks] [int] NULL, - [MaxCredits] [decimal](5, 2) NULL, - [MinCredits] [decimal](5, 2) NULL, - [ProgrammeDuration] [int] NOT NULL, - [ProgrammeValidity] [int] NOT NULL, - [TotalParts] [int] NOT NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [IsNEP] [bit] NULL, - CONSTRAINT [PK_MstProgramme] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstProgrammeBranchMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstProgrammeBranchMap]( - [Id] [int] NOT NULL, - [ProgrammeId] [int] NOT NULL, - [SpecialisationId] [int] NOT NULL, - [SubSpecialisationId] [int] NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_MstProgrammeBranchMap] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstProgrammePart] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstProgrammePart]( - [Id] [int] NOT NULL, - [ProgrammeId] [int] NOT NULL, - [ExamPatternId] [int] NOT NULL, - [PartName] [nvarchar](100) NULL, - [PartShortName] [nvarchar](50) NULL, - [SequenceNo] [bigint] NULL, - [NoOfTerms] [bigint] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [IsActive] [bit] NULL, - [IsDeleted] [bit] NULL, - CONSTRAINT [PK_MstProgrammePart] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY], - CONSTRAINT [IX_MstProgrammePart] UNIQUE NONCLUSTERED -( - [PartName] ASC, - [PartShortName] ASC, - [ProgrammeId] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstProgrammePartTerm] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstProgrammePartTerm]( - [Id] [int] NOT NULL, - [PartId] [int] NOT NULL, - [PartTermName] [nvarchar](max) NOT NULL, - [PartTermShortName] [nvarchar](100) NOT NULL, - [SequenceNo] [int] NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [IsBranchChangeAllowed] [bit] NULL, - CONSTRAINT [PK_MstProgrammePartTerm] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstProgrammePartTermPaperMap] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstProgrammePartTermPaperMap]( - [Id] [bigint] NOT NULL, - [PartTermId] [int] NULL, - [PaperId] [bigint] NULL, - [GroupId] [bigint] NULL, - [IsActive] [bit] NULL, - [IsDelete] [bit] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_MstProgrammePartTermPaperMap] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstSpecialisation] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstSpecialisation]( - [Id] [int] NOT NULL, - [BranchName] [nvarchar](100) NOT NULL, - [FacultyId] [int] NOT NULL, - [InstituteId] [int] NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_MstSpecialisation] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstStudent] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstStudent]( - [PRN] [bigint] NOT NULL, - [LastName] [nvarchar](50) NULL, - [FirstName] [nvarchar](50) NULL, - [MiddleName] [nvarchar](50) NULL, - [NameAsPerMarksheet] [nvarchar](100) NULL, - [Gender] [nvarchar](25) NULL, - [ReligionId] [bigint] NULL, - [OtherReligion] [nvarchar](20) NULL, - [MaritalStatusId] [bigint] NULL, - [MotherTongueId] [bigint] NULL, - [CommunicationLanguageId] [bigint] NULL, - [DOB] [date] NULL, - [DOBDoc] [nvarchar](50) NULL, - [PhotoIdDoc] [nvarchar](100) NULL, - [BloodGroupId] [bigint] NULL, - [HeightInCms] [decimal](18, 2) NULL, - [WeightInKgs] [decimal](18, 2) NULL, - [IsMajorThelesamiaStatus] [nvarchar](30) NULL, - [IsNRI] [bit] NULL, - [CountryIdOfCitizenship] [bigint] NULL, - [Caste] [nvarchar](20) NULL, - [PlaceOfBirth] [nvarchar](20) NULL, - [PassportNumber] [nvarchar](50) NULL, - [PassportDate] [date] NULL, - [AadharNumber] [nvarchar](20) NULL, - [AadharDoc] [nvarchar](50) NULL, - [NameOnAadhar] [nvarchar](50) NULL, - [PermanentAddress] [nvarchar](max) NULL, - [PermanentCountryId] [bigint] NULL, - [PermanentStateId] [bigint] NULL, - [PermanentDistrictId] [bigint] NULL, - [PermanentCityVillage] [nvarchar](50) NULL, - [PermanentPincode] [bigint] NULL, - [IsCurrentAsPermanent] [bit] NULL, - [CurrentAddress] [nvarchar](max) NULL, - [CurrentCountryId] [bigint] NULL, - [CurrentStateId] [bigint] NULL, - [CurrentDistrictId] [bigint] NULL, - [CurrentCityVillage] [nvarchar](50) NULL, - [CurrentPincode] [bigint] NULL, - [NameOfFather] [nvarchar](50) NULL, - [NameOfMother] [nvarchar](50) NULL, - [FatherMotherContactNo] [nvarchar](20) NULL, - [SpouseName] [nvarchar](50) NULL, - [SocialCategoryId] [bigint] NULL, - [GSocialCategoryId] [bigint] NULL, - [IsSocialDocSubmitted] [bit] NULL, - [IsEWSDocSubmitted] [bit] NULL, - [IsPCDocSubmitted] [bit] NULL, - [IsReservationDocSubmitted] [bit] NULL, - [SocialCategoryDoc] [nvarchar](50) NULL, - [ReservationCategoryDoc] [nvarchar](max) NULL, - [ApplicationCategoryId] [bigint] NULL, - [GuardianName] [nvarchar](50) NULL, - [GuardianContactNo] [nvarchar](50) NULL, - [FamilyAnnualIncome] [bigint] NULL, - [OccupationIdOfFather] [bigint] NULL, - [OccupationIdOfMother] [bigint] NULL, - [OccupationIdOfGuardian] [bigint] NULL, - [IsEmp] [bit] NULL, - [CurrentEmployerName] [nvarchar](50) NULL, - [IsGuardianEbc] [bit] NULL, - [GuardianAnnualIncome] [bigint] NULL, - [EmailId] [nvarchar](50) NULL, - [MobileNo] [nvarchar](50) NULL, - [OptionalMobileNo] [nvarchar](50) NULL, - [IsSmsPermissionGiven] [bit] NULL, - [IsLocalToVadodara] [bit] NULL, - [ActivityId] [bigint] NULL, - [ActivityName] [nvarchar](50) NULL, - [ParticipationLevelsId] [bigint] NULL, - [SecuredRankId] [bigint] NULL, - [IsEWS] [nvarchar](50) NULL, - [EWSDoc] [nvarchar](max) NULL, - [IsPhysicallyChallenged] [nvarchar](50) NULL, - [PCDoc] [nvarchar](max) NULL, - [DisabilityPercentage] [bigint] NULL, - [DisabilityType] [nvarchar](50) NULL, - [StudentPhoto] [nvarchar](max) NULL, - [StudentSignature] [nvarchar](max) NULL, - [IsTransferFromApplicant] [bit] NULL, - [IsEmailSend] [bit] NULL, - [EmailSendOn] [datetime] NULL, - [IsSMSSend] [bit] NULL, - [SMSSendOn] [datetime] NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - [ABCId] [bigint] NULL, - [IsLastQualifyMS] [bit] NULL, - [FacultyId] [int] NULL, - [ProgrammeName] [nvarchar](100) NULL, - [PRNorEnrollNo] [nvarchar](30) NULL, - [PassingYear] [int] NULL, - [AdmissionYear] [int] NULL, - [NCLCerti] [nvarchar](max) NULL, - [NCLCertiNo] [nvarchar](30) NULL, - [NCLCerti_IsuueDate] [date] NULL, - [NCLCertiValidityDate] [date] NULL, - [EWS_IADoc] [nvarchar](50) NULL, - [EWSCertiNo] [nvarchar](30) NULL, - [EWSCerti_IsuueDate] [date] NULL, - [EWSCertiValidityDate] [date] NULL, - [GCAS_ApplicationNo] [nvarchar](50) NULL, - [GCAS_ApplicantName] [nvarchar](100) NULL, - [NameAsPerABCId] [nchar](100) NULL, - [DeviceToken] [nvarchar](255) NULL, - CONSTRAINT [PK_MstStudent] PRIMARY KEY CLUSTERED -( - [PRN] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] -GO -/****** Object: Table [dbo].[MstSubSpecialisation] Script Date: 08-05-2026 Fri 3.39.02 PM ******/ -SET ANSI_NULLS ON -GO -SET QUOTED_IDENTIFIER ON -GO -CREATE TABLE [dbo].[MstSubSpecialisation]( - [Id] [int] IDENTITY(1,1) NOT NULL, - [SpecialisationId] [int] NOT NULL, - [SubSpecialisationName] [nvarchar](50) NOT NULL, - [IsActive] [bit] NOT NULL, - [IsDeleted] [bit] NOT NULL, - [CreatedBy] [bigint] NULL, - [CreatedOn] [datetime] NULL, - [ModifiedBy] [bigint] NULL, - [ModifiedOn] [datetime] NULL, - CONSTRAINT [PK_MstSubSpecialisation] PRIMARY KEY CLUSTERED -( - [Id] ASC -)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] -) ON [PRIMARY] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePart] ADD CONSTRAINT [DF_IncProgrammeInstancePart_IsSeparatePassingHead] DEFAULT ((0)) FOR [IsSeparatePassingHead] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] ADD CONSTRAINT [DF_IncProgrammeInstancePartTerm_IsSeparatePassingHead] DEFAULT ((0)) FOR [IsSeparatePassingHead] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] ADD CONSTRAINT [DF_IncProgrammeInstancePartTermPaperGroup_SeparatePassingHead] DEFAULT ((0)) FOR [SeparatePassingHead] -GO -ALTER TABLE [dbo].[MstInstitute] ADD CONSTRAINT [DF_MstInstitute_IsConsiderForAdmission] DEFAULT ((1)) FOR [IsConsiderForAdmission] -GO -ALTER TABLE [dbo].[MstPaperTeachingLearningMap] ADD CONSTRAINT [DF_MstPaperTeachingLearningMap_AssessmentTypeMinMarks] DEFAULT ((0)) FOR [AssessmentTypeMinMarks] -GO -ALTER TABLE [dbo].[MstPaperTeachingLearningMap] ADD CONSTRAINT [DF_MstPaperTeachingLearningMap_AssessmentTypeMaxMarks] DEFAULT ((0)) FOR [AssessmentTypeMaxMarks] -GO -ALTER TABLE [dbo].[MstStudent] ADD CONSTRAINT [DF_MstStudent_IsTransferFromApplicant] DEFAULT ((0)) FOR [IsTransferFromApplicant] -GO -ALTER TABLE [dbo].[IncInstitutePartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncInstitutePartTermPaperMap_IncProgInstPartTermPaperMap] FOREIGN KEY([PartTermPaperMapId]) -REFERENCES [dbo].[IncProgInstPartTermPaperMap] ([Id]) -GO -ALTER TABLE [dbo].[IncInstitutePartTermPaperMap] CHECK CONSTRAINT [FK_IncInstitutePartTermPaperMap_IncProgInstPartTermPaperMap] -GO -ALTER TABLE [dbo].[IncInstitutePartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncInstitutePartTermPaperMap_MstInstitute] FOREIGN KEY([InstituteId]) -REFERENCES [dbo].[MstInstitute] ([Id]) -GO -ALTER TABLE [dbo].[IncInstitutePartTermPaperMap] CHECK CONSTRAINT [FK_IncInstitutePartTermPaperMap_MstInstitute] -GO -ALTER TABLE [dbo].[IncPreferanceGroupMap] WITH CHECK ADD CONSTRAINT [FK_IncPreferanceGroupMap_IncProgrammeInstancePartTermPaperGroup] FOREIGN KEY([GroupId]) -REFERENCES [dbo].[IncProgrammeInstancePartTermPaperGroup] ([Id]) -GO -ALTER TABLE [dbo].[IncPreferanceGroupMap] CHECK CONSTRAINT [FK_IncPreferanceGroupMap_IncProgrammeInstancePartTermPaperGroup] -GO -ALTER TABLE [dbo].[IncPreferanceGroupMap] WITH CHECK ADD CONSTRAINT [FK_IncPreferanceGroupMap_MstPreferenceGroup] FOREIGN KEY([PreferenceId]) -REFERENCES [dbo].[MstPreferenceGroup] ([Id]) -GO -ALTER TABLE [dbo].[IncPreferanceGroupMap] CHECK CONSTRAINT [FK_IncPreferanceGroupMap_MstPreferenceGroup] -GO -ALTER TABLE [dbo].[IncProgInstPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncProgInstPartTermPaperMap_IncProgrammeInstancePartTermPaperGroup] FOREIGN KEY([GroupId]) -REFERENCES [dbo].[IncProgrammeInstancePartTermPaperGroup] ([Id]) -GO -ALTER TABLE [dbo].[IncProgInstPartTermPaperMap] CHECK CONSTRAINT [FK_IncProgInstPartTermPaperMap_IncProgrammeInstancePartTermPaperGroup] -GO -ALTER TABLE [dbo].[IncProgInstPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncProgInstPartTermPaperMap_MstPaper] FOREIGN KEY([PaperId]) -REFERENCES [dbo].[MstPaper] ([Id]) -GO -ALTER TABLE [dbo].[IncProgInstPartTermPaperMap] CHECK CONSTRAINT [FK_IncProgInstPartTermPaperMap_MstPaper] -GO -ALTER TABLE [dbo].[IncProgrammeInstance] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstance_IncAcademicYear] FOREIGN KEY([AcademicYearId]) -REFERENCES [dbo].[IncAcademicYear] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstance] CHECK CONSTRAINT [FK_IncProgrammeInstance_IncAcademicYear] -GO -ALTER TABLE [dbo].[IncProgrammeInstance] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstance_MstFaculty] FOREIGN KEY([FacultyId]) -REFERENCES [dbo].[MstFaculty] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstance] CHECK CONSTRAINT [FK_IncProgrammeInstance_MstFaculty] -GO -ALTER TABLE [dbo].[IncProgrammeInstance] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstance_MstProgramme] FOREIGN KEY([ProgrammeId]) -REFERENCES [dbo].[MstProgramme] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstance] CHECK CONSTRAINT [FK_IncProgrammeInstance_MstProgramme] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePart] WITH CHECK ADD CONSTRAINT [FK_AdmProgramInstancePart_MstProgrammePart] FOREIGN KEY([ProgrammePartId]) -REFERENCES [dbo].[MstProgrammePart] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePart] CHECK CONSTRAINT [FK_AdmProgramInstancePart_MstProgrammePart] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePart] WITH NOCHECK ADD CONSTRAINT [FK_IncProgrammeInstancePart_IncProgrammeInstance] FOREIGN KEY([ProgrammeInstanceId]) -REFERENCES [dbo].[IncProgrammeInstance] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePart] CHECK CONSTRAINT [FK_IncProgrammeInstancePart_IncProgrammeInstance] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgramInstancePartTerm_MstProgrammePart] FOREIGN KEY([ProgrammePartId]) -REFERENCES [dbo].[MstProgrammePart] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgramInstancePartTerm_MstProgrammePart] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgramInstancePartTerm_MstProgrammePartTerm] FOREIGN KEY([ProgrammePartTermId]) -REFERENCES [dbo].[MstProgrammePartTerm] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgramInstancePartTerm_MstProgrammePartTerm] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgramInstancePartTerm_MstSpecialisation] FOREIGN KEY([SpecialisationId]) -REFERENCES [dbo].[MstSpecialisation] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgramInstancePartTerm_MstSpecialisation] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncAcademicYear] FOREIGN KEY([AcademicYearId]) -REFERENCES [dbo].[IncAcademicYear] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncAcademicYear] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncProgrammeInstance] FOREIGN KEY([ProgrammeInstanceId]) -REFERENCES [dbo].[IncProgrammeInstance] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncProgrammeInstance] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncProgrammeInstancePart] FOREIGN KEY([ProgrammeInstancePartId]) -REFERENCES [dbo].[IncProgrammeInstancePart] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_IncProgrammeInstancePart] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_MstFaculty] FOREIGN KEY([FacultyId]) -REFERENCES [dbo].[MstFaculty] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_MstFaculty] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTerm_MstProgrammePartTerm] FOREIGN KEY([ProgrammePartTermId]) -REFERENCES [dbo].[MstProgrammePartTerm] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTerm_MstProgrammePartTerm] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_IncProgramInstancePart] FOREIGN KEY([ProgrammeInstancePartId]) -REFERENCES [dbo].[IncProgrammeInstancePart] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_IncProgramInstancePart] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_IncProgrammeInstance] FOREIGN KEY([ProgrammeInstanceId]) -REFERENCES [dbo].[IncProgrammeInstance] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_IncProgrammeInstance] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_MstFaculty] FOREIGN KEY([FacultyId]) -REFERENCES [dbo].[MstFaculty] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_MstFaculty] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_MstProgramme] FOREIGN KEY([ProgrammeId]) -REFERENCES [dbo].[MstProgramme] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_MstProgramme] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] WITH CHECK ADD CONSTRAINT [FK_MstProgramInstancePartTerm_MstProgrammeBranchMap] FOREIGN KEY([ProgrammeBranchMapId]) -REFERENCES [dbo].[MstProgrammeBranchMap] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTerm] CHECK CONSTRAINT [FK_MstProgramInstancePartTerm_MstProgrammeBranchMap] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] WITH CHECK ADD CONSTRAINT [FK_IncProgrammeInstancePartTermPaperGroup_IncProgrammeInstancePartTermPaperGroup] FOREIGN KEY([MstPartTermGroupId]) -REFERENCES [dbo].[MstPartTermGroupMap] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] CHECK CONSTRAINT [FK_IncProgrammeInstancePartTermPaperGroup_IncProgrammeInstancePartTermPaperGroup] -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] WITH CHECK ADD CONSTRAINT [FK_MstProgrammeInstancePaperGroup_MstProgrammeInstancePaperGroup] FOREIGN KEY([ParentGroupId]) -REFERENCES [dbo].[IncProgrammeInstancePartTermPaperGroup] ([Id]) -GO -ALTER TABLE [dbo].[IncProgrammeInstancePartTermPaperGroup] CHECK CONSTRAINT [FK_MstProgrammeInstancePaperGroup_MstProgrammeInstancePaperGroup] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_ExamEventMaster] FOREIGN KEY([DegreeExamEventId]) -REFERENCES [dbo].[ExamEventMaster] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_ExamEventMaster] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_FeeCategoryPartTermMap] FOREIGN KEY([AdmissionFeeCategoryPartTermMapId]) -REFERENCES [dbo].[FeeCategoryPartTermMap] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_FeeCategoryPartTermMap] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_IncAcademicYear] FOREIGN KEY([AcademicYearId]) -REFERENCES [dbo].[IncAcademicYear] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_IncAcademicYear] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_IncProgrammeInstancePart] FOREIGN KEY([ProgrammeInstancePartId]) -REFERENCES [dbo].[IncProgrammeInstancePart] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_IncProgrammeInstancePart] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_IncStudentAdmission] FOREIGN KEY([StudentAdmissionId]) -REFERENCES [dbo].[IncStudentAdmission] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_IncStudentAdmission] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstAdmissionCommittee] FOREIGN KEY([AdmissionCommitteeId]) -REFERENCES [dbo].[MstAdmissionCommittee] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstAdmissionCommittee] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstFaculty] FOREIGN KEY([FacultyId]) -REFERENCES [dbo].[MstFaculty] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstFaculty] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstFeeCategory] FOREIGN KEY([AdmissionFeeCategoryId]) -REFERENCES [dbo].[MstFeeCategory] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstFeeCategory] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstInstitute] FOREIGN KEY([InstituteId]) -REFERENCES [dbo].[MstInstitute] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstInstitute] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstPreferenceGroup] FOREIGN KEY([PreferenceGroupId]) -REFERENCES [dbo].[MstPreferenceGroup] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstPreferenceGroup] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstProgramme] FOREIGN KEY([ProgrammeId]) -REFERENCES [dbo].[MstProgramme] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstProgramme] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstSpecialisation] FOREIGN KEY([SpecialisationId]) -REFERENCES [dbo].[MstSpecialisation] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstSpecialisation] -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] WITH CHECK ADD CONSTRAINT [FK_IncStudentAcademicInformation_MstStudent] FOREIGN KEY([PRN]) -REFERENCES [dbo].[MstStudent] ([PRN]) -GO -ALTER TABLE [dbo].[IncStudentAcademicInformation] CHECK CONSTRAINT [FK_IncStudentAcademicInformation_MstStudent] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_ExamEventMaster] FOREIGN KEY([DegreeExamEventId]) -REFERENCES [dbo].[ExamEventMaster] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_ExamEventMaster] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_FeeCategoryPartTermMap] FOREIGN KEY([AdmissionFeeCategoryPartTermMapId]) -REFERENCES [dbo].[FeeCategoryPartTermMap] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_FeeCategoryPartTermMap] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_IncAcademicYear] FOREIGN KEY([AcademicYearId]) -REFERENCES [dbo].[IncAcademicYear] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_IncAcademicYear] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_IncProgrammeInstancePart] FOREIGN KEY([ProgrammeInstancePartId]) -REFERENCES [dbo].[IncProgrammeInstancePart] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_IncProgrammeInstancePart] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_IncProgrammeInstancePartTerm] FOREIGN KEY([SpecialisationId]) -REFERENCES [dbo].[MstSpecialisation] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_IncProgrammeInstancePartTerm] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstFaculty] FOREIGN KEY([FacultyId]) -REFERENCES [dbo].[MstFaculty] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstFaculty] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstFeeCategory] FOREIGN KEY([AdmissionFeeCategoryId]) -REFERENCES [dbo].[MstFeeCategory] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstFeeCategory] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstInstitute] FOREIGN KEY([InstituteId]) -REFERENCES [dbo].[MstInstitute] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstInstitute] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstProgramme] FOREIGN KEY([ProgrammeId]) -REFERENCES [dbo].[MstProgramme] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstProgramme] -GO -ALTER TABLE [dbo].[IncStudentAdmission] WITH CHECK ADD CONSTRAINT [FK_IncStudentAdmission_MstStudent] FOREIGN KEY([PRN]) -REFERENCES [dbo].[MstStudent] ([PRN]) -GO -ALTER TABLE [dbo].[IncStudentAdmission] CHECK CONSTRAINT [FK_IncStudentAdmission_MstStudent] -GO -ALTER TABLE [dbo].[IncStudentPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncStudentPartTermPaperMap_IncProgInstPartTermPaperMap] FOREIGN KEY([PaperId]) -REFERENCES [dbo].[IncProgInstPartTermPaperMap] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentPartTermPaperMap] CHECK CONSTRAINT [FK_IncStudentPartTermPaperMap_IncProgInstPartTermPaperMap] -GO -ALTER TABLE [dbo].[IncStudentPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncStudentPartTermPaperMap_IncStudentAcademicInformation] FOREIGN KEY([StudentAcademicInformationId]) -REFERENCES [dbo].[IncStudentAcademicInformation] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentPartTermPaperMap] CHECK CONSTRAINT [FK_IncStudentPartTermPaperMap_IncStudentAcademicInformation] -GO -ALTER TABLE [dbo].[IncStudentPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncStudentPartTermPaperMap_MstPaper] FOREIGN KEY([MstPaperId]) -REFERENCES [dbo].[MstPaper] ([Id]) -GO -ALTER TABLE [dbo].[IncStudentPartTermPaperMap] CHECK CONSTRAINT [FK_IncStudentPartTermPaperMap_MstPaper] -GO -ALTER TABLE [dbo].[IncStudentPartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_IncStudentPartTermPaperMap_MstStudent] FOREIGN KEY([PRN]) -REFERENCES [dbo].[MstStudent] ([PRN]) -GO -ALTER TABLE [dbo].[IncStudentPartTermPaperMap] CHECK CONSTRAINT [FK_IncStudentPartTermPaperMap_MstStudent] -GO -ALTER TABLE [dbo].[MstInstituteProgrammeMap] WITH CHECK ADD CONSTRAINT [FK_MstInstituteProgrammeMap_MstInstitute] FOREIGN KEY([InstituteId]) -REFERENCES [dbo].[MstInstitute] ([Id]) -GO -ALTER TABLE [dbo].[MstInstituteProgrammeMap] CHECK CONSTRAINT [FK_MstInstituteProgrammeMap_MstInstitute] -GO -ALTER TABLE [dbo].[MstInstituteProgrammeMap] WITH CHECK ADD CONSTRAINT [FK_MstInstituteProgrammeMap_MstProgramme] FOREIGN KEY([ProgrammeId]) -REFERENCES [dbo].[MstProgramme] ([Id]) -GO -ALTER TABLE [dbo].[MstInstituteProgrammeMap] CHECK CONSTRAINT [FK_MstInstituteProgrammeMap_MstProgramme] -GO -ALTER TABLE [dbo].[MstPaper] WITH CHECK ADD CONSTRAINT [FK_MstPaper_MstSubject] FOREIGN KEY([SubjectId]) -REFERENCES [dbo].[MstSubject] ([Id]) -GO -ALTER TABLE [dbo].[MstPaper] CHECK CONSTRAINT [FK_MstPaper_MstSubject] -GO -ALTER TABLE [dbo].[MstPaperTeachingLearningMap] WITH NOCHECK ADD CONSTRAINT [FK_MstPaperTeachingLearningMap_MstAssessmentMethod] FOREIGN KEY([AssessmentMethodId]) -REFERENCES [dbo].[MstAssessmentMethod] ([Id]) -GO -ALTER TABLE [dbo].[MstPaperTeachingLearningMap] CHECK CONSTRAINT [FK_MstPaperTeachingLearningMap_MstAssessmentMethod] -GO -ALTER TABLE [dbo].[MstPaperTeachingLearningMap] WITH CHECK ADD CONSTRAINT [FK_MstPaperTeachingLearningMap_MstPaper] FOREIGN KEY([PaperId]) -REFERENCES [dbo].[MstPaper] ([Id]) -GO -ALTER TABLE [dbo].[MstPaperTeachingLearningMap] CHECK CONSTRAINT [FK_MstPaperTeachingLearningMap_MstPaper] -GO -ALTER TABLE [dbo].[MstPaperTeachingLearningMap] WITH CHECK ADD CONSTRAINT [FK_MstPaperTeachingLearningMap_MstTeachingLearningMethod] FOREIGN KEY([TeachingLearningMethodId]) -REFERENCES [dbo].[MstTeachingLearningMethod] ([Id]) -GO -ALTER TABLE [dbo].[MstPaperTeachingLearningMap] CHECK CONSTRAINT [FK_MstPaperTeachingLearningMap_MstTeachingLearningMethod] -GO -ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstEvaluation] FOREIGN KEY([EvaluationId]) -REFERENCES [dbo].[MstEvaluation] ([Id]) -GO -ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstEvaluation] -GO -ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstFaculty] FOREIGN KEY([FacultyId]) -REFERENCES [dbo].[MstFaculty] ([Id]) -GO -ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstFaculty] -GO -ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstInstructionMedium] FOREIGN KEY([InstructionMediumId]) -REFERENCES [dbo].[MstInstructionMedium] ([Id]) -GO -ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstInstructionMedium] -GO -ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstProgrammeLevel] FOREIGN KEY([ProgrammeLevelId]) -REFERENCES [dbo].[MstProgrammeLevel] ([Id]) -GO -ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstProgrammeLevel] -GO -ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstProgrammeMode] FOREIGN KEY([ProgrammeModeId]) -REFERENCES [dbo].[MstProgrammeMode] ([Id]) -GO -ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstProgrammeMode] -GO -ALTER TABLE [dbo].[MstProgramme] WITH CHECK ADD CONSTRAINT [FK_MstProgramme_MstProgrammeType] FOREIGN KEY([ProgrammeTypeId]) -REFERENCES [dbo].[MstProgrammeType] ([Id]) -GO -ALTER TABLE [dbo].[MstProgramme] CHECK CONSTRAINT [FK_MstProgramme_MstProgrammeType] -GO -ALTER TABLE [dbo].[MstProgrammeBranchMap] WITH CHECK ADD CONSTRAINT [FK_MstProgrammeBranchMap_MstProgramme] FOREIGN KEY([ProgrammeId]) -REFERENCES [dbo].[MstProgramme] ([Id]) -GO -ALTER TABLE [dbo].[MstProgrammeBranchMap] CHECK CONSTRAINT [FK_MstProgrammeBranchMap_MstProgramme] -GO -ALTER TABLE [dbo].[MstProgrammeBranchMap] WITH CHECK ADD CONSTRAINT [FK_MstProgrammeBranchMap_MstSpecialisation] FOREIGN KEY([SpecialisationId]) -REFERENCES [dbo].[MstSpecialisation] ([Id]) -GO -ALTER TABLE [dbo].[MstProgrammeBranchMap] CHECK CONSTRAINT [FK_MstProgrammeBranchMap_MstSpecialisation] -GO -ALTER TABLE [dbo].[MstProgrammeBranchMap] WITH CHECK ADD CONSTRAINT [FK_MstProgrammeBranchMap_MstSubSpecialisation] FOREIGN KEY([SubSpecialisationId]) -REFERENCES [dbo].[MstSubSpecialisation] ([Id]) -GO -ALTER TABLE [dbo].[MstProgrammeBranchMap] CHECK CONSTRAINT [FK_MstProgrammeBranchMap_MstSubSpecialisation] -GO -ALTER TABLE [dbo].[MstProgrammePart] WITH CHECK ADD CONSTRAINT [FK_MstProgrammePart_MstExaminationPattern] FOREIGN KEY([ExamPatternId]) -REFERENCES [dbo].[MstExaminationPattern] ([Id]) -GO -ALTER TABLE [dbo].[MstProgrammePart] CHECK CONSTRAINT [FK_MstProgrammePart_MstExaminationPattern] -GO -ALTER TABLE [dbo].[MstProgrammePart] WITH CHECK ADD CONSTRAINT [FK_MstProgrammePart_MstProgramme] FOREIGN KEY([ProgrammeId]) -REFERENCES [dbo].[MstProgramme] ([Id]) -GO -ALTER TABLE [dbo].[MstProgrammePart] CHECK CONSTRAINT [FK_MstProgrammePart_MstProgramme] -GO -ALTER TABLE [dbo].[MstProgrammePartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK__MstProgrammePartTerm] FOREIGN KEY([PartTermId]) -REFERENCES [dbo].[MstProgrammePartTerm] ([Id]) -GO -ALTER TABLE [dbo].[MstProgrammePartTermPaperMap] CHECK CONSTRAINT [FK__MstProgrammePartTerm] -GO -ALTER TABLE [dbo].[MstProgrammePartTermPaperMap] WITH CHECK ADD CONSTRAINT [FK_MstPaper] FOREIGN KEY([PaperId]) -REFERENCES [dbo].[MstPaper] ([Id]) -GO -ALTER TABLE [dbo].[MstProgrammePartTermPaperMap] CHECK CONSTRAINT [FK_MstPaper] -GO -ALTER TABLE [dbo].[MstSpecialisation] WITH CHECK ADD CONSTRAINT [FK_MstSpecialisation_MstFaculty] FOREIGN KEY([FacultyId]) -REFERENCES [dbo].[MstFaculty] ([Id]) -GO -ALTER TABLE [dbo].[MstSpecialisation] CHECK CONSTRAINT [FK_MstSpecialisation_MstFaculty] -GO -ALTER TABLE [dbo].[MstSpecialisation] WITH CHECK ADD CONSTRAINT [FK_MstSpecialisation_MstInstitute] FOREIGN KEY([InstituteId]) -REFERENCES [dbo].[MstInstitute] ([Id]) -GO -ALTER TABLE [dbo].[MstSpecialisation] CHECK CONSTRAINT [FK_MstSpecialisation_MstInstitute] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_AdmExtraAct] FOREIGN KEY([ActivityId]) -REFERENCES [dbo].[AdmExtraAct] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_AdmExtraAct] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_AdmExtraCuriculam] FOREIGN KEY([ParticipationLevelsId]) -REFERENCES [dbo].[AdmExtraCuriculam] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_AdmExtraCuriculam] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_AdmExtraCuriculamActivity] FOREIGN KEY([SecuredRankId]) -REFERENCES [dbo].[AdmExtraCuriculamActivity] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_AdmExtraCuriculamActivity] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_BloodGroup] FOREIGN KEY([BloodGroupId]) -REFERENCES [dbo].[BloodGroup] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_BloodGroup] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_CommunicationLanguage] FOREIGN KEY([CommunicationLanguageId]) -REFERENCES [dbo].[CommunicationLanguage] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_CommunicationLanguage] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_CountryMaster] FOREIGN KEY([CountryIdOfCitizenship]) -REFERENCES [dbo].[CountryMaster] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_CountryMaster] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_CountryMaster1] FOREIGN KEY([PermanentCountryId]) -REFERENCES [dbo].[CountryMaster] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_CountryMaster1] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_CountryMaster2] FOREIGN KEY([CurrentCountryId]) -REFERENCES [dbo].[CountryMaster] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_CountryMaster2] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_DistrictMaster] FOREIGN KEY([PermanentDistrictId]) -REFERENCES [dbo].[DistrictMaster] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_DistrictMaster] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_DistrictMaster1] FOREIGN KEY([CurrentDistrictId]) -REFERENCES [dbo].[DistrictMaster] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_DistrictMaster1] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_GenMaritalStatus] FOREIGN KEY([MaritalStatusId]) -REFERENCES [dbo].[GenMaritalStatus] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_GenMaritalStatus] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_MaritalStatusId] FOREIGN KEY([MaritalStatusId]) -REFERENCES [dbo].[GenMaritalStatus] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_MaritalStatusId] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_MotherTongue] FOREIGN KEY([MotherTongueId]) -REFERENCES [dbo].[MotherTongue] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_MotherTongue] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_Occupation] FOREIGN KEY([OccupationIdOfFather]) -REFERENCES [dbo].[GenOccupation] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_Occupation] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_Occupation1] FOREIGN KEY([OccupationIdOfMother]) -REFERENCES [dbo].[GenOccupation] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_Occupation1] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_Occupation2] FOREIGN KEY([OccupationIdOfGuardian]) -REFERENCES [dbo].[GenOccupation] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_Occupation2] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_ReligionMaster] FOREIGN KEY([ReligionId]) -REFERENCES [dbo].[ReligionMaster] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_ReligionMaster] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_StateMaster] FOREIGN KEY([PermanentStateId]) -REFERENCES [dbo].[StateMaster] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_StateMaster] -GO -ALTER TABLE [dbo].[MstStudent] WITH CHECK ADD CONSTRAINT [FK_MstStudent_StateMaster1] FOREIGN KEY([CurrentStateId]) -REFERENCES [dbo].[StateMaster] ([Id]) -GO -ALTER TABLE [dbo].[MstStudent] CHECK CONSTRAINT [FK_MstStudent_StateMaster1] -GO -ALTER TABLE [dbo].[MstSubSpecialisation] WITH CHECK ADD CONSTRAINT [FK_MstSubSpecialisation_MstSpecialisation] FOREIGN KEY([SpecialisationId]) -REFERENCES [dbo].[MstSpecialisation] ([Id]) -GO -ALTER TABLE [dbo].[MstSubSpecialisation] CHECK CONSTRAINT [FK_MstSubSpecialisation_MstSpecialisation] -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Inactive in case name change or modified' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncInstitutePartTermPaperMap', @level2type=N'COLUMN',@level2name=N'IsActive' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Soft Delete' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncInstitutePartTermPaperMap', @level2type=N'COLUMN',@level2name=N'IsDeleted' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Academic Year' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncProgrammeInstance', @level2type=N'COLUMN',@level2name=N'AcademicYearId' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Intake Capacity' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncProgrammeInstance', @level2type=N'COLUMN',@level2name=N'Intake' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Programme Instance' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'IncProgrammeInstancePart', @level2type=N'COLUMN',@level2name=N'ProgrammeInstanceId' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Address of the Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteAddress' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Code of the city' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'CityName' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Pincode' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'Pincode' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Contact No of Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteContactNo' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Fax no of Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteFaxNo' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Email Id of Head of Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteEmail' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Website Url of the Faculty' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'InstituteUrl' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Inactive in case name change or modified' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'IsActive' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Soft Delete' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstInstitute', @level2type=N'COLUMN',@level2name=N'IsDeleted' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Name of Paper' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstPaper', @level2type=N'COLUMN',@level2name=N'PaperName' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Code of paper' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstPaper', @level2type=N'COLUMN',@level2name=N'PaperCode' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Name of the Programme (Bachelor of Commerce)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeName' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Short name of the Programme (B.Com.)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeCode' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Faculty from which the programme is offered' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'FacultyId' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Level of Programme like Certificate, Under Graduate, Diploma' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeLevelId' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Mode of Programme: Regular or Distance ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeModeId' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Type: General/Technical/Research' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeTypeId' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Medium of Instruction' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'InstructionMediumId' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Evaluation : Marks/Direct Grade/Indirect Grade' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'EvaluationId' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Total Programme duration in Months' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeDuration' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Validity of Programme in Months' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'ProgrammeValidity' -GO -EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Total Year or Parts of the Programme' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'MstProgramme', @level2type=N'COLUMN',@level2name=N'TotalParts' -GO diff --git a/RABBITMQ_MIGRATION.md b/RABBITMQ_MIGRATION.md deleted file mode 100644 index 532a80c..0000000 --- a/RABBITMQ_MIGRATION.md +++ /dev/null @@ -1,57 +0,0 @@ -# RabbitMQ Migration Summary - -## What was changed - -The backend has been migrated from Redis-based Celery configuration to RabbitMQ. - -### 1) Django/Celery settings updated -- `ClassLens_DB/ClassLens_DB/settings.py` - - Replaced `CELERY_BROKER_URL` source from `REDIS_URL` to `RABBITMQ_URL`. - - Replaced `CELERY_RESULT_BACKEND` from Redis URL to `rpc://` (RabbitMQ-compatible Celery result backend). - - Removed `django_redis` from `INSTALLED_APPS`. - - Replaced Redis cache backend with Django local memory cache: - - `django.core.cache.backends.locmem.LocMemCache` - -### 2) Celery app config updated -- `ClassLens_DB/ClassLens_DB/celery.py` - - Replaced Redis URL variable with RabbitMQ URL variable. - - Updated `broker_url` to use `RABBITMQ_URL`. - - Updated `result_backend` to `rpc://`. - -### 3) Environment configuration updated -- `ClassLens_DB/.env` - - Removed Redis URL entry. - - Added RabbitMQ broker URL: - -```env -RABBITMQ_URL=amqp://guest:guest@localhost:5672// -``` - -### 4) Dependencies cleaned up -- `requirements.txt` -- `ClassLens_DB/requirements.txt` - - Removed: - - `django-redis` - - `redis` - -### 5) Documentation updated -- `README.md` - - Replaced Redis references with RabbitMQ references. - - Updated environment variable docs to `RABBITMQ_URL`. - - Replaced Redis setup section with RabbitMQ setup instructions. - - Added RabbitMQ management UI credentials: - - URL: `http://localhost:15672/` - - Username: `guest` - - Password: `guest` - -## RabbitMQ values in use - -- Broker URL: `amqp://guest:guest@localhost:5672//` -- Management UI: `http://localhost:15672/` -- Username: `guest` -- Password: `guest` - -## Notes - -- Celery with RabbitMQ does not use Redis as result backend; `rpc://` is now used. -- If you run Celery workers, ensure RabbitMQ server is running before starting workers. diff --git a/data-1778222711514.csv b/data-1778222711514.csv deleted file mode 100644 index f9a6e22..0000000 --- a/data-1778222711514.csv +++ /dev/null @@ -1,103 +0,0 @@ -"table_name","column_name","data_type","is_nullable" -"Home_adminuser","id","bigint","NO" -"Home_adminuser","username","character varying","NO" -"Home_adminuser","password","character varying","NO" -"Home_adminuser","is_active","boolean","NO" -"Home_adminuser","created_at","timestamp with time zone","NO" -"Home_attendancephotos","id","bigint","NO" -"Home_attendancephotos","photo","character varying","NO" -"Home_attendancephotos","uploaded_at","timestamp with time zone","NO" -"Home_attendancephotos","class_session_id","bigint","NO" -"Home_attendancerecord","id","bigint","NO" -"Home_attendancerecord","status","boolean","NO" -"Home_attendancerecord","marked_at","timestamp with time zone","NO" -"Home_attendancerecord","class_session_id","bigint","NO" -"Home_attendancerecord","student_id","bigint","NO" -"Home_classsession","id","bigint","NO" -"Home_classsession","year","integer","NO" -"Home_classsession","class_datetime","timestamp with time zone","NO" -"Home_classsession","department_id","bigint","NO" -"Home_classsession","subject_id","bigint","NO" -"Home_classsession","teacher_id","bigint","NO" -"Home_department","id","bigint","NO" -"Home_department","name","text","NO" -"Home_student","id","bigint","NO" -"Home_student","prn","bigint","NO" -"Home_student","name","text","NO" -"Home_student","email","character varying","NO" -"Home_student","password_hash","text","YES" -"Home_student","year","integer","NO" -"Home_student","face_embedding","USER-DEFINED","YES" -"Home_student","notification_token","text","YES" -"Home_student","department_id","bigint","NO" -"Home_studentattendancepercentage","id","bigint","NO" -"Home_studentattendancepercentage","present_count","integer","NO" -"Home_studentattendancepercentage","attendancePercentage","double precision","NO" -"Home_studentattendancepercentage","student_id","bigint","NO" -"Home_studentattendancepercentage","subject_id","bigint","NO" -"Home_studentenrollment","id","bigint","NO" -"Home_studentenrollment","student_prn","bigint","NO" -"Home_studentenrollment","subject_id","bigint","NO" -"Home_subject","id","bigint","NO" -"Home_subject","code","text","NO" -"Home_subject","name","text","NO" -"Home_subjectfromdept","id","bigint","NO" -"Home_subjectfromdept","year","integer","NO" -"Home_subjectfromdept","semester","integer","NO" -"Home_subjectfromdept","department_id","bigint","NO" -"Home_subjectfromdept_subject","id","bigint","NO" -"Home_subjectfromdept_subject","subjectfromdept_id","bigint","NO" -"Home_subjectfromdept_subject","subject_id","bigint","NO" -"Home_teacher","id","bigint","NO" -"Home_teacher","name","text","NO" -"Home_teacher","email","character varying","NO" -"Home_teacher","password_hash","text","YES" -"Home_teacher","date_joined","date","YES" -"Home_teacher","department_id","bigint","NO" -"Home_teachersubject","id","bigint","NO" -"Home_teachersubject","subject_id","bigint","NO" -"Home_teachersubject","teacher_id_id","bigint","NO" -"auth_group","id","integer","NO" -"auth_group","name","character varying","NO" -"auth_group_permissions","id","bigint","NO" -"auth_group_permissions","group_id","integer","NO" -"auth_group_permissions","permission_id","integer","NO" -"auth_permission","id","integer","NO" -"auth_permission","name","character varying","NO" -"auth_permission","content_type_id","integer","NO" -"auth_permission","codename","character varying","NO" -"auth_user","id","integer","NO" -"auth_user","password","character varying","NO" -"auth_user","last_login","timestamp with time zone","YES" -"auth_user","is_superuser","boolean","NO" -"auth_user","username","character varying","NO" -"auth_user","first_name","character varying","NO" -"auth_user","last_name","character varying","NO" -"auth_user","email","character varying","NO" -"auth_user","is_staff","boolean","NO" -"auth_user","is_active","boolean","NO" -"auth_user","date_joined","timestamp with time zone","NO" -"auth_user_groups","id","bigint","NO" -"auth_user_groups","user_id","integer","NO" -"auth_user_groups","group_id","integer","NO" -"auth_user_user_permissions","id","bigint","NO" -"auth_user_user_permissions","user_id","integer","NO" -"auth_user_user_permissions","permission_id","integer","NO" -"django_admin_log","id","integer","NO" -"django_admin_log","action_time","timestamp with time zone","NO" -"django_admin_log","object_id","text","YES" -"django_admin_log","object_repr","character varying","NO" -"django_admin_log","action_flag","smallint","NO" -"django_admin_log","change_message","text","NO" -"django_admin_log","content_type_id","integer","YES" -"django_admin_log","user_id","integer","NO" -"django_content_type","id","integer","NO" -"django_content_type","app_label","character varying","NO" -"django_content_type","model","character varying","NO" -"django_migrations","id","bigint","NO" -"django_migrations","app","character varying","NO" -"django_migrations","name","character varying","NO" -"django_migrations","applied","timestamp with time zone","NO" -"django_session","session_key","character varying","NO" -"django_session","session_data","text","NO" -"django_session","expire_date","timestamp with time zone","NO" diff --git a/db-chat.txt b/db-chat.txt deleted file mode 100644 index 2b822db..0000000 --- a/db-chat.txt +++ /dev/null @@ -1,132 +0,0 @@ - -Based on your clarification—that you're fetching data from an API with the structure of the DBMSUIS_V7.sql file (MSUIS v7 database schema), and you'll implement attendance-related services yourself—I'll provide a mapping of the exact data you can fetch and map from this file to your backend's required schema. I'll also list the remaining data/services that need to be implemented separately (e.g., attendance, admin, and other missing features). - -Key Assumptions -The MSUIS API will provide data in JSON/REST format mirroring the SQL tables (e.g., endpoints like /MstStudent, /MstFaculty, etc.). -Mapping is based on inferred fields from the SQL dump (via grep searches and references). Some fields are confirmed (e.g., PRN in MstStudent), others are assumed based on typical university schemas. -You'll need to transform/map the data during API calls (e.g., via scripts or Django views) to fit your models. -Missing tables/fields in MSUIS mean you'll skip or default them (e.g., set face_embedding to null). -No direct "teacher" table in MSUIS; faculty might serve as departments/teachers, but you'll need to adapt. -Mapped Data: What You Can Fetch and Map from MSUIS -Here's the mapping from MSUIS tables to your backend tables/fields. Only map what's available; for missing fields, use defaults or skip. - -Home_department (Map from MstFaculty) - -MSUIS Source: MstFaculty (referenced in foreign keys; CREATE TABLE not in dump, but fields inferred from usage: Id, Name, etc.). -Mapping: -id → MstFaculty.Id (primary key). -name → MstFaculty.Name (or similar field; assume it's the faculty name as department). -Notes: Faculty in MSUIS seems to represent departments/schools. If MstFaculty has more fields (e.g., code), map accordingly. No direct match for other fields. -Home_teacher (Partial Map from MstFaculty or None) - -MSUIS Source: No direct table (MstFaculty is more like departments). If faculty members are stored elsewhere, use MstFaculty; otherwise, no data. -Mapping (if using MstFaculty as proxy): -id → MstFaculty.Id. -name → MstFaculty.Name (assume name field exists). -email → Not available (default to null or generate). -password_hash → Not available (implement separately or default). -department_id → Self-reference or link to another MstFaculty if hierarchical. -date_joined → Not available (default to current date). -Notes: MSUIS may not track individual teachers. You might need to create teacher records manually or map from other sources. -Home_student (Map from MstStudent) - -MSUIS Source: MstStudent (fields inferred: PRN, FirstName, MiddleName, LastName, Email, etc.). -Mapping: -id → Auto-generated (MSUIS uses PRN as key, but map to your id). -prn → MstStudent.PRN. -name → Concatenate FirstName + MiddleName + LastName (or FullName if available). -email → MstStudent.Email. -password_hash → Not available (implement hashing separately or default). -year → From IncStudentAcademicInformation.Year (linked via PRN). -department_id → MstStudent.FacultyId (maps to Home_department). -face_embedding → Not available (implement facial recognition separately). -notification_token → Not available (implement push notifications separately). -Notes: Link to IncStudentAcademicInformation for year/department details. -Home_subject (Map from MstPaper) - -MSUIS Source: MstPaper (fields: Id, Code, Name, etc.). -Mapping: -id → MstPaper.Id. -code → MstPaper.Code. -name → MstPaper.Name. -Notes: Papers in MSUIS are subjects/courses. -Home_subjectfromdept (Partial Map from IncProgrammeInstancePartTerm or Mappings) - -MSUIS Source: IncProgrammeInstancePartTerm (links programmes, parts, terms) and MstProgrammePartTermPaperMap. -Mapping: -id → Auto-generated. -department_id → IncProgrammeInstancePartTerm.FacultyId (or from MstProgramme). -year → IncProgrammeInstancePartTerm.Year. -semester → IncProgrammeInstancePartTerm.Semester (or Term). -Subject many-to-many: From MstProgrammePartTermPaperMap.PaperId. -Notes: Complex; map programmes as departments. -Home_studentenrollment (Map from IncStudentPartTermPaperMap) - -MSUIS Source: IncStudentPartTermPaperMap (PRN, PaperId, etc.). -Mapping: -id → Auto-generated. -student_prn → IncStudentPartTermPaperMap.PRN. -subject_id → IncStudentPartTermPaperMap.PaperId. -Notes: Direct mapping for enrollments. -Home_teachersubject (No Direct Map) - -MSUIS Source: None (no teacher-subject links). -Mapping: Skip or create manually (e.g., assign based on programmes). -Notes: Implement separately. -Home_classsession (No Direct Map) - -MSUIS Source: None. -Mapping: Implement separately (your attendance service will create these). -Home_attendancephotos (No Direct Map) - -MSUIS Source: None. -Mapping: Implement separately. -Home_attendancerecord (No Direct Map) - -MSUIS Source: None. -Mapping: Implement separately. -Home_studentattendancepercentage (No Direct Map) - -MSUIS Source: None. -Mapping: Implement separately. -Home_adminuser (No Direct Map) - -MSUIS Source: None. -Mapping: Implement separately. -Home_subjectfromdept_subject (Map from Junctions) - -MSUIS Source: MstProgrammePartTermPaperMap or similar. -Mapping: subjectfromdept_id and subject_id from mappings. -Remaining Data/Services to Implement -Since MSUIS lacks attendance, admin, and some core features, you'll need to build these yourself. Here's what to implement: - -Attendance System: - -Tables: Home_classsession, Home_attendancephotos, Home_attendancerecord, Home_studentattendancepercentage. -Services: Facial recognition (DeepFace), photo upload, attendance marking, notifications (FCM), task queuing (Celery). -APIs: Mark attendance, get attendance status, teacher subjects, student dashboard, etc. -Authentication & Admin: - -Table: Home_adminuser. -Services: JWT login for admins, password hashing, user management. -APIs: Admin login, CRUD for all models. -Missing Fields/Data: - -password_hash for students/teachers (hash during registration). -face_embedding (generate via DeepFace on photo upload). -notification_token (store on app login). -date_joined for teachers (set on creation). -Teacher-subject assignments (manual or based on programmes). -Class sessions (create dynamically for attendance). -Other Services: - -OTP/email verification. -Dashboard stats (counts from fetched data). -Bulk uploads (CSV/Excel for students/teachers). -Health checks. -Implementation Steps -Fetch from MSUIS API: Use endpoints like GET /MstStudent to pull data, then map/transform in Django (e.g., in views or management commands). -Populate DB: Run scripts to insert mapped data into your models. -Build Missing Parts: Develop the attendance app as per your existing code (models, views, tasks). -Testing: Validate mappings with sample data; ensure foreign keys align. -If you share sample API responses from MSUIS or need code snippets for mapping, I can refine this! \ No newline at end of file diff --git a/setup_backend.bat b/setup_backend.bat deleted file mode 100644 index 999966a..0000000 --- a/setup_backend.bat +++ /dev/null @@ -1,85 +0,0 @@ -@echo off -REM ClassLens Backend Setup Script - -cd /d "m:\ClassLens\classLenseBackend\ClassLens\ClassLens_DB" - -echo. -echo ======================================== -echo ClassLens Backend Setup & Migration -echo ======================================== -echo. - -REM Activate virtual environment -echo [1/5] Activating Python virtual environment... -call .\.venv\Scripts\activate.bat - -if %ERRORLEVEL% NEQ 0 ( - echo ERROR: Failed to activate virtual environment - pause - exit /b 1 -) - -REM Make migrations -echo. -echo [2/5] Creating database migrations... -python manage.py makemigrations Home -if %ERRORLEVEL% NEQ 0 echo WARNING: makemigrations for Home had issues - -python manage.py makemigrations DatabaseAdminApp -if %ERRORLEVEL% NEQ 0 echo WARNING: makemigrations for DatabaseAdminApp had issues - -REM Run migrations -echo. -echo [3/5] Running database migrations... -python manage.py migrate -if %ERRORLEVEL% NEQ 0 ( - echo ERROR: Migration failed - echo Please check your database configuration in .env - pause - exit /b 1 -) - -REM Create default admin user -echo. -echo [4/5] Creating default admin user... -python manage.py shell << EOF -from Home.models import AdminUser -import os - -username = "admin" -password = "admin@123456" - -# Check if admin user already exists -if not AdminUser.objects.filter(username=username).exists(): - admin = AdminUser(username=username, is_active=True) - admin.set_password(password) - admin.save() - print(f"✓ Admin user created: {username}") - print(f" Password: {password}") -else: - print(f"✓ Admin user '{username}' already exists") -EOF - -REM Check Django setup -echo. -echo [5/5] Checking Django setup... -python manage.py check -if %ERRORLEVEL% NEQ 0 ( - echo WARNING: Django check reported issues -) - -echo. -echo ======================================== -echo Setup Complete! -echo ======================================== -echo. -echo Next steps: -echo 1. Ensure PostgreSQL is running -echo 2. Ensure Redis is running (for Celery results) -echo 3. Optionally start RabbitMQ (if not running, Celery will queue locally) -echo 4. Run: python manage.py runserver -echo 5. Login at http://localhost:8000/api/admin/login/ -echo Username: admin -echo Password: admin@123456 -echo. -pause From 1378fcf4ee516569f9d675a18a84a2180c0cd8d0 Mon Sep 17 00:00:00 2001 From: Dhriti-5 Date: Wed, 3 Jun 2026 10:55:27 +0530 Subject: [PATCH 13/14] updated .gitignore --- add_teacher_data.py | 53 --------------------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 add_teacher_data.py diff --git a/add_teacher_data.py b/add_teacher_data.py deleted file mode 100644 index 01d61a2..0000000 --- a/add_teacher_data.py +++ /dev/null @@ -1,53 +0,0 @@ -# Script to add teacher, subject and department data -# Run this with: python manage.py shell < add_teacher_data.py - -from Home.models import Department, Teacher, Subject, TeacherSubject - -# Create or get the Department -department, created = Department.objects.get_or_create( - name="Computer Science and Engineering" -) -if created: - print(f"✓ Created Department: {department.name}") -else: - print(f"✓ Department already exists: {department.name}") - -# Create or get the Subject -subject, created = Subject.objects.get_or_create( - name="Design and Analysis of Algorithms-CSE", - defaults={'code': 'DAA-CSE'} # You can change this code if needed -) -if created: - print(f"✓ Created Subject: {subject.name}") -else: - print(f"✓ Subject already exists: {subject.name}") - -# Create or get the Teacher -teacher, created = Teacher.objects.get_or_create( - email="viral.kapadia-cse@msubaroda.ac.in", - defaults={ - 'name': "Viral Kapadia", - 'department': department - } -) -if created: - print(f"✓ Created Teacher: {teacher.name}") -else: - print(f"✓ Teacher already exists: {teacher.name}") - # Update department if teacher already exists - if teacher.department != department: - teacher.department = department - teacher.save() - print(f" Updated teacher's department") - -# Link Teacher to Subject -teacher_subject, created = TeacherSubject.objects.get_or_create( - teacher_id=teacher, - subject=subject -) -if created: - print(f"✓ Created TeacherSubject link: {teacher.name} teaches {subject.name}") -else: - print(f"✓ TeacherSubject link already exists") - -print("\n✅ All data added successfully!") From dd0f069af4953b552fa57e65078d02d0b0be9f3e Mon Sep 17 00:00:00 2001 From: Dhriti-5 Date: Thu, 4 Jun 2026 16:23:14 +0530 Subject: [PATCH 14/14] change view.py to calculate attendance statstics --- ClassLens_DB/ClassLens_DB/settings.py | 2 +- ClassLens_DB/Home/views.py | 64 ++++++++++++++++++++------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/ClassLens_DB/ClassLens_DB/settings.py b/ClassLens_DB/ClassLens_DB/settings.py index e8ba4da..3c00e49 100644 --- a/ClassLens_DB/ClassLens_DB/settings.py +++ b/ClassLens_DB/ClassLens_DB/settings.py @@ -33,13 +33,13 @@ DEBUG = True ALLOWED_HOSTS = [ + '172.25.13.31', '172.16.141.247', '172.26.12.236', '10.0.2.2', '14.139.121.110', 'localhost', '127.0.0.1', - '172.25.13.31', '10.0.3.2', ] diff --git a/ClassLens_DB/Home/views.py b/ClassLens_DB/Home/views.py index 7efe5d4..0b0a4d0 100644 --- a/ClassLens_DB/Home/views.py +++ b/ClassLens_DB/Home/views.py @@ -564,6 +564,7 @@ def update_face(request, *args, **kwargs): def get_student_attendance(request, *args, **kwargs): try: subject_id = request.data.get("subject_id") + division_id = request.data.get("division_id") if subject_id is None: return Response( @@ -571,20 +572,40 @@ def get_student_attendance(request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST, ) - total_sessions = ClassSession.objects.filter(subject_id=subject_id).count() - - attendance_data = StudentAttendancePercentage.objects.filter( - subject_id=subject_id - ).select_related('student') + # Fetch enrolled student PRNs from StudentEnrollment + enrolled_prns = StudentEnrollment.objects.filter(subject_id=subject_id).values_list('student_prn', flat=True) + + # Get Student records and annotate them with real total and attended counts from AttendanceRecord + students = Student.objects.filter(prn__in=enrolled_prns).annotate( + real_total_classes=Count( + 'attendancerecord', + filter=Q(attendancerecord__class_session__subject_id=subject_id) + ), + real_attended_classes=Count( + 'attendancerecord', + filter=Q(attendancerecord__class_session__subject_id=subject_id, attendancerecord__status=True) + ) + ) + if division_id: + students = students.filter(division_id=division_id) result = [] - for record in attendance_data: + for student in students: + total = student.real_total_classes + attended = student.real_attended_classes + + percentage = 0.0 + if total > 0: + percentage = (attended * 100.0) / total + if percentage > 100.0: + percentage = 100.0 + result.append({ - "student_id": record.student.id, - "student_name": record.student.name, - "total_classes": total_sessions, - "attended_classes": record.present_count, - "attendance_percentage": record.attendancePercentage + "student_id": student.id, + "student_name": student.name, + "total_classes": total, + "attended_classes": attended, + "attendance_percentage": percentage }) return Response( @@ -1072,11 +1093,22 @@ def get_student_dashboard(request, *args, **kwargs): percentage = data.attendancePercentage present_count = data.present_count - teacher = TeacherSubject.objects.filter(subject=subject, division=student.division).select_related('teacher_id').first() - if teacher is None and student.division is not None: - teacher = TeacherSubject.objects.filter(subject=subject, division__isnull=True).select_related('teacher_id').first() - if teacher is None: - teacher = TeacherSubject.objects.filter(subject=subject).select_related('teacher_id').first() + teacher = None + if student.division is not None: + teacher = TeacherSubject.objects.filter( + subject=subject, + division=student.division + ).select_related('teacher_id').first() + if teacher is None: + teacher = TeacherSubject.objects.filter( + subject=subject, + division__isnull=True + ).select_related('teacher_id').first() + else: + teacher = TeacherSubject.objects.filter( + subject=subject + ).select_related('teacher_id').first() + teacher_name = teacher.teacher_id.name if teacher else "N/A" subjects_data.append({