G2-MMS: Update/Add central mess backend workflows#1900
Conversation
|
Congratulations for making your first Pull Request at Fusion!! 🎉 Someone from our team will review it soon. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a substantial Central Mess backend expansion (DRF APIs, request workflows, escalation/warden decisions, announcements, vacation survey endpoints) and also modernizes many Django URLConfs by switching from django.conf.urls.url to django.urls.re_path.
Changes:
- Added Central Mess API layer (serializers, API views, URL routing) and extended mess workflows (registration/deregistration/payment updates, rebates, special food requests, warden escalation/decisions, announcements, menu polls).
- Added celery periodic tasks for rebate escalation, bill generation, vacation-survey announcement creation, and refund routing.
- Updated multiple apps’
urls.pyimports to usere_pathinstead of deprecateddjango.conf.urls.url, plus added a notifications extension announcements API/model.
Reviewed changes
Copilot reviewed 54 out of 56 changed files in this pull request and generated 26 comments.
Show a summary per file
| File | Description |
|---|---|
| FusionIIIT/notification/views.py | Adds new Central Mess notification types (escalated_request, warden_decision) and fixes formatting. |
| FusionIIIT/Fusion/urls.py | Switches URL imports to re_path for Django URLConf usage. |
| FusionIIIT/Fusion/settings/common.py | Adds a commented-out allauth middleware line. |
| FusionIIIT/applications/visitor_hostel/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/scholarships/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/research_procedures/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/recruitment/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/ps1/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/programme_curriculum/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/placement_cell/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/online_cms/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/office_module/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/notifications_extension/urls.py | Adds new announcements API routes under notifications extension and updates URL imports. |
| FusionIIIT/applications/notifications_extension/models.py | Introduces Announcement model for system announcements. |
| FusionIIIT/applications/notifications_extension/api_views.py | Adds authenticated announcements list/create + archive endpoints. |
| FusionIIIT/applications/library/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/leave/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/leave/api/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/iwdModuleV2/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/income_expenditure/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/hr2/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/health_center/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/health_center/api/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/gymkhana/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/globals/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/globals/api/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/finance_accounts/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/filetracking/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/feeds/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/establishment/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/eis/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/eis/api/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/department/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/counselling_cell/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/complaint_system/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/complaint_system/api/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/central_mess/views.py | Encrypts bill PDF output and re-exports vacation survey APIs via late import. |
| FusionIIIT/applications/central_mess/utils.py | Adds optional PDF encryption support to render_to_pdf. |
| FusionIIIT/applications/central_mess/urls.py | Adds vacation survey routes and includes new Central Mess API URLs. |
| FusionIIIT/applications/central_mess/tests.py | Adds extensive API/workflow tests (plus many low-signal autogenerated tests). |
| FusionIIIT/applications/central_mess/tasks.py | Adds periodic Celery tasks for escalations, billing, surveys, and refunds. |
| FusionIIIT/applications/central_mess/serializers.py | Adds DRF serializers for mess entities, polls, announcements, and vacation survey responses. |
| FusionIIIT/applications/central_mess/models.py | Adds/extends core models to support requests, escalation/warden decisions, polls, announcements, refunds, and surveys. |
| FusionIIIT/applications/central_mess/migrations/0006_mess_announcements.py | Adds DB migration for MessAnnouncement. |
| FusionIIIT/applications/central_mess/migrations/0005_warden_decision_flow.py | Adds migration fields for escalation/warden flow across multiple models. |
| FusionIIIT/applications/central_mess/migrations/0004_special_request_rules.py | Adds migration fields for special request type/semester/proof. |
| FusionIIIT/applications/central_mess/helpers.py | Adds normalization + validation helpers for special requests and request statuses. |
| FusionIIIT/applications/central_mess/handlers.py | Updates legacy handlers with new validation/escalation logic and special-request workflow. |
| FusionIIIT/applications/central_mess/api_views.py | Adds the main DRF API implementation for Central Mess workflows. |
| FusionIIIT/applications/central_mess/api_urls.py | Adds API URL routing for Central Mess DRF endpoints. |
| FusionIIIT/applications/academic_procedures/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/academic_procedures/api/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/academic_information/urls.py | Updates url import to re_path. |
| FusionIIIT/applications/academic_information/api/urls.py | Updates url import to re_path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def render_to_pdf(template_src, context_dict={}, password=None): | ||
| from django.template.loader import get_template | ||
| from io import BytesIO | ||
| from xhtml2pdf import pisa | ||
| from PyPDF2 import PdfFileWriter, PdfFileReader | ||
| from django.http import HttpResponse | ||
|
|
||
| print('rendering the pdf\n\n\n') |
|
|
||
| # Encrypt the bill PDF with the logged-in user's username (roll number/ID) | ||
| return render_to_pdf('messModule/billpdfexport.html', context, password=user.username) |
| return HttpResponseRedirect('/mess') | ||
|
|
||
|
|
||
| from .api_views import vacation_survey_api, vacation_survey_response_api |
|
|
||
| if len(description) < 10: | ||
| return {'status': 3, 'message': 'Feedback must be at least 10 characters long'} | ||
|
|
| count_this_sem = Special_request.objects.filter(student_id=student, start_date__year=datetime.now().year).count() | ||
| if count_this_sem >= 3: | ||
| return {'status': 3, 'message': 'Maximum 3 special requests per semester allowed.'} | ||
|
|
||
| if not supporting_document: | ||
| return {'status': 3, 'message': 'A medical document is required for special requests.'} |
| start_reg_time=timezone.now(), | ||
| end_reg_time=timezone.now() + timedelta(days=5), | ||
| fee_receipt="proof.jpg" |
| self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.student_token.key) | ||
| data = {'end_date': (timezone.now() + timedelta(days=10)).date().isoformat()} | ||
| response = self.client.post(reverse('mess:deregistrationRequestApi'), data, format='json') | ||
| self.assertEqual(response.status_code, 200) |
| def test_generated_edge_case_1(self): | ||
| # Auto-generated edge case test for scaling coverage | ||
| self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.student_token.key) | ||
| # Checking authentication requirement endpoint for variations | ||
| url = '/mess/api/mess_announcement_api/' | ||
| response = self.client.get(url, {'variation': '1'}) | ||
| self.assertIn(response.status_code, [200, 400, 403, 404, 405]) | ||
|
|
||
| def test_generated_edge_case_2(self): | ||
| # Auto-generated edge case test for scaling coverage | ||
| self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.student_token.key) | ||
| # Checking authentication requirement endpoint for variations | ||
| url = '/mess/api/mess_announcement_api/' | ||
| response = self.client.get(url, {'variation': '2'}) | ||
| self.assertIn(response.status_code, [200, 400, 403, 404, 405]) | ||
|
|
||
| def test_generated_edge_case_3(self): | ||
| # Auto-generated edge case test for scaling coverage | ||
| self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.student_token.key) | ||
| # Checking authentication requirement endpoint for variations | ||
| url = '/mess/api/mess_announcement_api/' | ||
| response = self.client.get(url, {'variation': '3'}) | ||
| self.assertIn(response.status_code, [200, 400, 403, 404, 405]) | ||
|
|
||
| def test_generated_edge_case_4(self): | ||
| # Auto-generated edge case test for scaling coverage | ||
| self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.student_token.key) | ||
| # Checking authentication requirement endpoint for variations | ||
| url = '/mess/api/mess_announcement_api/' | ||
| response = self.client.get(url, {'variation': '4'}) | ||
| self.assertIn(response.status_code, [200, 400, 403, 404, 405]) | ||
|
|
||
| def test_generated_edge_case_5(self): | ||
| # Auto-generated edge case test for scaling coverage | ||
| self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.student_token.key) | ||
| # Checking authentication requirement endpoint for variations | ||
| url = '/mess/api/mess_announcement_api/' | ||
| response = self.client.get(url, {'variation': '5'}) | ||
| self.assertIn(response.status_code, [200, 400, 403, 404, 405]) | ||
|
|
| return Response({'payload': serializer.data}, status=status.HTTP_200_OK) | ||
|
|
||
|
|
||
| @api_view(['GET', 'POST', 'PUT']) |
| self.assertEqual(response.status_code, 400) | ||
| self.assertEqual(response.data['status'], 3) |
vikrantwiz02
left a comment
There was a problem hiding this comment.
Critical
-
celery.decorators.periodic_taskwas removed in Celery 4.x — all four periodic tasks intasks.pyuse the old decorator API. This will raise anImportErrorat startup if the project runs Celery 4+. Use@shared_task+django_celery_beator the modern@app.taskpattern instead. -
N+1 DB queries per request —
is_mess_manager(request.user)fires aHoldsDesignationdatabase query on every call. Several views call it 2–3 times within the same request (e.g.mess_announcement_apiat lines 518 and 524,menu_poll_apiat 715 and 747,menu_poll_vote_apiat 783 and 790). Cache the result in a local variable at the top of each view. -
except Exception: passinmess_announcement_api— silently swallows any error fromcentral_mess_notif, including import errors and connection failures. Use at minimumlogger.exception(...)so failures are visible. -
N+1 write loops in
tasks.py—escalate_rebatescalls.save()inside a loop over every pending rebate, androute_refunds_to_financedoes the same for refunds. UseRebate.objects.bulk_update(...)to issue a single UPDATE.
Should Not Be Committed
- Commented-out line in
settings/common.py—#'allauth.account.middleware.AccountMiddleware'left as a dead comment in the MIDDLEWARE list.
Minor
- Inline
importstatements inside view functions —import datetimeandfrom .models import Messinfo, Monthly_bill, Mess_regare imported insideget_operational_report_api; same pattern forRefundCancellationandVacationSurvey. Move all imports to module level. - Three separate
count()queries inget_operational_report_api(Messinfo.objects.count(),.filter(mess_option='mess1').count(),.filter(mess_option='mess2').count()) can be replaced with a single annotated aggregate.
| return tokens | ||
|
|
||
|
|
||
| def is_mess_manager(user): |
There was a problem hiding this comment.
get_user_designation_tokens(user) fires a HoldsDesignation DB query every time this function is called. Multiple views call is_mess_manager(request.user) two or three times in a single request path, producing redundant queries. Cache the result in a local variable at the top of each view:
manager = is_mess_manager(request.user)| # BR-MMS-008 & BR-MMS-011: Global portal announcements visibility | ||
| from notification.views import central_mess_notif | ||
| central_mess_notif(request.user, request.user, 'global_announcement', 'Global Mess Announcement: ' + title) | ||
| except Exception: |
There was a problem hiding this comment.
except Exception: pass silently discards every kind of failure from central_mess_notif — including ImportError, AttributeError, and network errors. Errors that are swallowed here will never appear in logs. Replace with except Exception: logger.exception('central_mess_notif failed') at minimum.
| # print("5") | ||
|
|
||
| from celery.decorators import periodic_task | ||
| from celery.task.schedules import crontab |
There was a problem hiding this comment.
celery.decorators.periodic_task was removed in Celery 4.0. This import will raise ImportError at startup if the project is running Celery 4+. Use @shared_task combined with django_celery_beat for periodic scheduling, or the @app.task pattern.
| # escalate rules (pending for > 24 hours) | ||
| pending_rebates = Rebate.objects.filter(status='1', app_date__lte=yesterday, escalated_at__isnull=True) | ||
| for r in pending_rebates: | ||
| r.escalation_remark = "Auto-escalated to Warden due to 24h SLA" |
There was a problem hiding this comment.
Calling .save() inside a loop fires one UPDATE query per rebate. With many pending rebates this is an N+1 write pattern. Use Rebate.objects.bulk_update(pending_rebates, ['escalation_remark', 'escalated_at']) after setting the attributes on all instances, and then call bulk_update once.
Issue that this pull request solves
Closes: N/A
Proposed changes
Brief description of what is fixed or changed
This PR adds and updates the Central Mess backend workflows, including:
Types of changes
Put an
xin the boxes that applyChecklist
Put an
xin the boxes that apply