From 0c3b5260f95da933faa153d96b925cc6355b4cb0 Mon Sep 17 00:00:00 2001 From: Anishwar Sharma <81948807+anishwar-007@users.noreply.github.com> Date: Thu, 16 Feb 2023 22:46:53 +0530 Subject: [PATCH 01/19] GAD-2:ALL WEEKS: OVERALL CHANGES (#1092) --- FusionIIIT/applications/iwdModuleV2/views.py | 101 ++++++++++++------ FusionIIIT/templates/iwdModuleV2/Page1.html | 5 +- FusionIIIT/templates/iwdModuleV2/Page2.html | 31 ++++-- FusionIIIT/templates/iwdModuleV2/Page3.html | 8 +- .../templates/iwdModuleV2/createWork.html | 13 +-- .../iwdModuleV2/page1_support_1_aes.html | 3 +- .../page2_support_1_corrigendum.html | 2 +- .../templates/iwdModuleV2/viewWork.html | 3 +- 8 files changed, 105 insertions(+), 61 deletions(-) diff --git a/FusionIIIT/applications/iwdModuleV2/views.py b/FusionIIIT/applications/iwdModuleV2/views.py index 2b36550fc..7cc9cf67c 100644 --- a/FusionIIIT/applications/iwdModuleV2/views.py +++ b/FusionIIIT/applications/iwdModuleV2/views.py @@ -18,7 +18,7 @@ # in conjunction with SRS. After that, everything will become easier. def dashboard(request): - eligible = False + eligible = True userObj = request.user userDesignationObjects = HoldsDesignation.objects.filter(user=userObj) for p in userDesignationObjects: @@ -107,7 +107,8 @@ def page2_1(request): def corrigendumInput(request): if request.method == 'POST': - existingObject = CorrigendumTable.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = CorrigendumTable.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formObject = CorrigendumTable() @@ -128,7 +129,8 @@ def corrigendumInput(request): def addendumInput(request): if request.method == 'POST': - existingObject = Addendum.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = Addendum.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formObject = Addendum() @@ -145,7 +147,8 @@ def addendumInput(request): def PreBidForm(request): if request.method == 'POST': - existingObject = PreBidDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = PreBidDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formObject = PreBidDetails() @@ -161,9 +164,11 @@ def PreBidForm(request): def noOfEntriesTechnicalBid(request): formNoTechnicalObjects = NoOfTechnicalBidTimes() - formNoTechnicalObjects.key = Projects.objects.get(id=request.session['projectId']) + formNoTechnicalObjects.key = Projects.objects.get( + id=request.session['projectId']) if request.method == 'POST': - existingObject = NoOfTechnicalBidTimes.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = NoOfTechnicalBidTimes.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formNoTechnicalObjects.number = int(request.POST['number']) @@ -174,9 +179,11 @@ def noOfEntriesTechnicalBid(request): def TechnicalBidForm(request): formObject = TechnicalBidDetails() - numberOfTechnicalBidTimes = NoOfTechnicalBidTimes.objects.get(key=Projects.objects.get(id=request.session['projectId'])).number + numberOfTechnicalBidTimes = NoOfTechnicalBidTimes.objects.get( + key=Projects.objects.get(id=request.session['projectId'])).number if request.method == 'POST': - existingObject = TechnicalBidDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = TechnicalBidDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formObject = TechnicalBidDetails() @@ -184,12 +191,14 @@ def TechnicalBidForm(request): formObject.sNo = request.POST['sNo'] formObject.requirements = request.POST['requirements'] formObject.save() - TechnicalBidContractorDetails.objects.filter(key=formObject).all().delete() + TechnicalBidContractorDetails.objects.filter( + key=formObject).all().delete() for w in range(numberOfTechnicalBidTimes): formContractorObject = TechnicalBidContractorDetails() formContractorObject.key = formObject formContractorObject.name = request.POST[str(w) + 'name'] - formContractorObject.description = request.POST[str(w) + 'Description'] + formContractorObject.description = request.POST[str( + w) + 'Description'] formContractorObject.save() return redirect('iwdModuleV2/noOfEntriesFinancialBid') return render(request, 'iwdModuleV2/page2_support_4_technicalbid.html', @@ -198,12 +207,15 @@ def TechnicalBidForm(request): def noOfEntriesFinancialBid(request): listOfContractors = [] - objectTechnicalBid = TechnicalBidDetails.objects.get(key=Projects.objects.get(id=request.session['projectId'])) - objects = TechnicalBidContractorDetails.objects.filter(key=objectTechnicalBid) + objectTechnicalBid = TechnicalBidDetails.objects.get( + key=Projects.objects.get(id=request.session['projectId'])) + objects = TechnicalBidContractorDetails.objects.filter( + key=objectTechnicalBid) for t in objects: listOfContractors.append(t.name) if request.method == 'POST': - existingObject = FinancialBidDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = FinancialBidDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formObject = FinancialBidDetails() @@ -217,7 +229,8 @@ def noOfEntriesFinancialBid(request): formContractorObject.name = listOfContractors[f] formContractorObject.totalCost = request.POST[listOfContractors[f] + 'totalCost'] formContractorObject.estimatedCost = request.POST[listOfContractors[f] + 'estimatedCost'] - formContractorObject.percentageRelCost = request.POST[listOfContractors[f] + 'percentageRelCost'] + formContractorObject.percentageRelCost = request.POST[ + listOfContractors[f] + 'percentageRelCost'] formContractorObject.perFigures = request.POST[listOfContractors[f] + 'perFigures'] formContractorObject.save() return redirect('iwdModuleV2/letterOfIntent') @@ -227,7 +240,8 @@ def noOfEntriesFinancialBid(request): def letterOfIntent(request): if request.method == 'POST': - existingObject = LetterOfIntentDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = LetterOfIntentDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formObject = LetterOfIntentDetails() @@ -244,7 +258,8 @@ def letterOfIntent(request): def workOrderForm(request): if request.method == 'POST': - existingObject = WorkOrderForm.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = WorkOrderForm.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formObject = WorkOrderForm() @@ -267,7 +282,8 @@ def workOrderForm(request): def AgreementInput(request): if request.method == 'POST': - existingObject = Agreement.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + existingObject = Agreement.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) if existingObject.count() == 1: existingObject.delete() formObject = Agreement() @@ -291,7 +307,8 @@ def milestonesForm(request): formObject.timeAllowed = request.POST['timeAllowed'] formObject.save() return redirect('iwdModuleV2/page3_1') - Milestones.objects.filter(key=Projects.objects.get(id=request.session['projectId'])).all().delete() + Milestones.objects.filter(key=Projects.objects.get( + id=request.session['projectId'])).all().delete() return render(request, 'iwdModuleV2/page2_support_9_milestone.html', {}) @@ -321,35 +338,42 @@ def ExtensionOfTimeForm(request): def page1View(request): - request.session['projectId'] = request.POST['id'] - projectPageOne = PageOneDetails.objects.get(id=Projects.objects.get(id=request.session['projectId'])) + if request.POST: + request.session['projectId'] = request.POST['id'] + projectPageOne = PageOneDetails.objects.get( + id=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/Page1.html', {'x': projectPageOne}) def page2View(request): - projectPageTwo = PageTwoDetails.objects.get(id=Projects.objects.get(id=request.session['projectId'])) + projectPageTwo = PageTwoDetails.objects.get( + id=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/Page2.html', {'x': projectPageTwo}) def AESView(request): - objects = AESDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + objects = AESDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/AA&ES.html', {'AES': objects}) def financialBidView(request): elements = [] - objects = FinancialBidDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + objects = FinancialBidDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) for f in objects: contractorObjects = FinancialContractorDetails.objects.filter(key=f) for w in contractorObjects: - obj = [f.sNo, f.description, w.name, w.estimatedCost, w.percentageRelCost, w.perFigures, w.totalCost] + obj = [f.sNo, f.description, w.name, w.estimatedCost, + w.percentageRelCost, w.perFigures, w.totalCost] elements.append(obj) return render(request, 'iwdModuleV2/Page2_financialbid.html', {'financial': elements}) def technicalBidView(request): elements = [] - objects = TechnicalBidDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + objects = TechnicalBidDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) for f in objects: contractorObjects = TechnicalBidContractorDetails.objects.filter(key=f) for w in contractorObjects: @@ -359,45 +383,54 @@ def technicalBidView(request): def preBidDetailsView(request): - preBidObjects = PreBidDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + preBidObjects = PreBidDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/Page2_pre-bid.html', {'preBidDetails': preBidObjects}) def corrigendumView(request): - corrigendumObject = CorrigendumTable.objects.get(key=Projects.objects.get(id=request.session['projectId'])) + corrigendumObject = CorrigendumTable.objects.get( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/corrigendum.html', {'corrigendum': corrigendumObject}) def addendumView(request): - addendumObject = Addendum.objects.get(key=Projects.objects.get(id=request.session['projectId'])) + addendumObject = Addendum.objects.get( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/Addendum.html', {'x': addendumObject}) def letterOfIntentView(request): - letterOfIntentObject = LetterOfIntentDetails.objects.get(key=Projects.objects.get(id=request.session['projectId'])) + letterOfIntentObject = LetterOfIntentDetails.objects.get( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/letterOfIntent.html', {'x': letterOfIntentObject}) def workOrderFormView(request): - workOrderFormObject = WorkOrderForm.objects.get(key=Projects.objects.get(id=request.session['projectId'])) + workOrderFormObject = WorkOrderForm.objects.get( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/WorkOrderForm.html', {'x': workOrderFormObject}) def agreementView(request): - agreementObject = Agreement.objects.get(key=Projects.objects.get(id=request.session['projectId'])) + agreementObject = Agreement.objects.get( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/Agreement.html', {'agreement': agreementObject}) def milestoneView(request): - milestoneObjects = Milestones.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + milestoneObjects = Milestones.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/Page2_milestones.html', {'milestones': milestoneObjects}) def page3View(request): - pageThreeDetails = PageThreeDetails.objects.get(id=Projects.objects.get(id=request.session['projectId'])) + pageThreeDetails = PageThreeDetails.objects.get( + id=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/Page3.html', {'x': pageThreeDetails}) def extensionFormView(request): - extensionObjects = ExtensionOfTimeDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) + extensionObjects = ExtensionOfTimeDetails.objects.filter( + key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/ExtensionForm.html', {'extension': extensionObjects}) diff --git a/FusionIIIT/templates/iwdModuleV2/Page1.html b/FusionIIIT/templates/iwdModuleV2/Page1.html index 8e7eac710..bfd2d8a69 100644 --- a/FusionIIIT/templates/iwdModuleV2/Page1.html +++ b/FusionIIIT/templates/iwdModuleV2/Page1.html @@ -65,7 +65,7 @@ AA And AES
Download
-
i
+
i
@@ -111,7 +111,8 @@ - Next + Next + {% if var %}

{{var}}

{% endif %} diff --git a/FusionIIIT/templates/iwdModuleV2/Page2.html b/FusionIIIT/templates/iwdModuleV2/Page2.html index 9f933e3be..715244f82 100644 --- a/FusionIIIT/templates/iwdModuleV2/Page2.html +++ b/FusionIIIT/templates/iwdModuleV2/Page2.html @@ -65,7 +65,7 @@ Corrigendum
Download
-
i
+
i
@@ -73,7 +73,8 @@ Addendum
Download
-
i
+ +
i
@@ -81,7 +82,8 @@ Pre-bid meeting details
Download
-
i
+ +
i
@@ -89,7 +91,8 @@ Technical-bid meeting details
Download
-
i
+ +
i
@@ -101,7 +104,8 @@ Financial-bid meeting details
Download
-
i
+ +
i
@@ -113,7 +117,8 @@ Letter of intent
Download
-
i
+ +
i
@@ -121,7 +126,8 @@ Work order
Download
-
i
+ +
i
@@ -129,7 +135,8 @@ Agreement Letter
Download
-
i
+ +
i
@@ -137,13 +144,15 @@ Milestones
Download
-
i
+ +
i
- Next + Prev + Next @@ -178,4 +187,4 @@ -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/Page3.html b/FusionIIIT/templates/iwdModuleV2/Page3.html index d19ae128d..ddde765e5 100644 --- a/FusionIIIT/templates/iwdModuleV2/Page3.html +++ b/FusionIIIT/templates/iwdModuleV2/Page3.html @@ -65,7 +65,8 @@ Extension of time
Download
-
i
+ +
i
@@ -76,7 +77,8 @@ - Next + Prev + Back To Home @@ -110,4 +112,4 @@ -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/createWork.html b/FusionIIIT/templates/iwdModuleV2/createWork.html index 04323ba15..7fa533571 100644 --- a/FusionIIIT/templates/iwdModuleV2/createWork.html +++ b/FusionIIIT/templates/iwdModuleV2/createWork.html @@ -4,20 +4,17 @@ Create Project Requisition: -
+
- - -
+ -
+ - -
+ -
+
diff --git a/FusionIIIT/templates/iwdModuleV2/page1_support_1_aes.html b/FusionIIIT/templates/iwdModuleV2/page1_support_1_aes.html index ed6ff8543..a5da06deb 100644 --- a/FusionIIIT/templates/iwdModuleV2/page1_support_1_aes.html +++ b/FusionIIIT/templates/iwdModuleV2/page1_support_1_aes.html @@ -125,7 +125,8 @@

- + Prev +

diff --git a/FusionIIIT/templates/iwdModuleV2/page2_support_1_corrigendum.html b/FusionIIIT/templates/iwdModuleV2/page2_support_1_corrigendum.html index f372125ac..151e5afc0 100644 --- a/FusionIIIT/templates/iwdModuleV2/page2_support_1_corrigendum.html +++ b/FusionIIIT/templates/iwdModuleV2/page2_support_1_corrigendum.html @@ -100,7 +100,7 @@
- Next + Prev diff --git a/FusionIIIT/templates/iwdModuleV2/viewWork.html b/FusionIIIT/templates/iwdModuleV2/viewWork.html index 3fb49831f..d67b8d528 100644 --- a/FusionIIIT/templates/iwdModuleV2/viewWork.html +++ b/FusionIIIT/templates/iwdModuleV2/viewWork.html @@ -1,6 +1,7 @@
-
{% csrf_token %} + + {% csrf_token %}

From 5535dd49b45ae7f82f3fefe939657e936c68fe8a Mon Sep 17 00:00:00 2001 From: JAYANT JAIN <56956286+jayant26@users.noreply.github.com> Date: Sun, 26 Mar 2023 17:50:03 +0530 Subject: [PATCH 02/19] gad-2: improved CSS of page_1 and corrigendum of IWD module (#1112) --- .../templates/iwdModuleV2/page1_create.html | 2 +- .../page2_support_1_corrigendum.html | 204 ++++++++++-------- 2 files changed, 121 insertions(+), 85 deletions(-) diff --git a/FusionIIIT/templates/iwdModuleV2/page1_create.html b/FusionIIIT/templates/iwdModuleV2/page1_create.html index c549fe90f..de798b7cb 100644 --- a/FusionIIIT/templates/iwdModuleV2/page1_create.html +++ b/FusionIIIT/templates/iwdModuleV2/page1_create.html @@ -78,7 +78,7 @@
- +

+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+ {% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/createdRequests.html b/FusionIIIT/templates/iwdModuleV2/createdRequests.html new file mode 100644 index 000000000..a7f86e523 --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/createdRequests.html @@ -0,0 +1,120 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} +Academic +{% endblock %} + + +{% block body %} +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ +
+
+ Created Requests +
+
+
+
+ + + + + + + + + + + + + + {% for f in obj %} + + + + + + + + + + + {% endfor %} +
Details:-
IdNameDescriptionAreaCreated By
{{f.0}}{{f.1}}{{f.3}}{{f.2}}{{f.4}} + +
+ {% csrf_token %} + + +
+
+
+
+
+ + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+{% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/dashboard.html b/FusionIIIT/templates/iwdModuleV2/dashboard.html index 9f0e1db49..12c27a550 100644 --- a/FusionIIIT/templates/iwdModuleV2/dashboard.html +++ b/FusionIIIT/templates/iwdModuleV2/dashboard.html @@ -34,28 +34,24 @@
{% comment %}ROW #2 starts here!{% endcomment %} - {% if eligible %} + {% if eligible == "Engineer" %}
{% comment %}The Tab-Menu starts here!{% endcomment %} {% comment %}The Tab-Menu ends here!{% endcomment %} @@ -69,22 +65,63 @@ {% comment %}The central-rail segment starts here!{% endcomment %}
{% comment %}The Appointments Form starts here!{% endcomment %} -
+
{% block appointment %} - {% include 'iwdModuleV2/createWork.html' %} + {% include 'iwdModuleV2/requestsView.html' %} {% endblock %}
- {% comment %}The appointment Form ends here!{% endcomment %} - {% comment %}The patient history starts here!{% endcomment %} -
- {% block history %} - {% include 'iwdModuleV2/viewWork.html' %} - {% endblock %} +
+ {% endif %} + {% if eligible == "Dean" %} +
+ {% comment %}The Tab-Menu starts here!{% endcomment %} + + {% comment %}The Tab-Menu ends here!{% endcomment %} +
- {% comment %}The patient history ends here!{% endcomment %} + {% comment %}ROW #2 ends here!{% endcomment %}
+ {% comment %}The left-rail segment ends here!{% endcomment %} + + {% comment %}The central-rail segment starts here!{% endcomment %} + {% endif %} + {% if eligible == "director" %} +
+ {% comment %}The Tab-Menu starts here!{% endcomment %} + + {% comment %}The Tab-Menu ends here!{% endcomment %} + +
+ {% comment %}ROW #2 ends here!{% endcomment %} + +
+ {% comment %}The left-rail segment ends here!{% endcomment %} + + {% comment %}The central-rail segment starts here!{% endcomment %} {% endif %} {% comment %}The central-rail segment ends here!{% endcomment %} diff --git a/FusionIIIT/templates/iwdModuleV2/deanProcessedRequests.html b/FusionIIIT/templates/iwdModuleV2/deanProcessedRequests.html new file mode 100644 index 000000000..dd9ba8ba8 --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/deanProcessedRequests.html @@ -0,0 +1,96 @@ +{% extends 'globals/base.html' %} +{% load static %} + +{% block title %} + Academic +{% endblock %} + +{% block body %} + {% block navBar %} + {% include 'dashboard/navbar.html' %} + {% endblock %} + + +
+
+
+ {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} +
+
+
+
+ + +
+
+ Dean processed Requests +
+ +
+
+
+ + + + + + + + + + + + + {% for f in obj %} + + + + + + + + + + + {% endfor %} +
Details:-
IdNameDescriptionAreaCreated By
{{f.0}}{{f.1}}{{f.3}}{{f.2}}{{f.4}} +
+
+ {% csrf_token %} + + +
+
+ {% csrf_token %} + + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+{% endblock %} diff --git a/FusionIIIT/templates/iwdModuleV2/engineerProcessedRequests.html b/FusionIIIT/templates/iwdModuleV2/engineerProcessedRequests.html new file mode 100644 index 000000000..7c3bd813d --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/engineerProcessedRequests.html @@ -0,0 +1,121 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} + Academic +{% endblock %} + + +{% block body %} + {% block navBar %} + {% include 'dashboard/navbar.html' %} + {% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ +
+
+ Engineer Processed Requests +
+
+
+
+ + + + + + + + + + + + + + {% for f in obj %} + + + + + + + + + + + {% endfor %} +
Details:-
IdNameDescriptionAreaCreated By
{{f.0}}{{f.1}}{{f.3}}{{f.2}}{{f.4}} + +
+ {% csrf_token %} + + +
+
+
+
+
+ + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+ {% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/requestsStatus.html b/FusionIIIT/templates/iwdModuleV2/requestsStatus.html new file mode 100644 index 000000000..14711ab16 --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/requestsStatus.html @@ -0,0 +1,114 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} + Academic +{% endblock %} + + +{% block body %} + {% block navBar %} + {% include 'dashboard/navbar.html' %} + {% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ +
+
+ Requests Status +
+
+
+
+ + + + + + + + + + + + + + {% for f in obj %} + + + + + + + + + + + {% endfor %} +
Details:-
IdNameDescriptionAreaCreated ByStatus
{{f.0}}{{f.1}}{{f.3}}{{f.2}}{{f.4}}{{f.5}}
+
+
+
+ + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+ {% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/requestsView.html b/FusionIIIT/templates/iwdModuleV2/requestsView.html new file mode 100644 index 000000000..230ebe362 --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/requestsView.html @@ -0,0 +1,124 @@ + +{% load static %} + + +{% block title %} + Academic +{% endblock %} + + +{% block body %} + {% block navBar %} + + {% endblock %} + + + + {% comment %}The left-margin segment!{% endcomment %} + + + {% comment %}The left-rail segment starts here!{% endcomment %} + + {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + + + + {% comment %}The Tab-Menu ends here!{% endcomment %} + + {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + + + {% load static %} +
+ Requests +
+
{% csrf_token %} +
+ +
+ +
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ + +
+ + +
+ +
+
+ + +
+
+
+
+ + + + {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} + + {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} + + {% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 4cc3a0a30..f30bb509a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ amqp==5.0.2 -arabic-reshaper==2.1.1 +# arabic-reshaper==2.1.1 asgiref==3.3.1 attrs==20.3.0 beautifulsoup4==4.9.3 From 338b463b44cc63f813bf264a2d5ee5e687436a89 Mon Sep 17 00:00:00 2001 From: Srivatsa19 Date: Tue, 19 Mar 2024 22:15:47 +0530 Subject: [PATCH 04/19] Changes made --- .../migrations/0002_auto_20240308_1023.py | 38 + .../eis/migrations/0002_auto_20240308_1023.py | 53 ++ .../filetracking/api/serializers.py | 24 + .../applications/filetracking/api/urls.py | 22 + .../applications/filetracking/api/views.py | 111 +++ .../applications/filetracking/decorators.py | 38 + .../filetracking/filetracking/admin.py | 7 + .../filetracking/api/serializers.py | 24 + .../filetracking/filetracking/api/urls.py | 22 + .../filetracking/filetracking/api/views.py | 111 +++ .../filetracking/filetracking/apps.py | 5 + .../filetracking/filetracking/decorators.py | 38 + .../filetracking/migrations/0001_initial.py | 53 ++ .../filetracking/migrations/__init__.py | 0 .../filetracking/filetracking/models.py | 51 ++ .../filetracking/filetracking/sdk/methods.py | 423 ++++++++++ .../filetracking/filetracking/tests.py | 3 + .../filetracking/filetracking/urls.py | 43 + .../filetracking/filetracking/utils.py | 7 + .../filetracking/filetracking/views.py | 732 ++++++++++++++++++ .../migrations/0002_auto_20240308_1023.py | 33 + .../applications/filetracking/models.py | 12 +- .../applications/filetracking/sdk/methods.py | 424 ++++++++++ FusionIIIT/applications/filetracking/urls.py | 40 +- FusionIIIT/applications/filetracking/views.py | 555 +++++++------ .../migrations/0002_auto_20240308_1023.py | 18 + .../migrations/0003_auto_20240308_1025.py | 18 + .../migrations/0002_bills_requests.py | 41 + FusionIIIT/applications/iwdModuleV2/models.py | 20 +- FusionIIIT/applications/iwdModuleV2/urls.py | 14 +- FusionIIIT/applications/iwdModuleV2/views.py | 415 ++++++++-- .../migrations/0002_auto_20240308_1023.py | 23 + .../migrations/0002_auto_20240308_1023.py | 18 + .../templates/iwdModuleV2/addItemsView.html | 120 +++ .../iwdModuleV2/createdRequests.html | 8 + .../templates/iwdModuleV2/dashboard.html | 44 +- .../iwdModuleV2/deanProcessedRequests.html | 14 + .../templates/iwdModuleV2/editInventory.html | 124 +++ .../engineerProcessedRequests.html | 7 + .../templates/iwdModuleV2/inventory.html | 111 +++ .../templates/iwdModuleV2/issueWorkOrder.html | 120 +++ .../iwdModuleV2/requestFromInventory.html | 172 ++++ .../iwdModuleV2/requestsInProgress.html | 134 ++++ .../templates/iwdModuleV2/requestsView.html | 189 ++--- .../templates/iwdModuleV2/workOrder.html | 175 +++++ 45 files changed, 4254 insertions(+), 400 deletions(-) create mode 100644 FusionIIIT/applications/academic_procedures/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/eis/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/filetracking/api/serializers.py create mode 100644 FusionIIIT/applications/filetracking/api/urls.py create mode 100644 FusionIIIT/applications/filetracking/api/views.py create mode 100644 FusionIIIT/applications/filetracking/decorators.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/admin.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/api/serializers.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/api/urls.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/api/views.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/apps.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/decorators.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/migrations/0001_initial.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/migrations/__init__.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/models.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/sdk/methods.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/tests.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/urls.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/utils.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/views.py create mode 100644 FusionIIIT/applications/filetracking/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/filetracking/sdk/methods.py create mode 100644 FusionIIIT/applications/globals/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/globals/migrations/0003_auto_20240308_1025.py create mode 100644 FusionIIIT/applications/iwdModuleV2/migrations/0002_bills_requests.py create mode 100644 FusionIIIT/applications/programme_curriculum/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/scholarships/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/templates/iwdModuleV2/addItemsView.html create mode 100644 FusionIIIT/templates/iwdModuleV2/editInventory.html create mode 100644 FusionIIIT/templates/iwdModuleV2/inventory.html create mode 100644 FusionIIIT/templates/iwdModuleV2/issueWorkOrder.html create mode 100644 FusionIIIT/templates/iwdModuleV2/requestFromInventory.html create mode 100644 FusionIIIT/templates/iwdModuleV2/requestsInProgress.html create mode 100644 FusionIIIT/templates/iwdModuleV2/workOrder.html diff --git a/FusionIIIT/applications/academic_procedures/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/academic_procedures/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..2b5457988 --- /dev/null +++ b/FusionIIIT/applications/academic_procedures/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,38 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('academic_procedures', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='assistantshipclaim', + name='year', + field=models.IntegerField(choices=[(2024, 2024), (2023, 2023)]), + ), + migrations.AlterField( + model_name='course_registration', + name='working_year', + field=models.IntegerField(blank=True, choices=[(2024, 2024), (2023, 2023)], null=True), + ), + migrations.AlterField( + model_name='finalregistrations', + name='batch', + field=models.IntegerField(default=2024), + ), + migrations.AlterField( + model_name='messdue', + name='year', + field=models.IntegerField(choices=[(2024, 2024), (2023, 2023)]), + ), + migrations.AlterField( + model_name='register', + name='year', + field=models.IntegerField(default=2024), + ), + ] diff --git a/FusionIIIT/applications/eis/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/eis/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..217222095 --- /dev/null +++ b/FusionIIIT/applications/eis/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,53 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('eis', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='emp_achievement', + name='a_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_confrence_organised', + name='k_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_expert_lectures', + name='l_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_keynote_address', + name='k_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_mtechphd_thesis', + name='s_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_patents', + name='p_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_published_books', + name='pyear', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_research_papers', + name='year', + field=models.CharField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], max_length=10, null=True), + ), + ] diff --git a/FusionIIIT/applications/filetracking/api/serializers.py b/FusionIIIT/applications/filetracking/api/serializers.py new file mode 100644 index 000000000..bdae2024e --- /dev/null +++ b/FusionIIIT/applications/filetracking/api/serializers.py @@ -0,0 +1,24 @@ +from applications.filetracking.models import File, Tracking +from django.core.files import File as DjangoFile +from rest_framework import serializers + + +class FileSerializer(serializers.ModelSerializer): + class Meta: + model = File + fields = '__all__' + + +class TrackingSerializer(serializers.ModelSerializer): + class Meta: + model = Tracking + fields = '__all__' + + +class FileHeaderSerializer(serializers.ModelSerializer): + ''' + This serializes everything except the attachments of a file and whether it is read or not + ''' + class Meta: + model = File + exclude = ['upload_file', 'is_read'] diff --git a/FusionIIIT/applications/filetracking/api/urls.py b/FusionIIIT/applications/filetracking/api/urls.py new file mode 100644 index 000000000..90f03b2ef --- /dev/null +++ b/FusionIIIT/applications/filetracking/api/urls.py @@ -0,0 +1,22 @@ +from django.conf.urls import url +from .views import ( + CreateFileView, + ViewFileView, + DeleteFileView, + ViewInboxView, + ViewOutboxView, + ViewHistoryView, + ForwardFileView, + GetDesignationsView, +) + +urlpatterns = [ + url(r'^file/$', CreateFileView.as_view(), name='create_file'), + url(r'^file/(?P\d+)/$', ViewFileView.as_view(), name='view_file'), + url(r'^file/(?P\d+)/$', DeleteFileView.as_view(), name='delete_file'), + url(r'^inbox/$', ViewInboxView.as_view(), name='view_inbox'), + url(r'^outbox/$', ViewOutboxView.as_view(), name='view_outbox'), + url(r'^history/(?P\d+)/$', ViewHistoryView.as_view(), name='view_history'), + url(r'^file/(?P\d+)/$', ForwardFileView.as_view(), name='forward_file'), + url(r'^designations/(?P\w+)/$', GetDesignationsView.as_view(), name='get_designations'), +] diff --git a/FusionIIIT/applications/filetracking/api/views.py b/FusionIIIT/applications/filetracking/api/views.py new file mode 100644 index 000000000..c4bb01189 --- /dev/null +++ b/FusionIIIT/applications/filetracking/api/views.py @@ -0,0 +1,111 @@ +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status, permissions +from rest_framework.authentication import TokenAuthentication +from ..models import File +from ..sdk.methods import create_file, view_file, delete_file, view_inbox, view_outbox, view_history, forward_file, get_designations + +class CreateFileView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [permissions.IsAuthenticated] + + def post(self, request): + try: + current_user = request.user.username + current_designation = request.data.get('designation') + receiver_username = request.data.get('receiver_username') + receiver_designation = request.data.get('receiver_designation') + subject = request.data.get('subject') + description = request.data.get('description') + + if None in [current_designation, receiver_username, receiver_designation, subject, description]: + return Response({'error': 'One or more required fields are missing.'}, status=status.HTTP_400_BAD_REQUEST) + + file_id = create_file(uploader=current_user, uploader_designation=current_designation, + receiver=receiver_username, receiver_designation=receiver_designation, subject=subject, description=description) + + return Response({'file_id': file_id}, status=status.HTTP_201_CREATED) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class ViewFileView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [permissions.IsAuthenticated] + + def get(self, request, file_id): + try: + file_details = view_file(int(file_id)) + return Response(file_details, status=status.HTTP_200_OK) + except ValueError: + return Response({'error': 'Invalid file ID format.'}, status=status.HTTP_400_BAD_REQUEST) + except File.DoesNotExist: + return Response({'error': 'File not found.'}, status=status.HTTP_404_NOT_FOUND) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class DeleteFileView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def delete(self, request, file_id, *args, **kwargs): + success = delete_file(int(file_id)) + if success: + return Response({'message': 'File deleted successfully'}, + status=status.HTTP_204_NO_CONTENT) + else: + return Response({'error': 'File not found'}, + status=status.HTTP_404_NOT_FOUND) + + +class ViewInboxView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + inbox_files = view_inbox( + request.user.username, + request.query_params.get('designation'), + request.query_params.get('src_module')) + return Response(inbox_files) + + +class ViewOutboxView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + outbox_files = view_outbox( + request.user.username, + request.query_params.get('designation'), + request.query_params.get('src_module')) + return Response(outbox_files) + + +class ViewHistoryView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, file_id, *args, **kwargs): + history = view_history(int(file_id)) + return Response(history) + + +class ForwardFileView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def post(self, request, file_id, *args, **kwargs): + new_tracking_id = forward_file(int(file_id), **request.data) + return Response({'tracking_id': new_tracking_id}, + status=status.HTTP_201_CREATED) + + +class GetDesignationsView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, username, *args, **kwargs): + user_designations = get_designations(username) + return Response({'designations': user_designations}) diff --git a/FusionIIIT/applications/filetracking/decorators.py b/FusionIIIT/applications/filetracking/decorators.py new file mode 100644 index 000000000..05cc7cc51 --- /dev/null +++ b/FusionIIIT/applications/filetracking/decorators.py @@ -0,0 +1,38 @@ +from django.shortcuts import render, get_object_or_404 +from django.contrib.auth.models import User +from applications.globals.models import ExtraInfo, HoldsDesignation + + +def user_check(request): + """ + This function is used to check if the user is a student or not. + Its return type is bool. + @param: + request - contains metadata about the requested page + + @Variables: + current_user - get user from request + user_details - extract details of the user from the database + desig_id - check for designation + student - designation for a student + final_user - final designation of the request(our user) + """ + try: + current_user = get_object_or_404(User, username=request.user.username) + user_details = ExtraInfo.objects.select_related('user','department').get(user=request.user) + des = HoldsDesignation.objects.all().select_related().filter(user=request.user).first() + if str(des.designation) == "student": + return True + else: + return False + except Exception as e: + return False + +def user_is_student(view_func): + def _wrapped_view(request, *args, **kwargs): + if user_check(request): + return render(request, 'filetracking/fileTrackingNotAllowed.html') + else: + return view_func(request, *args, **kwargs) + return _wrapped_view + diff --git a/FusionIIIT/applications/filetracking/filetracking/admin.py b/FusionIIIT/applications/filetracking/filetracking/admin.py new file mode 100644 index 000000000..82b78df95 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +# Register your models here. +from applications.filetracking.models import File, Tracking + +admin.site.register(File) +admin.site.register(Tracking) diff --git a/FusionIIIT/applications/filetracking/filetracking/api/serializers.py b/FusionIIIT/applications/filetracking/filetracking/api/serializers.py new file mode 100644 index 000000000..bdae2024e --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/api/serializers.py @@ -0,0 +1,24 @@ +from applications.filetracking.models import File, Tracking +from django.core.files import File as DjangoFile +from rest_framework import serializers + + +class FileSerializer(serializers.ModelSerializer): + class Meta: + model = File + fields = '__all__' + + +class TrackingSerializer(serializers.ModelSerializer): + class Meta: + model = Tracking + fields = '__all__' + + +class FileHeaderSerializer(serializers.ModelSerializer): + ''' + This serializes everything except the attachments of a file and whether it is read or not + ''' + class Meta: + model = File + exclude = ['upload_file', 'is_read'] diff --git a/FusionIIIT/applications/filetracking/filetracking/api/urls.py b/FusionIIIT/applications/filetracking/filetracking/api/urls.py new file mode 100644 index 000000000..90f03b2ef --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/api/urls.py @@ -0,0 +1,22 @@ +from django.conf.urls import url +from .views import ( + CreateFileView, + ViewFileView, + DeleteFileView, + ViewInboxView, + ViewOutboxView, + ViewHistoryView, + ForwardFileView, + GetDesignationsView, +) + +urlpatterns = [ + url(r'^file/$', CreateFileView.as_view(), name='create_file'), + url(r'^file/(?P\d+)/$', ViewFileView.as_view(), name='view_file'), + url(r'^file/(?P\d+)/$', DeleteFileView.as_view(), name='delete_file'), + url(r'^inbox/$', ViewInboxView.as_view(), name='view_inbox'), + url(r'^outbox/$', ViewOutboxView.as_view(), name='view_outbox'), + url(r'^history/(?P\d+)/$', ViewHistoryView.as_view(), name='view_history'), + url(r'^file/(?P\d+)/$', ForwardFileView.as_view(), name='forward_file'), + url(r'^designations/(?P\w+)/$', GetDesignationsView.as_view(), name='get_designations'), +] diff --git a/FusionIIIT/applications/filetracking/filetracking/api/views.py b/FusionIIIT/applications/filetracking/filetracking/api/views.py new file mode 100644 index 000000000..c4bb01189 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/api/views.py @@ -0,0 +1,111 @@ +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status, permissions +from rest_framework.authentication import TokenAuthentication +from ..models import File +from ..sdk.methods import create_file, view_file, delete_file, view_inbox, view_outbox, view_history, forward_file, get_designations + +class CreateFileView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [permissions.IsAuthenticated] + + def post(self, request): + try: + current_user = request.user.username + current_designation = request.data.get('designation') + receiver_username = request.data.get('receiver_username') + receiver_designation = request.data.get('receiver_designation') + subject = request.data.get('subject') + description = request.data.get('description') + + if None in [current_designation, receiver_username, receiver_designation, subject, description]: + return Response({'error': 'One or more required fields are missing.'}, status=status.HTTP_400_BAD_REQUEST) + + file_id = create_file(uploader=current_user, uploader_designation=current_designation, + receiver=receiver_username, receiver_designation=receiver_designation, subject=subject, description=description) + + return Response({'file_id': file_id}, status=status.HTTP_201_CREATED) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class ViewFileView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [permissions.IsAuthenticated] + + def get(self, request, file_id): + try: + file_details = view_file(int(file_id)) + return Response(file_details, status=status.HTTP_200_OK) + except ValueError: + return Response({'error': 'Invalid file ID format.'}, status=status.HTTP_400_BAD_REQUEST) + except File.DoesNotExist: + return Response({'error': 'File not found.'}, status=status.HTTP_404_NOT_FOUND) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class DeleteFileView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def delete(self, request, file_id, *args, **kwargs): + success = delete_file(int(file_id)) + if success: + return Response({'message': 'File deleted successfully'}, + status=status.HTTP_204_NO_CONTENT) + else: + return Response({'error': 'File not found'}, + status=status.HTTP_404_NOT_FOUND) + + +class ViewInboxView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + inbox_files = view_inbox( + request.user.username, + request.query_params.get('designation'), + request.query_params.get('src_module')) + return Response(inbox_files) + + +class ViewOutboxView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + outbox_files = view_outbox( + request.user.username, + request.query_params.get('designation'), + request.query_params.get('src_module')) + return Response(outbox_files) + + +class ViewHistoryView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, file_id, *args, **kwargs): + history = view_history(int(file_id)) + return Response(history) + + +class ForwardFileView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def post(self, request, file_id, *args, **kwargs): + new_tracking_id = forward_file(int(file_id), **request.data) + return Response({'tracking_id': new_tracking_id}, + status=status.HTTP_201_CREATED) + + +class GetDesignationsView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, username, *args, **kwargs): + user_designations = get_designations(username) + return Response({'designations': user_designations}) diff --git a/FusionIIIT/applications/filetracking/filetracking/apps.py b/FusionIIIT/applications/filetracking/filetracking/apps.py new file mode 100644 index 000000000..7e3d3b6d2 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class FileTrackingConfig(AppConfig): + name = 'applications.filetracking' diff --git a/FusionIIIT/applications/filetracking/filetracking/decorators.py b/FusionIIIT/applications/filetracking/filetracking/decorators.py new file mode 100644 index 000000000..05cc7cc51 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/decorators.py @@ -0,0 +1,38 @@ +from django.shortcuts import render, get_object_or_404 +from django.contrib.auth.models import User +from applications.globals.models import ExtraInfo, HoldsDesignation + + +def user_check(request): + """ + This function is used to check if the user is a student or not. + Its return type is bool. + @param: + request - contains metadata about the requested page + + @Variables: + current_user - get user from request + user_details - extract details of the user from the database + desig_id - check for designation + student - designation for a student + final_user - final designation of the request(our user) + """ + try: + current_user = get_object_or_404(User, username=request.user.username) + user_details = ExtraInfo.objects.select_related('user','department').get(user=request.user) + des = HoldsDesignation.objects.all().select_related().filter(user=request.user).first() + if str(des.designation) == "student": + return True + else: + return False + except Exception as e: + return False + +def user_is_student(view_func): + def _wrapped_view(request, *args, **kwargs): + if user_check(request): + return render(request, 'filetracking/fileTrackingNotAllowed.html') + else: + return view_func(request, *args, **kwargs) + return _wrapped_view + diff --git a/FusionIIIT/applications/filetracking/filetracking/migrations/0001_initial.py b/FusionIIIT/applications/filetracking/filetracking/migrations/0001_initial.py new file mode 100644 index 000000000..6924ae1ff --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/migrations/0001_initial.py @@ -0,0 +1,53 @@ +# Generated by Django 3.1.5 on 2023-03-15 18:53 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('globals', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='File', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('subject', models.CharField(blank=True, max_length=100, null=True)), + ('description', models.CharField(blank=True, max_length=400, null=True)), + ('upload_date', models.DateTimeField(auto_now_add=True)), + ('upload_file', models.FileField(blank=True, upload_to='')), + ('is_read', models.BooleanField(default=False)), + ('designation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='upload_designation', to='globals.designation')), + ('uploader', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='uploaded_files', to='globals.extrainfo')), + ], + options={ + 'db_table': 'File', + }, + ), + migrations.CreateModel( + name='Tracking', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('receive_date', models.DateTimeField(auto_now_add=True)), + ('forward_date', models.DateTimeField(auto_now_add=True)), + ('remarks', models.CharField(blank=True, max_length=250, null=True)), + ('upload_file', models.FileField(blank=True, upload_to='')), + ('is_read', models.BooleanField(default=False)), + ('current_design', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='globals.holdsdesignation')), + ('current_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='globals.extrainfo')), + ('file_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='filetracking.file')), + ('receive_design', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rec_design', to='globals.designation')), + ('receiver_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='receiver_id', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'Tracking', + }, + ), + ] diff --git a/FusionIIIT/applications/filetracking/filetracking/migrations/__init__.py b/FusionIIIT/applications/filetracking/filetracking/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/FusionIIIT/applications/filetracking/filetracking/models.py b/FusionIIIT/applications/filetracking/filetracking/models.py new file mode 100644 index 000000000..9d78b24c9 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/models.py @@ -0,0 +1,51 @@ +from django.db import models +from django.contrib.auth.models import User +from applications.globals.models import ExtraInfo, HoldsDesignation, Designation + + +class File(models.Model): + """ + This is file table which contains the all the files created by user + """ + uploader = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE, related_name='uploaded_files') + designation = models.ForeignKey(Designation, on_delete=models.CASCADE, null=True, related_name='upload_designation') + subject = models.CharField(max_length=100, null=True, blank=True) + description = models.CharField(max_length=400, null=True, blank=True) + upload_date = models.DateTimeField(auto_now_add=True) + upload_file = models.FileField(blank=True) + is_read = models.BooleanField(default = False) + + + # additions for API + src_module = models.CharField(max_length=100, default='filetracking') + src_object_id = models.CharField(max_length=100,null=True) + file_extra_JSON = models.JSONField(null=True) + + class Meta: + db_table = 'File' + + #def __str__(self): + #return str(self.ref_id) + + +class Tracking(models.Model): + """ + This is File Tracing Table which contains the status of each individual file created by the user + """ + file_id = models.ForeignKey(File, on_delete=models.CASCADE, null=True) + current_id = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE) + current_design = models.ForeignKey(HoldsDesignation, null=True, on_delete=models.CASCADE) + receiver_id = models.ForeignKey(User,null = True, on_delete=models.CASCADE, related_name='receiver_id') + receive_design = models.ForeignKey(Designation, null=True, on_delete=models.CASCADE, related_name='rec_design') + + receive_date = models.DateTimeField(auto_now_add=True) + forward_date = models.DateTimeField(auto_now_add=True) + remarks = models.CharField(max_length=250, null=True, blank=True) + upload_file = models.FileField(blank=True) + is_read = models.BooleanField(default = False) + + # additions for API + tracking_extra_JSON = models.JSONField(null=True) + + class Meta: + db_table = 'Tracking' diff --git a/FusionIIIT/applications/filetracking/filetracking/sdk/methods.py b/FusionIIIT/applications/filetracking/filetracking/sdk/methods.py new file mode 100644 index 000000000..c6f9ebc53 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/sdk/methods.py @@ -0,0 +1,423 @@ +from django.contrib.auth.models import User +from applications.filetracking.models import Tracking, File +from applications.globals.models import Designation, HoldsDesignation, ExtraInfo +from applications.filetracking.api.serializers import FileSerializer, FileHeaderSerializer, TrackingSerializer +from django.core.exceptions import ValidationError +from typing import Any + + +def create_file( + uploader: str, + uploader_designation: str, + receiver: str, + receiver_designation: str, + subject: str = "", + description: str = "", + src_module: str = "filetracking", + src_object_id: str = "", + file_extra_JSON: dict = {}, + attached_file: Any = None) -> int: + ''' + This function is used to create a file object corresponding to any object of a module that needs to be tracked + ''' + + ''' + Functioning: + create base file with params + create tracking with params + if both complete then return id of file + else raise error + + also, delete file object if tracking isnt created + ''' + uploader_user_obj = get_user_object_from_username(uploader) + uploader_extrainfo_obj = get_ExtraInfo_object_from_username(uploader) + uploader_designation_obj = Designation.objects.get( + name=uploader_designation) + receiver_obj = get_user_object_from_username(receiver) + receiver_designation_obj = Designation.objects.get( + name=receiver_designation) + + new_file = File.objects.create( + uploader=uploader_extrainfo_obj, + subject=subject, + description=description, + designation=uploader_designation_obj, + src_module=src_module, + src_object_id=src_object_id, + file_extra_JSON=file_extra_JSON, + ) + + + if attached_file is not None: + new_file.upload_file.save(attached_file.name, attached_file, save=True) + + uploader_holdsdesignation_obj = HoldsDesignation.objects.get( + user=uploader_user_obj, designation=uploader_designation_obj) + + new_tracking = Tracking.objects.create( + file_id=new_file, + current_id=uploader_extrainfo_obj, + current_design=uploader_holdsdesignation_obj, + receiver_id=receiver_obj, + receive_design=receiver_designation_obj, + tracking_extra_JSON=file_extra_JSON, + remarks=f"File with id:{str(new_file.id)} created by {uploader} and sent to {receiver}" + # upload_file = None, dont add file for first tracking + ) + if new_tracking is None: + new_file.delete() + raise ValidationError('Tracking model data is incorrect') + else: + return new_file.id + + +def view_file(file_id: int) -> dict: + ''' + This function returns all the details of a given file + ''' + try: + requested_file = File.objects.get(id=file_id) + serializer = FileSerializer(requested_file) + file_details = serializer.data + return file_details + except File.DoesNotExist: + raise NotFound("File Not Found with provided ID") + + +def delete_file(file_id: int) -> bool: + ''' + This function is used to delete a file from being tracked, all the tracking history is deleted as well and returns true if the deletion was successful + ''' + try: + File.objects.filter(id=file_id).delete() + return True + except File.DoesNotExist: + return False + +# inbox and outbox could be sorted based on most recent linked tracking entry + +def view_inbox(username: str, designation: str, src_module: str) -> list: + ''' + This function is used to get all the files in the inbox of a particular user and designation + ''' + user_designation = Designation.objects.get(name=designation) + recipient_object = get_user_object_from_username(username) + received_files_tracking = Tracking.objects.select_related('file_id').filter( + receiver_id=recipient_object, + receive_design=user_designation, + file_id__src_module=src_module, + file_id__is_read=False).order_by('receive_date'); + received_files = [tracking.file_id for tracking in received_files_tracking] + + # remove duplicate file ids (from sending back and forth) + received_files_unique = uniqueList(received_files) + + received_files_serialized = list(FileHeaderSerializer( + received_files_unique, many=True).data) + + for file in received_files_serialized: + file['sent_by_user'] = get_last_file_sender(file['id']).username + file['sent_by_designation'] = get_last_file_sender_designation(file['id']).name + + return received_files_serialized + + +def view_outbox(username: str, designation: str, src_module: str) -> list: + ''' + This function is used to get all the files in the outbox of a particular user and designation + ''' + user_designation = get_designation_obj_from_name(designation=designation) + user_object = get_user_object_from_username(username) + user_HoldsDesignation_object = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + sender_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + sent_files_tracking = Tracking.objects.select_related('file_id').filter( + current_id=sender_ExtraInfo_object, + current_design=user_HoldsDesignation_object, + file_id__src_module=src_module, + file_id__is_read=False).order_by('-receive_date') + sent_files = [tracking.file_id for tracking in sent_files_tracking] + + # remove duplicate file ids (from sending back and forth) + sent_files_unique = uniqueList(sent_files) + + sent_files_serialized = FileHeaderSerializer(sent_files_unique, many=True) + return sent_files_serialized.data + + + +def view_archived(username: str, designation: str, src_module: str) -> dict: + ''' + This function is used to get all the files in the archive of a particular user and designation + Archived file mean those which the user has ever interacted with, and are now finished or archived + ''' + user_designation = Designation.objects.get(name=designation) + user_object = get_user_object_from_username(username) + received_archived_tracking = Tracking.objects.select_related('file_id').filter( + receiver_id=user_object, + receive_design=user_designation, + file_id__src_module=src_module, + file_id__is_read=True) + + user_HoldsDesignation_object = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + sender_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + sent_archived_tracking = Tracking.objects.select_related('file_id').filter( + current_id=sender_ExtraInfo_object, + current_design=user_HoldsDesignation_object, + file_id__src_module=src_module, + file_id__is_read=True) + + archived_tracking = received_archived_tracking | sent_archived_tracking + archived_files = [tracking.file_id for tracking in archived_tracking] + + # remove duplicate file ids (from sending back and forth) + archived_files_unique = uniqueList(archived_files) + + archived_files_serialized = FileHeaderSerializer(archived_files_unique, many=True) + return archived_files_serialized.data + + + +def archive_file(file_id: int) -> bool: + ''' + This function is used to archive a file and returns true if the archiving was successful + ''' + try: + File.objects.filter(id=file_id).update(is_read=True) + return True + except File.DoesNotExist: + return False + +def unarchive_file(file_id: int) -> bool: + ''' + This functions is used to unarchive a file and returns true if the unarchiving was successful + ''' + try: + File.objects.filter(id=file_id).update(is_read=False) + return True + except File.DoesNotExist: + return False + + + +def create_draft( + uploader: str, + uploader_designation: str, + src_module: str = "filetracking", + src_object_id: str = "", + file_extra_JSON: dict = {}, + attached_file: Any = None) -> int: + ''' + This function is used to create a draft file object corresponding to any object of a module that needs to be tracked + It is similar to create_file but is not sent to anyone + Later this file can be sent to someone by forward_file by using draft file_id + ''' + uploader_extrainfo_obj = get_ExtraInfo_object_from_username(uploader) + uploader_designation_obj = Designation.objects.get( + name=uploader_designation) + + new_file = File.objects.create( + uploader=uploader_extrainfo_obj, + designation=uploader_designation_obj, + src_module=src_module, + src_object_id=src_object_id, + file_extra_JSON=file_extra_JSON, + upload_file=attached_file + ) + return new_file.id + + +def view_drafts(username: str, designation: str, src_module: str) -> dict: + ''' + This function is used to get all the files in the drafts (has not been sent) of a particular user and designation + ''' + user_designation = Designation.objects.get(name=designation) + user_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + draft_files = File.objects.filter( + tracking__isnull=True, uploader=user_ExtraInfo_object, designation=user_designation, src_module=src_module) + draft_files_serialized = FileHeaderSerializer(draft_files, many=True) + return draft_files_serialized.data + + + +def forward_file( + file_id: int, + receiver: str, + receiver_designation: str, + file_extra_JSON: dict, + remarks: str = "", + file_attachment: Any = None) -> int: + ''' + This function forwards the file and inserts a new tracking history into the file tracking table + Note that only the current owner(with appropriate designation) of the file has the ability to forward files + ''' + # HoldsDesignation and ExtraInfo object are used instead + # of Designation and User object because of the legacy code being that way + + current_owner = get_current_file_owner(file_id) + current_owner_designation = get_current_file_owner_designation(file_id) + current_owner_extra_info = ExtraInfo.objects.get(user=current_owner) + current_owner_holds_designation = HoldsDesignation.objects.get( + user=current_owner, designation=current_owner_designation) + receiver_obj = User.objects.get(username=receiver) + receiver_designation_obj = Designation.objects.get( + name=receiver_designation) + tracking_data = { + 'file_id': file_id, + 'current_id': current_owner_extra_info.id, + 'current_design': current_owner_holds_designation.id, + 'receiver_id': receiver_obj.id, + 'receive_design': receiver_designation_obj.id, + 'tracking_extra_JSON': file_extra_JSON, + 'remarks': remarks, + } + if file_attachment is not None: + tracking_data['upload_file'] = file_attachment + + tracking_entry = TrackingSerializer(data=tracking_data) + if tracking_entry.is_valid(): + tracking_entry.save() + return tracking_entry.instance.id + else: + raise ValidationError('forward data is incomplete') + + +def view_history(file_id: int) -> dict: + ''' + This function is used to get the history of a particular file with the given file_id + ''' + Tracking_history = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date') + Tracking_history_serialized = TrackingSerializer( + Tracking_history, many=True) + return Tracking_history_serialized.data + + +# HELPER FUNCTIONS + +def get_current_file_owner(file_id: int) -> User: + ''' + This functions returns the current owner of the file. + The current owner is the latest recipient of the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_recipient = latest_tracking.receiver_id + return latest_recipient + + +def get_current_file_owner_designation(file_id: int) -> Designation: + ''' + This function returns the designation of the current owner of the file. + The current owner is the latest recipient of the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_recipient_designation = latest_tracking.receive_design + return latest_recipient_designation + +def get_last_file_sender(file_id: int) -> User: + ''' + This Function returns the last file sender, + one who has last forwarded/sent the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_sender_extra_info = latest_tracking.current_id + return latest_sender_extra_info.user + +def get_last_file_sender_designation(file_id: int) -> Designation: + ''' + This Function returns the last file sender's Designation, + one who has last forwarded/sent the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('receive_date').first() + latest_sender_holds_designation = latest_tracking.current_design + return latest_sender_holds_designation.designation + +def get_designations(username: str) -> list: + ''' + This function is used to return a list of all the designation names of a particular user + ''' + user = User.objects.get(username=username) + designations_held = HoldsDesignation.objects.filter(user=user) + designation_name = [hold_designation.designation.name for hold_designation in designations_held] + return designation_name + + +def get_user_object_from_username(username: str) -> User: + user = User.objects.get(username=username) + return user + +def get_ExtraInfo_object_from_username(username: str) -> ExtraInfo: + user = User.objects.get(username=username) + extrainfo = ExtraInfo.objects.get(user=user) + return extrainfo + +def uniqueList(l: list) -> list: + ''' + This function is used to return a list with unique elements + O(n) time and space + ''' + seen = set() + unique_list = [] + for item in l: + if item not in seen: + unique_list.append(item) + seen.add(item) + return unique_list + +def add_uploader_department_to_files_list(files: list) -> list: + ''' + This function is used to add the department of the uploader to the file + ''' + for file in files: + uploader_Extrainfo = file['uploader'] + file['uploader_department'] = (str(uploader_Extrainfo.department)).split(': ')[1] + + return files + +def get_designation_obj_from_name(designation: str) -> Designation: + des = Designation.objects.get(name = designation) + return des + +def get_HoldsDesignation_obj(username: str, designation:str) -> HoldsDesignation: + user_object = get_user_object_from_username(username=username) + user_designation = get_designation_obj_from_name(designation=designation) + obj = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + return obj + +def get_last_recv_tracking_for_user(file_id: int, username: str, designation: str)-> Tracking: + ''' + This returns the last tracking where username+designation recieved file_id + ''' + + recv_user_obj = get_user_object_from_username(username) + recv_design_obj = get_designation_obj_from_name(designation) + + last_tracking = Tracking.objects.filter(file_id=file_id, + receiver_id=recv_user_obj, + receive_design=recv_design_obj).order_by('-receive_date')[0] + return last_tracking + +def get_last_forw_tracking_for_user(file_id: int, username: str, designation: str) -> Tracking: + ''' + Returns the last tracking where the specified user forwarded the file. + ''' + + # Get user and designation objects + sender_user_obj = get_ExtraInfo_object_from_username(username) + sender_designation_obj = get_HoldsDesignation_obj(username=username, designation=designation) + + # Filter Tracking objects by file_id, sender_id, and sender_designation + last_tracking = Tracking.objects.filter(file_id=file_id, + current_id=sender_user_obj, + current_design=sender_designation_obj).order_by('-forward_date').first() + return last_tracking + +def get_extra_info_object_from_id(id: int): + return ExtraInfo.objects.get(id=id) diff --git a/FusionIIIT/applications/filetracking/filetracking/tests.py b/FusionIIIT/applications/filetracking/filetracking/tests.py new file mode 100644 index 000000000..a79ca8be5 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/tests.py @@ -0,0 +1,3 @@ +# from django.test import TestCase + +# Create your tests here. diff --git a/FusionIIIT/applications/filetracking/filetracking/urls.py b/FusionIIIT/applications/filetracking/filetracking/urls.py new file mode 100644 index 000000000..9236b8c36 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/urls.py @@ -0,0 +1,43 @@ +from django.conf.urls import url, include + +from . import views +from .api import urls + +app_name = 'filetracking' + +urlpatterns = [ + + url(r'^$', views.filetracking, name='filetracking'), + url(r'^draftdesign/$', views.draft_design, name='draft_design'), + url(r'^drafts/(?P\d+)$', views.drafts_view, name='drafts_view'), + url(r'^outbox/(?P\d+)$', views.outbox_view, name='outbox_view'), + url(r'^inbox/(?P\d+)$', views.inbox_view, name='inbox_view'), + url(r'^outward/$', views.outward, name='outward'), + url(r'^inward/$', views.inward, name='inward'), + url(r'^confirmdelete/(?P\d+)$', + views.confirmdelete, name='confirm_delete'), + url(r'^archive/(?P\d+)/$', views.archive_view, name='archive_view'), + url(r'^finish/(?P\d+)/$', views.archive_file, name='finish_file'), + url(r'^viewfile/(?P\d+)/$', views.view_file, name='view_file_view'), + url(r'^forward/(?P\d+)/$', views.forward, name='forward'), + url(r'^ajax/$', views.AjaxDropdown1, name='ajax_dropdown1'), + url(r'^ajax_dropdown/$', views.AjaxDropdown, name='ajax_dropdown'), + url(r'^test/$', views.test, name='test'), + url(r'^delete/(?P\d+)$', views.delete, name='delete'), + url(r'^forward_inward/(?P\d+)/$', + views.forward_inward, name='forward_inward'), + + # correction team 24 + url(r'^finish_design/$', views.finish_design, name='finish_design'), + url(r'^finish_fileview/(?P\d+)$', + views.finish_fileview, + name='finish_fileview'), + url(r'^archive_design/$', views.archive_design, name='archive_design'), + url(r'^archive_finish/(?P\d+)/$', + views.archive_finish, name='archive_finish'), + url(r'^getdesignations/(?P\w+)/$', views.get_designations_view, name="get_user_designations"), + + # REST api urls + url(r'^api/', include(urls)) + +] diff --git a/FusionIIIT/applications/filetracking/filetracking/utils.py b/FusionIIIT/applications/filetracking/filetracking/utils.py new file mode 100644 index 000000000..5ebd27374 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/utils.py @@ -0,0 +1,7 @@ +from .models import File, Tracking +from applications.globals.models import ExtraInfo, HoldsDesignation, Designation +from django.contrib.auth.models import User + +def get_designation(userid): + user_designation=HoldsDesignation.objects.select_related('user','working','designation').filter(user=userid) + return user_designation \ No newline at end of file diff --git a/FusionIIIT/applications/filetracking/filetracking/views.py b/FusionIIIT/applications/filetracking/filetracking/views.py new file mode 100644 index 000000000..b6d9e3bff --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/views.py @@ -0,0 +1,732 @@ +from django.contrib import messages +from django.shortcuts import render, get_object_or_404, redirect +from .models import File, Tracking +from applications.globals.models import ExtraInfo, HoldsDesignation, Designation +from django.template.defaulttags import csrf_token +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse +from django.contrib.auth.decorators import login_required +from django.db import IntegrityError +from django.core import serializers +from django.contrib.auth.models import User +from django.http import JsonResponse +from timeit import default_timer as time +from notification.views import office_module_notif, file_tracking_notif +from .utils import * +from django.utils.dateparse import parse_datetime +from .sdk.methods import * +from .decorators import * + +@login_required(login_url="/accounts/login/") +@user_is_student +def filetracking(request): + """ + The function is used to create files by current user(employee). + It adds the employee(uploader) and file datails to a file(table) of filetracking(model) + if he intends to create file. + + @param: + request - trivial. + + @variables: + + + uploader - Employee who creates file. + subject - Title of the file. + description - Description of the file. + upload_file - Attachment uploaded while creating file. + file - The file object. + extrainfo - The Extrainfo object. + holdsdesignations - The HoldsDesignation object. + context - Holds data needed to make necessary changes in the template. + """ + if request.method == "POST": + try: + if 'save' in request.POST: + uploader = request.user.extrainfo + subject = request.POST.get('title') + description = request.POST.get('desc') + design = request.POST.get('design') + designation = Designation.objects.get(id=HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=design).designation_id) + upload_file = request.FILES.get('myfile') + if upload_file and upload_file.size / 1000 > 10240: + messages.error( + request, "File should not be greater than 10MB") + return redirect("/filetracking") + + File.objects.create( + uploader=uploader, + description=description, + subject=subject, + designation=designation, + upload_file=upload_file + ) + + messages.success(request, 'File Draft Saved Successfully') + + if 'send' in request.POST: + uploader = request.user.extrainfo + subject = request.POST.get('title') + description = request.POST.get('desc') + design = request.POST.get('design') + designation = Designation.objects.get(id=HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=design).designation_id) + + upload_file = request.FILES.get('myfile') + if upload_file and upload_file.size / 1000 > 10240: + messages.error( + request, "File should not be greater than 10MB") + return redirect("/filetracking") + + file = File.objects.create( + uploader=uploader, + description=description, + subject=subject, + designation=designation, + upload_file=upload_file + ) + + current_id = request.user.extrainfo + remarks = request.POST.get('remarks') + + sender = request.POST.get('design') + current_design = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=sender) + + receiver = request.POST.get('receiver') + try: + receiver_id = User.objects.get(username=receiver) + except Exception as e: + messages.error(request, 'Enter a valid Username') + return redirect('/filetracking/') + receive = request.POST.get('recieve') + try: + receive_design = Designation.objects.get(name=receive) + except Exception as e: + messages.error(request, 'Enter a valid Designation') + return redirect('/filetracking/') + + upload_file = request.FILES.get('myfile') + + Tracking.objects.create( + file_id=file, + current_id=current_id, + current_design=current_design, + receive_design=receive_design, + receiver_id=receiver_id, + remarks=remarks, + upload_file=upload_file, + ) + # office_module_notif(request.user, receiver_id) + file_tracking_notif(request.user, receiver_id, subject) + messages.success(request, 'File sent successfully') + + except IntegrityError: + message = "FileID Already Taken.!!" + return HttpResponse(message) + + file = File.objects.select_related( + 'uploader__user', 'uploader__department', 'designation').all() + extrainfo = ExtraInfo.objects.select_related('user', 'department').all() + holdsdesignations = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').all() + designations = get_designation(request.user) + + context = { + 'file': file, + 'extrainfo': extrainfo, + 'holdsdesignations': holdsdesignations, + 'designations': designations, + } + return render(request, 'filetracking/composefile.html', context) + + +@login_required(login_url="/accounts/login") +def draft_design(request): + """ + The function is used to get the designation of the user and renders it on draft template. + + @param: + request - trivial. + + @variables: + + + context - Holds data needed to make necessary changes in the template. + """ + designation = get_designation(request.user) + context = { + 'designation': designation, + } + return render(request, 'filetracking/draft_design.html', context) + + +@login_required(login_url="/accounts/login") +def drafts_view(request, id): + """ + This function is used to view all the drafts created by the user ordered by upload date.it collects all the created files from File object. + + @param: + request - trivial + id - user id + + @parameters + draft - file obeject containing all the files created by user + context - holds data needed to render the template + + + + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + draft_files = view_drafts( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # Correct upload_date type + for f in draft_files: + f['upload_date'] = parse_datetime(f['upload_date']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + draft_files = add_uploader_department_to_files_list(draft_files) + + context = { + 'draft_files': draft_files, + 'designations': designation, + } + return render(request, 'filetracking/drafts.html', context) + + +@login_required(login_url="/accounts/login") +def outbox_view(request, id): + """ + The function is used to get all the files sent by user(employee) to other employees + which are filtered from Tracking(table) objects by current user i.e. current_id. + It displays files sent by user to other employees of a Tracking(table) of filetracking(model) + in the 'Outbox' tab of template. + + @param: + request - trivial. + id - user id + + @variables: + outward_files - File objects filtered by current_id i.e, present working user. + context - Holds data needed to make necessary changes in the template. + + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + + outward_files = view_outbox(username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking') + + for f in outward_files: + last_forw_tracking = get_last_forw_tracking_for_user(file_id=f['id'], + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation) + f['sent_to_user'] = last_forw_tracking.receiver_id + f['sent_to_design'] = last_forw_tracking.receive_design + f['last_sent_date'] = last_forw_tracking.forward_date + + f['upload_date'] = parse_datetime(f['upload_date']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + outward_files = add_uploader_department_to_files_list(outward_files) + + context = { + + 'out_files': outward_files, + 'viewer_designation': designation, + } + return render(request, 'filetracking/outbox.html', context) + + +@login_required(login_url="/accounts/login") +def inbox_view(request, id): + """ + The function is used to fetch the files received by the user form other employees. + These files are filtered by receiver id and ordered by receive date. + + @param: + request - trivial. + id - HoldsDesignation object id + + @variables: + inward_files - File object with additional sent by information + context - Holds data needed to make necessary changes in the template. + + """ + + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + inward_files = view_inbox( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # correct upload_date type and add recieve_date + for f in inward_files: + f['upload_date'] = parse_datetime(f['upload_date']) + + last_recv_tracking = get_last_recv_tracking_for_user(file_id=f['id'], + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation) + f['receive_date'] = last_recv_tracking.receive_date + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + inward_files = add_uploader_department_to_files_list(inward_files) + + + context = { + + 'in_file': inward_files, + 'designations': designation, + } + return render(request, 'filetracking/inbox.html', context) + + +@login_required(login_url="/accounts/login") +def outward(request): + """ + This function fetches the different designations of the user and renders it on outward template + @param: + request - trivial. + + @variables: + context - Holds the different designation data of the user + + """ + designation = get_designation(request.user) + + context = { + 'designation': designation, + } + return render(request, 'filetracking/outward.html', context) + + +@login_required(login_url="/accounts/login") +def inward(request): + """ + This function fetches the different designations of the user and renders it on inward template + + + @param: + request - trivial. + + @variables: + context - Holds the different designation data of the user + """ + designation = get_designation(request.user) + context = { + + 'designation': designation, + } + return render(request, 'filetracking/inward.html', context) + + +@login_required(login_url = "/accounts/login") +def confirmdelete(request,id): + """ + The function is used to confirm the deletion of a file. + @param: + request - trivial. + id - user id + + @variables: + context - Holds data needed to make necessary changes in the template. + """ + file = File.objects.select_related( + 'uploader__user', 'uploader__department', 'designation').get(pk=id) + + context = { + 'j': file, + } + + return render(request, 'filetracking/confirmdelete.html', context) + +@login_required(login_url="/accounts/login") +def view_file(request, id): + ''' + This function is used to view a particular file received by an employee from another. + This function also conditionally renders two forms 'forward_file' and 'archive_file' + based on if the user has necessary permissions or not. + The business permissions are as follows: + 1. User can forward file only if they are the last recipient of the file + 2. User can archive a file only if they have received it last and they are also the original owner of the file + + To forward the file and to archive the file separate views with POST request are called + + It displays the details file of a File and remarks as well as the attachments of all the users + who have been involved till that point of the workflow. + + @param: + request - Trivial. + id - ID of the file object which the user intends to forward to another employee. + + @variables: + file - The File object. + track - The Tracking object. + designation - the designations of the user + ''' + + file = get_object_or_404(File, id=id) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file).order_by('receive_date') + designations = get_designation(request.user) + + forward_enable = False + archive_enable = False + + current_owner = get_current_file_owner(file.id) + file_uploader = get_user_object_from_username(file.uploader.user.username) + + + if current_owner == request.user and file.is_read is False: + forward_enable = True + if current_owner == request.user and file_uploader == request.user and file.is_read is False: + archive_enable = True + + context = { + 'designations': designations, + 'file': file, + 'track': track, + 'forward_enable': forward_enable, + 'archive_enable': archive_enable, + } + return render(request, 'filetracking/viewfile.html', context) + +@login_required(login_url="/accounts/login") +def archive_file(request, id): + '''This function is used to archive a file. + It returns unauthorized access if the user is not file uploader + and the current owner of the file + ''' + if request.method == "POST": + file = get_object_or_404(File, id=id); + current_owner = get_current_file_owner(file.id) + file_uploader = get_user_object_from_username(file.uploader.user.username) + if current_owner == request.user and file_uploader == request.user: + file.is_read = True + file.save() + messages.success(request, 'File Archived') + else: + messages.error(request, 'Unauthorized access') + + return render(request, 'filetracking/composefile.html') + +@login_required(login_url="/accounts/login") +def forward(request, id): + """ + The function is used to forward files received by user(employee) from other + employees which are filtered from Tracking(table) objects by current user + i.e. receiver_id to other employees. + It also gets track of file created by uploader through all users involved in file + along with their remarks and attachments + It displays details file of a File(table) and remarks and attachments of user involved + in file of Tracking(table) of filetracking(model) in the template. + + @param: + request - trivial. + id - id of the file object which the user intends to forward to other employee. + + @variables: + file - The File object. + track - The Tracking object. + remarks = Remarks posted by user. + receiver = Receiver to be selected by user for forwarding file. + receiver_id = Receiver_id who has been selected for forwarding file. + upload_file = File attached by user. + extrainfo = ExtraInfo object. + holdsdesignations = HoldsDesignation objects. + context - Holds data needed to make necessary changes in the template. + """ + + file = get_object_or_404(File, id=id) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file).order_by('receive_date') + + if request.method == "POST": + if 'finish' in request.POST: + file.is_read = True + file.save() + if 'send' in request.POST: + current_id = request.user.extrainfo + remarks = request.POST.get('remarks') + track.update(is_read=True) + + sender = request.POST.get('sender') + current_design = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=sender) + + receiver = request.POST.get('receiver') + try: + receiver_id = User.objects.get(username=receiver) + except Exception as e: + messages.error(request, 'Enter a valid destination') + designations = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + receive = request.POST.get('recieve') + try: + receive_design = Designation.objects.get(name=receive) + except Exception as e: + messages.error(request, 'Enter a valid Designation') + designations = get_designation(request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + + upload_file = request.FILES.get('myfile') + + Tracking.objects.create( + file_id=file, + current_id=current_id, + current_design=current_design, + receive_design=receive_design, + receiver_id=receiver_id, + remarks=remarks, + upload_file=upload_file, + ) + messages.success(request, 'File sent successfully') + + designations = get_designation(request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + + return render(request, 'filetracking/forward.html', context) + + +@login_required(login_url="/accounts/login") +def archive_design(request): + designation = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) + + context = { + 'designation': designation, + } + return render(request, 'filetracking/archive_design.html', context) + + +@login_required(login_url="/accounts/login") +def archive_view(request, id): + """ + The function is used to fetch the files in the user's archive + (those which have passed by user and been archived/finished) + + @param: + request - trivial. + id - HoldsDesignation object id + + @variables: + archive_files - File object with additional information + context - Holds data needed to make necessary changes in the template. + + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + + archive_files = view_archived( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # correct upload_date type and add receive_date + for f in archive_files: + f['upload_date'] = parse_datetime(f['upload_date']) + f['designation'] = Designation.objects.get(id=f['designation']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + archive_files = add_uploader_department_to_files_list(archive_files) + + context = { + 'archive_files': archive_files, + 'designations': designation, + } + return render(request, 'filetracking/archive.html', context) + + + +@login_required(login_url="/accounts/login") +def archive_finish(request, id): + # file = get_object_or_404(File, ref_id=id) + file1 = get_object_or_404(File, id=id) + track = Tracking.objects.filter(file_id=file1) + + return render(request, 'filetracking/archive_finish.html', {'file': file1, 'track': track}) + + +@login_required(login_url="/accounts/login") +def finish_design(request): + + designation = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) + + context = { + 'designation': designation, + } + return render(request, 'filetracking/finish_design.html', context) + + +@login_required(login_url="/accounts/login") +def finish_fileview(request, id): + + out = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id__uploader=request.user.extrainfo, is_read=False).order_by('-forward_date') + + abcd = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + + context = { + + 'out': out, + 'abcd': abcd, + } + return render(request, 'filetracking/finish_fileview.html', context) + + +@login_required(login_url="/accounts/login") +def finish(request, id): + # file = get_object_or_404(File, ref_id=id) + file1 = get_object_or_404(File, id=id) + track = Tracking.objects.filter(file_id=file1) + + if request.method == "POST": + if 'Finished' in request.POST: + File.objects.filter(pk=id).update(is_read=True) + track.update(is_read=True) + messages.success(request, 'File Archived') + + return render(request, 'filetracking/finish.html', {'file': file1, 'track': track, 'fileid': id}) + + +def AjaxDropdown1(request): + + """ + This function returns the designation of receiver on the forward or compose file template. + + @param: + request - trivial. + + + @variables: + context - return the httpresponce containing the matched designation of the user + """ + if request.method == 'POST': + value = request.POST.get('value') + + hold = Designation.objects.filter(name__startswith=value) + holds = serializers.serialize('json', list(hold)) + context = { + 'holds': holds + } + + return HttpResponse(JsonResponse(context), content_type='application/json') + + +def AjaxDropdown(request): + """ + This function returns the usernames of receiver on the forward or compose file template. + + @param: + request - trivial. + + + @variables: + context - return the httpresponce containing the matched username + """ + if request.method == 'POST': + value = request.POST.get('value') + users = User.objects.filter(username__startswith=value) + users = serializers.serialize('json', list(users)) + + context = { + 'users': users + } + return HttpResponse(JsonResponse(context), content_type='application/json') + + +def test(request): + return HttpResponse('success') + + + +@login_required(login_url = "/accounts/login") +def delete(request,id): + """ + The function is used the delete of a file and it returns to the drafts page. + + @param: + request - trivial. + id - id of the file that is going to be deleted + + """ + file = File.objects.get(pk=id) + file.delete() + return redirect('/filetracking/draftdesign/') + + + + +def forward_inward(request,id): + """ This function is used forward the files which are available in the inbox of the user . + + @param: + request - trivial + id - id of the file that is going to forward + + @variables: + file - file object + track - tracking object of the file + context - necessary data to render + + """ + + file = get_object_or_404(File, id=id) + file.is_read = True + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file) + designations = get_designation(request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + +def get_designations_view(request, username): + designations = get_designations(username) + print(designations) + return JsonResponse(designations, safe=False) + diff --git a/FusionIIIT/applications/filetracking/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/filetracking/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..31015f1ec --- /dev/null +++ b/FusionIIIT/applications/filetracking/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,33 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('filetracking', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='file', + name='file_extra_JSON', + field=models.JSONField(null=True), + ), + migrations.AddField( + model_name='file', + name='src_module', + field=models.CharField(default='filetracking', max_length=100), + ), + migrations.AddField( + model_name='file', + name='src_object_id', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='tracking', + name='tracking_extra_JSON', + field=models.JSONField(null=True), + ), + ] diff --git a/FusionIIIT/applications/filetracking/models.py b/FusionIIIT/applications/filetracking/models.py index 5f9581a08..9d78b24c9 100644 --- a/FusionIIIT/applications/filetracking/models.py +++ b/FusionIIIT/applications/filetracking/models.py @@ -16,6 +16,11 @@ class File(models.Model): is_read = models.BooleanField(default = False) + # additions for API + src_module = models.CharField(max_length=100, default='filetracking') + src_object_id = models.CharField(max_length=100,null=True) + file_extra_JSON = models.JSONField(null=True) + class Meta: db_table = 'File' @@ -25,13 +30,11 @@ class Meta: class Tracking(models.Model): """ - This is File Tracing Table which contains the status of each indivisual file created by the user + This is File Tracing Table which contains the status of each individual file created by the user """ file_id = models.ForeignKey(File, on_delete=models.CASCADE, null=True) current_id = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE) current_design = models.ForeignKey(HoldsDesignation, null=True, on_delete=models.CASCADE) - # receiver_id = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE, related_name='receiver_id') - # receive_design = models.ForeignKey(HoldsDesignation, null=True, on_delete=models.CASCADE, related_name='rec_design') receiver_id = models.ForeignKey(User,null = True, on_delete=models.CASCADE, related_name='receiver_id') receive_design = models.ForeignKey(Designation, null=True, on_delete=models.CASCADE, related_name='rec_design') @@ -41,5 +44,8 @@ class Tracking(models.Model): upload_file = models.FileField(blank=True) is_read = models.BooleanField(default = False) + # additions for API + tracking_extra_JSON = models.JSONField(null=True) + class Meta: db_table = 'Tracking' diff --git a/FusionIIIT/applications/filetracking/sdk/methods.py b/FusionIIIT/applications/filetracking/sdk/methods.py new file mode 100644 index 000000000..97b7c87a1 --- /dev/null +++ b/FusionIIIT/applications/filetracking/sdk/methods.py @@ -0,0 +1,424 @@ +from django.contrib.auth.models import User +from applications.filetracking.models import Tracking, File +from applications.globals.models import Designation, HoldsDesignation, ExtraInfo +from applications.filetracking.api.serializers import FileSerializer, FileHeaderSerializer, TrackingSerializer +from django.core.exceptions import ValidationError +from typing import Any + + +def create_file( + uploader: str, + uploader_designation: str, + receiver: str, + receiver_designation: str, + subject: str = "", + description: str = "", + src_module: str = "filetracking", + src_object_id: str = "", + file_extra_JSON: dict = {}, + attached_file: Any = None) -> int: + ''' + This function is used to create a file object corresponding to any object of a module that needs to be tracked + ''' + + ''' + Functioning: + create base file with params + create tracking with params + if both complete then return id of file + else raise error + + also, delete file object if tracking isnt created + ''' + uploader_user_obj = get_user_object_from_username(uploader) + uploader_extrainfo_obj = get_ExtraInfo_object_from_username(uploader) + uploader_designation_obj = Designation.objects.get( + name=uploader_designation) + receiver_obj = get_user_object_from_username(receiver) + receiver_designation_obj = Designation.objects.get( + name=receiver_designation) + + new_file = File.objects.create( + uploader=uploader_extrainfo_obj, + subject=subject, + description=description, + designation=uploader_designation_obj, + src_module=src_module, + src_object_id=src_object_id, + file_extra_JSON=file_extra_JSON, + ) + + + if attached_file is not None: + new_file.upload_file.save(attached_file.name, attached_file, save=True) + + uploader_holdsdesignation_obj = HoldsDesignation.objects.get( + user=uploader_user_obj, designation=uploader_designation_obj) + + new_tracking = Tracking.objects.create( + file_id=new_file, + current_id=uploader_extrainfo_obj, + current_design=uploader_holdsdesignation_obj, + receiver_id=receiver_obj, + receive_design=receiver_designation_obj, + tracking_extra_JSON=file_extra_JSON, + remarks=f"File with id:{str(new_file.id)} created by {uploader} and sent to {receiver}" + # upload_file = None, dont add file for first tracking + ) + if new_tracking is None: + new_file.delete() + raise ValidationError('Tracking model data is incorrect') + else: + return new_file.id + + +def view_file(file_id: int) -> dict: + ''' + This function returns all the details of a given file + ''' + try: + requested_file = File.objects.get(id=file_id) + serializer = FileSerializer(requested_file) + file_details = serializer.data + print(file_details) + return file_details + except File.DoesNotExist: + raise NotFound("File Not Found with provided ID") + + +def delete_file(file_id: int) -> bool: + ''' + This function is used to delete a file from being tracked, all the tracking history is deleted as well and returns true if the deletion was successful + ''' + try: + File.objects.filter(id=file_id).delete() + return True + except File.DoesNotExist: + return False + +# inbox and outbox could be sorted based on most recent linked tracking entry + +def view_inbox(username: str, designation: str, src_module: str) -> list: + ''' + This function is used to get all the files in the inbox of a particular user and designation + ''' + user_designation = Designation.objects.get(name=designation) + recipient_object = get_user_object_from_username(username) + received_files_tracking = Tracking.objects.select_related('file_id').filter( + receiver_id=recipient_object, + receive_design=user_designation, + file_id__src_module=src_module, + file_id__is_read=False).order_by('receive_date'); + received_files = [tracking.file_id for tracking in received_files_tracking] + + # remove duplicate file ids (from sending back and forth) + received_files_unique = uniqueList(received_files) + + received_files_serialized = list(FileHeaderSerializer( + received_files_unique, many=True).data) + + for file in received_files_serialized: + file['sent_by_user'] = get_last_file_sender(file['id']).username + file['sent_by_designation'] = get_last_file_sender_designation(file['id']).name + + return received_files_serialized + + +def view_outbox(username: str, designation: str, src_module: str) -> list: + ''' + This function is used to get all the files in the outbox of a particular user and designation + ''' + user_designation = get_designation_obj_from_name(designation=designation) + user_object = get_user_object_from_username(username) + user_HoldsDesignation_object = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + sender_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + sent_files_tracking = Tracking.objects.select_related('file_id').filter( + current_id=sender_ExtraInfo_object, + current_design=user_HoldsDesignation_object, + file_id__src_module=src_module, + file_id__is_read=False).order_by('-receive_date') + sent_files = [tracking.file_id for tracking in sent_files_tracking] + + # remove duplicate file ids (from sending back and forth) + sent_files_unique = uniqueList(sent_files) + + sent_files_serialized = FileHeaderSerializer(sent_files_unique, many=True) + return sent_files_serialized.data + + + +def view_archived(username: str, designation: str, src_module: str) -> dict: + ''' + This function is used to get all the files in the archive of a particular user and designation + Archived file mean those which the user has ever interacted with, and are now finished or archived + ''' + user_designation = Designation.objects.get(name=designation) + user_object = get_user_object_from_username(username) + received_archived_tracking = Tracking.objects.select_related('file_id').filter( + receiver_id=user_object, + receive_design=user_designation, + file_id__src_module=src_module, + file_id__is_read=True) + + user_HoldsDesignation_object = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + sender_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + sent_archived_tracking = Tracking.objects.select_related('file_id').filter( + current_id=sender_ExtraInfo_object, + current_design=user_HoldsDesignation_object, + file_id__src_module=src_module, + file_id__is_read=True) + + archived_tracking = received_archived_tracking | sent_archived_tracking + archived_files = [tracking.file_id for tracking in archived_tracking] + + # remove duplicate file ids (from sending back and forth) + archived_files_unique = uniqueList(archived_files) + + archived_files_serialized = FileHeaderSerializer(archived_files_unique, many=True) + return archived_files_serialized.data + + + +def archive_file(file_id: int) -> bool: + ''' + This function is used to archive a file and returns true if the archiving was successful + ''' + try: + File.objects.filter(id=file_id).update(is_read=True) + return True + except File.DoesNotExist: + return False + +def unarchive_file(file_id: int) -> bool: + ''' + This functions is used to unarchive a file and returns true if the unarchiving was successful + ''' + try: + File.objects.filter(id=file_id).update(is_read=False) + return True + except File.DoesNotExist: + return False + + + +def create_draft( + uploader: str, + uploader_designation: str, + src_module: str = "filetracking", + src_object_id: str = "", + file_extra_JSON: dict = {}, + attached_file: Any = None) -> int: + ''' + This function is used to create a draft file object corresponding to any object of a module that needs to be tracked + It is similar to create_file but is not sent to anyone + Later this file can be sent to someone by forward_file by using draft file_id + ''' + uploader_extrainfo_obj = get_ExtraInfo_object_from_username(uploader) + uploader_designation_obj = Designation.objects.get( + name=uploader_designation) + + new_file = File.objects.create( + uploader=uploader_extrainfo_obj, + designation=uploader_designation_obj, + src_module=src_module, + src_object_id=src_object_id, + file_extra_JSON=file_extra_JSON, + upload_file=attached_file + ) + return new_file.id + + +def view_drafts(username: str, designation: str, src_module: str) -> dict: + ''' + This function is used to get all the files in the drafts (has not been sent) of a particular user and designation + ''' + user_designation = Designation.objects.get(name=designation) + user_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + draft_files = File.objects.filter( + tracking__isnull=True, uploader=user_ExtraInfo_object, designation=user_designation, src_module=src_module) + draft_files_serialized = FileHeaderSerializer(draft_files, many=True) + return draft_files_serialized.data + + + +def forward_file( + file_id: int, + receiver: str, + receiver_designation: str, + file_extra_JSON: dict, + remarks: str = "", + file_attachment: Any = None) -> int: + ''' + This function forwards the file and inserts a new tracking history into the file tracking table + Note that only the current owner(with appropriate designation) of the file has the ability to forward files + ''' + # HoldsDesignation and ExtraInfo object are used instead + # of Designation and User object because of the legacy code being that way + + current_owner = get_current_file_owner(file_id) + current_owner_designation = get_current_file_owner_designation(file_id) + current_owner_extra_info = ExtraInfo.objects.get(user=current_owner) + current_owner_holds_designation = HoldsDesignation.objects.get( + user=current_owner, designation=current_owner_designation) + receiver_obj = User.objects.get(username=receiver) + receiver_designation_obj = Designation.objects.get( + name=receiver_designation) + tracking_data = { + 'file_id': file_id, + 'current_id': current_owner_extra_info.id, + 'current_design': current_owner_holds_designation.id, + 'receiver_id': receiver_obj.id, + 'receive_design': receiver_designation_obj.id, + 'tracking_extra_JSON': file_extra_JSON, + 'remarks': remarks, + } + if file_attachment is not None: + tracking_data['upload_file'] = file_attachment + + tracking_entry = TrackingSerializer(data=tracking_data) + if tracking_entry.is_valid(): + tracking_entry.save() + return tracking_entry.instance.id + else: + raise ValidationError('forward data is incomplete') + + +def view_history(file_id: int) -> dict: + ''' + This function is used to get the history of a particular file with the given file_id + ''' + Tracking_history = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date') + Tracking_history_serialized = TrackingSerializer( + Tracking_history, many=True) + return Tracking_history_serialized.data + + +# HELPER FUNCTIONS + +def get_current_file_owner(file_id: int) -> User: + ''' + This functions returns the current owner of the file. + The current owner is the latest recipient of the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_recipient = latest_tracking.receiver_id + return latest_recipient + + +def get_current_file_owner_designation(file_id: int) -> Designation: + ''' + This function returns the designation of the current owner of the file. + The current owner is the latest recipient of the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_recipient_designation = latest_tracking.receive_design + return latest_recipient_designation + +def get_last_file_sender(file_id: int) -> User: + ''' + This Function returns the last file sender, + one who has last forwarded/sent the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_sender_extra_info = latest_tracking.current_id + return latest_sender_extra_info.user + +def get_last_file_sender_designation(file_id: int) -> Designation: + ''' + This Function returns the last file sender's Designation, + one who has last forwarded/sent the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('receive_date').first() + latest_sender_holds_designation = latest_tracking.current_design + return latest_sender_holds_designation.designation + +def get_designations(username: str) -> list: + ''' + This function is used to return a list of all the designation names of a particular user + ''' + user = User.objects.get(username=username) + designations_held = HoldsDesignation.objects.filter(user=user) + designation_name = [hold_designation.designation.name for hold_designation in designations_held] + return designation_name + + +def get_user_object_from_username(username: str) -> User: + user = User.objects.get(username=username) + return user + +def get_ExtraInfo_object_from_username(username: str) -> ExtraInfo: + user = User.objects.get(username=username) + extrainfo = ExtraInfo.objects.get(user=user) + return extrainfo + +def uniqueList(l: list) -> list: + ''' + This function is used to return a list with unique elements + O(n) time and space + ''' + seen = set() + unique_list = [] + for item in l: + if item not in seen: + unique_list.append(item) + seen.add(item) + return unique_list + +def add_uploader_department_to_files_list(files: list) -> list: + ''' + This function is used to add the department of the uploader to the file + ''' + for file in files: + uploader_Extrainfo = file['uploader'] + file['uploader_department'] = (str(uploader_Extrainfo.department)).split(': ')[1] + + return files + +def get_designation_obj_from_name(designation: str) -> Designation: + des = Designation.objects.get(name = designation) + return des + +def get_HoldsDesignation_obj(username: str, designation:str) -> HoldsDesignation: + user_object = get_user_object_from_username(username=username) + user_designation = get_designation_obj_from_name(designation=designation) + obj = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + return obj + +def get_last_recv_tracking_for_user(file_id: int, username: str, designation: str)-> Tracking: + ''' + This returns the last tracking where username+designation recieved file_id + ''' + + recv_user_obj = get_user_object_from_username(username) + recv_design_obj = get_designation_obj_from_name(designation) + + last_tracking = Tracking.objects.filter(file_id=file_id, + receiver_id=recv_user_obj, + receive_design=recv_design_obj).order_by('-receive_date')[0] + return last_tracking + +def get_last_forw_tracking_for_user(file_id: int, username: str, designation: str) -> Tracking: + ''' + Returns the last tracking where the specified user forwarded the file. + ''' + + # Get user and designation objects + sender_user_obj = get_ExtraInfo_object_from_username(username) + sender_designation_obj = get_HoldsDesignation_obj(username=username, designation=designation) + + # Filter Tracking objects by file_id, sender_id, and sender_designation + last_tracking = Tracking.objects.filter(file_id=file_id, + current_id=sender_user_obj, + current_design=sender_designation_obj).order_by('-forward_date').first() + return last_tracking + +def get_extra_info_object_from_id(id: int): + return ExtraInfo.objects.get(id=id) diff --git a/FusionIIIT/applications/filetracking/urls.py b/FusionIIIT/applications/filetracking/urls.py index cb4a7563d..28c8deac1 100644 --- a/FusionIIIT/applications/filetracking/urls.py +++ b/FusionIIIT/applications/filetracking/urls.py @@ -1,31 +1,43 @@ -from django.conf.urls import url +from django.conf.urls import url, include from . import views +from .api import urls app_name = 'filetracking' urlpatterns = [ url(r'^$', views.filetracking, name='filetracking'), - url(r'^drafts/$', views.drafts, name='drafts'), - url(r'^fileview/(?P\d+)$', views.fileview, name='fileview'), - url(r'^fileview1/(?P\d+)$', views.fileview1, name='fileview1'), - url(r'^fileview2/(?P\d+)$', views.fileview2, name='fileview2'), + url(r'^draftdesign/$', views.draft_design, name='draft_design'), + url(r'^drafts/(?P\d+)$', views.drafts_view, name='drafts_view'), + url(r'^outbox/(?P\d+)$', views.outbox_view, name='outbox_view'), + url(r'^inbox/(?P\d+)$', views.inbox_view, name='inbox_view'), url(r'^outward/$', views.outward, name='outward'), url(r'^inward/$', views.inward, name='inward'), - url(r'^confirmdelete/(?P\d+)$', views.confirmdelete, name='confirm_delete'), - url(r'^archive/(?P\d+)/$', views.archive, name='archive'), - url(r'^finish/(?P\d+)/$', views.finish, name='finish'), + url(r'^confirmdelete/(?P\d+)$', + views.confirmdelete, name='confirm_delete'), + url(r'^archive/(?P\d+)/$', views.archive_view, name='archive_view'), + url(r'^finish/(?P\d+)/$', views.archive_file, name='finish_file'), + url(r'^viewfile/(?P\d+)/$', views.view_file, name='view_file_view'), url(r'^forward/(?P\d+)/$', views.forward, name='forward'), url(r'^ajax/$', views.AjaxDropdown1, name='ajax_dropdown1'), url(r'^ajax_dropdown/$', views.AjaxDropdown, name='ajax_dropdown'), - url(r'^test/$',views.test, name='test'), - url(r'^delete/(?P\d+)$',views.delete, name='delete'), - url(r'^forward_inward/(?P\d+)/$', views.forward_inward, name='forward_inward'), + url(r'^test/$', views.test, name='test'), + url(r'^delete/(?P\d+)$', views.delete, name='delete'), + url(r'^forward_inward/(?P\d+)/$', + views.forward_inward, name='forward_inward'), - ## correction team 24 + # correction team 24 url(r'^finish_design/$', views.finish_design, name='finish_design'), - url(r'^finish_fileview/(?P\d+)$', views.finish_fileview, name='finish_fileview'), + url(r'^finish_fileview/(?P\d+)$', + views.finish_fileview, + name='finish_fileview'), url(r'^archive_design/$', views.archive_design, name='archive_design'), - url(r'^archive_finish/(?P\d+)/$', views.archive_finish, name='archive_finish'), + url(r'^archive_finish/(?P\d+)/$', + views.archive_finish, name='archive_finish'), + url(r'^getdesignations/(?P\w+)/$', views.get_designations_view, name="get_user_designations"), + + # REST api urls + url(r'^api/', include(urls)) + ] diff --git a/FusionIIIT/applications/filetracking/views.py b/FusionIIIT/applications/filetracking/views.py index ef5d8f347..b6d9e3bff 100644 --- a/FusionIIIT/applications/filetracking/views.py +++ b/FusionIIIT/applications/filetracking/views.py @@ -8,12 +8,16 @@ from django.db import IntegrityError from django.core import serializers from django.contrib.auth.models import User +from django.http import JsonResponse from timeit import default_timer as time -from notification.views import office_module_notif,file_tracking_notif +from notification.views import office_module_notif, file_tracking_notif from .utils import * +from django.utils.dateparse import parse_datetime +from .sdk.methods import * +from .decorators import * - -@login_required(login_url = "/accounts/login/") +@login_required(login_url="/accounts/login/") +@user_is_student def filetracking(request): """ The function is used to create files by current user(employee). @@ -35,18 +39,20 @@ def filetracking(request): holdsdesignations - The HoldsDesignation object. context - Holds data needed to make necessary changes in the template. """ - if request.method =="POST": + if request.method == "POST": try: if 'save' in request.POST: uploader = request.user.extrainfo subject = request.POST.get('title') description = request.POST.get('desc') design = request.POST.get('design') - designation = Designation.objects.get(id = HoldsDesignation.objects.select_related('user','working','designation').get(id = design).designation_id) + designation = Designation.objects.get(id=HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=design).designation_id) upload_file = request.FILES.get('myfile') - if(upload_file.size / 1000 > 10240): - messages.error(request,"File should not be greater than 10MB") - return redirect("/filetracking") + if upload_file and upload_file.size / 1000 > 10240: + messages.error( + request, "File should not be greater than 10MB") + return redirect("/filetracking") File.objects.create( uploader=uploader, @@ -56,18 +62,20 @@ def filetracking(request): upload_file=upload_file ) - messages.success(request,'File Draft Saved Successfully') + messages.success(request, 'File Draft Saved Successfully') if 'send' in request.POST: uploader = request.user.extrainfo subject = request.POST.get('title') description = request.POST.get('desc') design = request.POST.get('design') - designation = Designation.objects.get(id = HoldsDesignation.objects.select_related('user','working','designation').get(id = design).designation_id) + designation = Designation.objects.get(id=HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=design).designation_id) upload_file = request.FILES.get('myfile') - if(upload_file.size / 1000 > 10240): - messages.error(request,"File should not be greater than 10MB") + if upload_file and upload_file.size / 1000 > 10240: + messages.error( + request, "File should not be greater than 10MB") return redirect("/filetracking") file = File.objects.create( @@ -78,12 +86,12 @@ def filetracking(request): upload_file=upload_file ) - current_id = request.user.extrainfo remarks = request.POST.get('remarks') sender = request.POST.get('design') - current_design = HoldsDesignation.objects.select_related('user','working','designation').get(id=sender) + current_design = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=sender) receiver = request.POST.get('receiver') try: @@ -109,19 +117,19 @@ def filetracking(request): remarks=remarks, upload_file=upload_file, ) - #office_module_notif(request.user, receiver_id) - file_tracking_notif(request.user,receiver_id,subject) - messages.success(request,'File sent successfully') + # office_module_notif(request.user, receiver_id) + file_tracking_notif(request.user, receiver_id, subject) + messages.success(request, 'File sent successfully') except IntegrityError: message = "FileID Already Taken.!!" return HttpResponse(message) - - - file = File.objects.select_related('uploader__user','uploader__department','designation').all() - extrainfo = ExtraInfo.objects.select_related('user','department').all() - holdsdesignations = HoldsDesignation.objects.select_related('user','working','designation').all() + file = File.objects.select_related( + 'uploader__user', 'uploader__department', 'designation').all() + extrainfo = ExtraInfo.objects.select_related('user', 'department').all() + holdsdesignations = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').all() designations = get_designation(request.user) context = { @@ -133,8 +141,8 @@ def filetracking(request): return render(request, 'filetracking/composefile.html', context) -@login_required(login_url = "/accounts/login") -def drafts(request): +@login_required(login_url="/accounts/login") +def draft_design(request): """ The function is used to get the designation of the user and renders it on draft template. @@ -142,22 +150,21 @@ def drafts(request): request - trivial. @variables: - - + + context - Holds data needed to make necessary changes in the template. """ designation = get_designation(request.user) context = { 'designation': designation, } - return render(request, 'filetracking/drafts.html', context) + return render(request, 'filetracking/draft_design.html', context) -@login_required(login_url = "/accounts/login") -def fileview(request,id): - +@login_required(login_url="/accounts/login") +def drafts_view(request, id): """ - This function is used to veiw all all created files by the user ordered by upload date.it collects all the created files from File object. + This function is used to view all the drafts created by the user ordered by upload date.it collects all the created files from File object. @param: request - trivial @@ -166,45 +173,36 @@ def fileview(request,id): @parameters draft - file obeject containing all the files created by user context - holds data needed to render the template - - - """ - # draft = File.objects.select_related('uploader__user','uploader__department','designation').filter(uploader=request.user.extrainfo).order_by('-upload_date') - # extrainfo = ExtraInfo.objects.select_related('user','department').all() - - extrainfo = ExtraInfo.objects.select_related('user','department').all() - - ids = File.objects.filter(uploader=request.user.extrainfo).order_by('-upload_date').values_list('id', flat=True) - draft_files_pk=[] - - for i in ids: - file_tracking_ids = Tracking.objects.filter(file_id=i).values_list('id', flat=True) - if(len(file_tracking_ids)==0): - draft_files_pk.append(i) - - draft_file_list=[] - for i in draft_files_pk: - draft_file_list.append(File.objects.get(pk=i)) + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + draft_files = view_drafts( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # Correct upload_date type + for f in draft_files: + f['upload_date'] = parse_datetime(f['upload_date']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + draft_files = add_uploader_department_to_files_list(draft_files) - user_designation = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) - s = str(user_designation).split(" - ") - designations = s[1] context = { - - 'draft': draft_file_list, - 'extrainfo': extrainfo, - 'designations': designations, + 'draft_files': draft_files, + 'designations': designation, } - return render(request, 'filetracking/fileview.html', context) - - + return render(request, 'filetracking/drafts.html', context) -@login_required(login_url = "/accounts/login") -def fileview1(request,id): +@login_required(login_url="/accounts/login") +def outbox_view(request, id): """ The function is used to get all the files sent by user(employee) to other employees which are filtered from Tracking(table) objects by current user i.e. current_id. @@ -216,56 +214,88 @@ def fileview1(request,id): id - user id @variables: - out - The Tracking object filtered by current_id i.e, present working user. + outward_files - File objects filtered by current_id i.e, present working user. context - Holds data needed to make necessary changes in the template. - + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + + outward_files = view_outbox(username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking') + + for f in outward_files: + last_forw_tracking = get_last_forw_tracking_for_user(file_id=f['id'], + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation) + f['sent_to_user'] = last_forw_tracking.receiver_id + f['sent_to_design'] = last_forw_tracking.receive_design + f['last_sent_date'] = last_forw_tracking.forward_date - outward_files = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(current_id=request.user.extrainfo).order_by('-forward_date') + f['upload_date'] = parse_datetime(f['upload_date']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) - user_designation = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) + outward_files = add_uploader_department_to_files_list(outward_files) context = { - 'out': outward_files, - 'abcd': user_designation, + 'out_files': outward_files, + 'viewer_designation': designation, } - return render(request, 'filetracking/fileview1.html', context) + return render(request, 'filetracking/outbox.html', context) -@login_required(login_url = "/accounts/login") -def fileview2(request,id): - +@login_required(login_url="/accounts/login") +def inbox_view(request, id): """ The function is used to fetch the files received by the user form other employees. These files are filtered by receiver id and ordered by receive date. @param: request - trivial. - id - user id + id - HoldsDesignation object id @variables: - inward_file - The Tracking object filtered by receiver_id i.e, present working user. + inward_files - File object with additional sent by information context - Holds data needed to make necessary changes in the template. """ - inward_file = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(receiver_id=request.user).order_by('-receive_date') - user_designation = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) - s = str(user_designation).split(" - ") - designations = s[1] + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + inward_files = view_inbox( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # correct upload_date type and add recieve_date + for f in inward_files: + f['upload_date'] = parse_datetime(f['upload_date']) + + last_recv_tracking = get_last_recv_tracking_for_user(file_id=f['id'], + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation) + f['receive_date'] = last_recv_tracking.receive_date + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + inward_files = add_uploader_department_to_files_list(inward_files) + context = { - 'in_file': inward_file, - 'designations': designations, + 'in_file': inward_files, + 'designations': designation, } - return render(request, 'filetracking/fileview2.html', context) + return render(request, 'filetracking/inbox.html', context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def outward(request): """ This function fetches the different designations of the user and renders it on outward template @@ -274,22 +304,22 @@ def outward(request): @variables: context - Holds the different designation data of the user - + """ designation = get_designation(request.user) context = { 'designation': designation, } - return render( request, 'filetracking/outward.html', context) + return render(request, 'filetracking/outward.html', context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def inward(request): """ This function fetches the different designations of the user and renders it on inward template - + @param: request - trivial. @@ -298,7 +328,7 @@ def inward(request): """ designation = get_designation(request.user) context = { - + 'designation': designation, } return render(request, 'filetracking/inward.html', context) @@ -306,7 +336,6 @@ def inward(request): @login_required(login_url = "/accounts/login") def confirmdelete(request,id): - """ The function is used to confirm the deletion of a file. @param: @@ -316,16 +345,86 @@ def confirmdelete(request,id): @variables: context - Holds data needed to make necessary changes in the template. """ - file = File.objects.select_related('uploader__user','uploader__department','designation').get(pk = id) + file = File.objects.select_related( + 'uploader__user', 'uploader__department', 'designation').get(pk=id) context = { 'j': file, } - return render(request, 'filetracking/confirmdelete.html',context) + return render(request, 'filetracking/confirmdelete.html', context) +@login_required(login_url="/accounts/login") +def view_file(request, id): + ''' + This function is used to view a particular file received by an employee from another. + This function also conditionally renders two forms 'forward_file' and 'archive_file' + based on if the user has necessary permissions or not. + The business permissions are as follows: + 1. User can forward file only if they are the last recipient of the file + 2. User can archive a file only if they have received it last and they are also the original owner of the file -@login_required(login_url = "/accounts/login") + To forward the file and to archive the file separate views with POST request are called + + It displays the details file of a File and remarks as well as the attachments of all the users + who have been involved till that point of the workflow. + + @param: + request - Trivial. + id - ID of the file object which the user intends to forward to another employee. + + @variables: + file - The File object. + track - The Tracking object. + designation - the designations of the user + ''' + + file = get_object_or_404(File, id=id) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file).order_by('receive_date') + designations = get_designation(request.user) + + forward_enable = False + archive_enable = False + + current_owner = get_current_file_owner(file.id) + file_uploader = get_user_object_from_username(file.uploader.user.username) + + + if current_owner == request.user and file.is_read is False: + forward_enable = True + if current_owner == request.user and file_uploader == request.user and file.is_read is False: + archive_enable = True + + context = { + 'designations': designations, + 'file': file, + 'track': track, + 'forward_enable': forward_enable, + 'archive_enable': archive_enable, + } + return render(request, 'filetracking/viewfile.html', context) + +@login_required(login_url="/accounts/login") +def archive_file(request, id): + '''This function is used to archive a file. + It returns unauthorized access if the user is not file uploader + and the current owner of the file + ''' + if request.method == "POST": + file = get_object_or_404(File, id=id); + current_owner = get_current_file_owner(file.id) + file_uploader = get_user_object_from_username(file.uploader.user.username) + if current_owner == request.user and file_uploader == request.user: + file.is_read = True + file.save() + messages.success(request, 'File Archived') + else: + messages.error(request, 'Unauthorized access') + + return render(request, 'filetracking/composefile.html') + +@login_required(login_url="/accounts/login") def forward(request, id): """ The function is used to forward files received by user(employee) from other @@ -351,73 +450,72 @@ def forward(request, id): holdsdesignations = HoldsDesignation objects. context - Holds data needed to make necessary changes in the template. """ - - file = get_object_or_404(File, id=id) - track = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(file_id=file) - - if request.method == "POST": - if 'finish' in request.POST: - file.complete_flag = True - file.save() - - if 'send' in request.POST: - current_id = request.user.extrainfo - remarks = request.POST.get('remarks') - track.update(is_read=True) - sender = request.POST.get('sender') - current_design = HoldsDesignation.objects.select_related('user','working','designation').get(id=sender) - - receiver = request.POST.get('receiver') - try: - receiver_id = User.objects.get(username=receiver) - except Exception as e: - messages.error(request, 'Enter a valid destination') - designations = HoldsDesignation.objects.select_related('user','working','designation').filter(user=request.user) - - context = { - - 'designations': designations, - 'file': file, - 'track': track, - } - return render(request, 'filetracking/forward.html', context) - receive = request.POST.get('recieve') - try: - receive_design = Designation.objects.get(name=receive) - except Exception as e: - messages.error(request, 'Enter a valid Designation') - designations = get_designation(request.user) + file = get_object_or_404(File, id=id) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file).order_by('receive_date') - context = { - - 'designations': designations, - 'file': file, - 'track': track, - } - return render(request, 'filetracking/forward.html', context) + if request.method == "POST": + if 'finish' in request.POST: + file.is_read = True + file.save() + if 'send' in request.POST: + current_id = request.user.extrainfo + remarks = request.POST.get('remarks') + track.update(is_read=True) + + sender = request.POST.get('sender') + current_design = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=sender) + + receiver = request.POST.get('receiver') + try: + receiver_id = User.objects.get(username=receiver) + except Exception as e: + messages.error(request, 'Enter a valid destination') + designations = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + receive = request.POST.get('recieve') + try: + receive_design = Designation.objects.get(name=receive) + except Exception as e: + messages.error(request, 'Enter a valid Designation') + designations = get_designation(request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + + upload_file = request.FILES.get('myfile') + + Tracking.objects.create( + file_id=file, + current_id=current_id, + current_design=current_design, + receive_design=receive_design, + receiver_id=receiver_id, + remarks=remarks, + upload_file=upload_file, + ) + messages.success(request, 'File sent successfully') - - upload_file = request.FILES.get('myfile') - - Tracking.objects.create( - file_id=file, - current_id=current_id, - current_design=current_design, - receive_design=receive_design, - receiver_id=receiver_id, - remarks=remarks, - upload_file=upload_file, - ) - messages.success(request, 'File sent successfully') - - designations = get_designation(request.user) context = { - - 'designations':designations, + + 'designations': designations, 'file': file, 'track': track, } @@ -425,83 +523,88 @@ def forward(request, id): return render(request, 'filetracking/forward.html', context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def archive_design(request): - - designation = HoldsDesignation.objects.select_related('user','working','designation').filter(user=request.user) + designation = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) context = { 'designation': designation, } - return render( request, 'filetracking/archive_design.html', context) - - + return render(request, 'filetracking/archive_design.html', context) +@login_required(login_url="/accounts/login") +def archive_view(request, id): + """ + The function is used to fetch the files in the user's archive + (those which have passed by user and been archived/finished) -@login_required(login_url = "/accounts/login") -def archive(request , id): - - draft = File.objects.select_related('uploader__user','uploader__department','designation').filter(is_read=True).order_by('-upload_date') - + @param: + request - trivial. + id - HoldsDesignation object id - extrainfo = ExtraInfo.objects.select_related('user','department').all() - # designations = Designation.objects.filter(upload_designation=extrainfo.id) - abcd = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) - s = str(abcd).split(" - ") - designations = s[1] - #designations = HoldsDesignation.objects.filter(user=request.user) - # for x in designations: - # if abcd==x: - # designations=abcd + @variables: + archive_files - File object with additional information + context - Holds data needed to make necessary changes in the template. - context = { + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] - 'draft': draft, - 'extrainfo': extrainfo, - 'designations': designations, - } + archive_files = view_archived( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + # correct upload_date type and add receive_date + for f in archive_files: + f['upload_date'] = parse_datetime(f['upload_date']) + f['designation'] = Designation.objects.get(id=f['designation']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + archive_files = add_uploader_department_to_files_list(archive_files) + context = { + 'archive_files': archive_files, + 'designations': designation, + } + return render(request, 'filetracking/archive.html', context) - return render(request, 'filetracking/archive.html' , context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def archive_finish(request, id): - file1 = get_object_or_404(File, id=id) ##file = get_object_or_404(File, ref_id=id) + # file = get_object_or_404(File, ref_id=id) + file1 = get_object_or_404(File, id=id) track = Tracking.objects.filter(file_id=file1) - - return render(request, 'filetracking/archive_finish.html', {'file': file1, 'track': track}) - - -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def finish_design(request): - designation = HoldsDesignation.objects.select_related('user','working','designation').filter(user=request.user) + designation = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) context = { 'designation': designation, } - return render( request, 'filetracking/finish_design.html', context) + return render(request, 'filetracking/finish_design.html', context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def finish_fileview(request, id): - out = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(file_id__uploader=request.user.extrainfo, is_read=False).order_by('-forward_date') - - - - - abcd = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) + out = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id__uploader=request.user.extrainfo, is_read=False).order_by('-forward_date') + abcd = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) context = { @@ -511,38 +614,29 @@ def finish_fileview(request, id): return render(request, 'filetracking/finish_fileview.html', context) - - -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def finish(request, id): - file1 = get_object_or_404(File, id=id) ##file = get_object_or_404(File, ref_id=id) + # file = get_object_or_404(File, ref_id=id) + file1 = get_object_or_404(File, id=id) track = Tracking.objects.filter(file_id=file1) - if request.method == "POST": - if 'Finished' in request.POST: - File.objects.filter(pk=id).update(is_read=True) - track.update(is_read=True) - messages.success(request,'File Archived') - - - - - - - - return render(request, 'filetracking/finish.html', {'file': file1, 'track': track,'fileid':id}) - + if 'Finished' in request.POST: + File.objects.filter(pk=id).update(is_read=True) + track.update(is_read=True) + messages.success(request, 'File Archived') + return render(request, 'filetracking/finish.html', {'file': file1, 'track': track, 'fileid': id}) def AjaxDropdown1(request): + """ This function returns the designation of receiver on the forward or compose file template. @param: request - trivial. - + @variables: context - return the httpresponce containing the matched designation of the user @@ -553,20 +647,19 @@ def AjaxDropdown1(request): hold = Designation.objects.filter(name__startswith=value) holds = serializers.serialize('json', list(hold)) context = { - 'holds' : holds + 'holds': holds } return HttpResponse(JsonResponse(context), content_type='application/json') def AjaxDropdown(request): - """ This function returns the usernames of receiver on the forward or compose file template. @param: request - trivial. - + @variables: context - return the httpresponce containing the matched username @@ -589,24 +682,22 @@ def test(request): @login_required(login_url = "/accounts/login") def delete(request,id): - """ The function is used the delete of a file and it returns to the drafts page. @param: request - trivial. id - id of the file that is going to be deleted - + """ - file = File.objects.get(pk = id) + file = File.objects.get(pk=id) file.delete() - return redirect('/filetracking/drafts/') + return redirect('/filetracking/draftdesign/') def forward_inward(request,id): - """ This function is used forward the files which are available in the inbox of the user . @param: @@ -617,21 +708,25 @@ def forward_inward(request,id): file - file object track - tracking object of the file context - necessary data to render - + """ file = get_object_or_404(File, id=id) file.is_read = True - track = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(file_id=file) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file) designations = get_designation(request.user) context = { - - 'designations':designations, + + 'designations': designations, 'file': file, 'track': track, } return render(request, 'filetracking/forward.html', context) - +def get_designations_view(request, username): + designations = get_designations(username) + print(designations) + return JsonResponse(designations, safe=False) + diff --git a/FusionIIIT/applications/globals/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/globals/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..9fa2bfc59 --- /dev/null +++ b/FusionIIIT/applications/globals/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('globals', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='extrainfo', + name='user_status', + field=models.CharField(choices=[('NEW', 'NEW'), ('PRESENT', 'PRESENT')], default='PRESENT', max_length=50), + ), + ] diff --git a/FusionIIIT/applications/globals/migrations/0003_auto_20240308_1025.py b/FusionIIIT/applications/globals/migrations/0003_auto_20240308_1025.py new file mode 100644 index 000000000..2f9f4c3d6 --- /dev/null +++ b/FusionIIIT/applications/globals/migrations/0003_auto_20240308_1025.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('globals', '0002_auto_20240308_1023'), + ] + + operations = [ + migrations.AlterField( + model_name='extrainfo', + name='user_status', + field=models.CharField(choices=[('PRESENT', 'PRESENT'), ('NEW', 'NEW')], default='PRESENT', max_length=50), + ), + ] diff --git a/FusionIIIT/applications/iwdModuleV2/migrations/0002_bills_requests.py b/FusionIIIT/applications/iwdModuleV2/migrations/0002_bills_requests.py new file mode 100644 index 000000000..24909bc10 --- /dev/null +++ b/FusionIIIT/applications/iwdModuleV2/migrations/0002_bills_requests.py @@ -0,0 +1,41 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('iwdModuleV2', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Requests', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('description', models.CharField(max_length=200)), + ('area', models.CharField(max_length=200)), + ('requestCreatedBy', models.CharField(max_length=200)), + ('engineerProcessed', models.IntegerField()), + ('directorApproval', models.IntegerField()), + ('deanProcessed', models.IntegerField()), + ('status', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='Bills', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('work', models.CharField(max_length=200)), + ('description', models.CharField(max_length=200)), + ('agency', models.CharField(max_length=200)), + ('bill_processed', models.IntegerField()), + ('bill_settled', models.IntegerField()), + ('key', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='iwdModuleV2.projects', unique=True)), + ], + ), + ] diff --git a/FusionIIIT/applications/iwdModuleV2/models.py b/FusionIIIT/applications/iwdModuleV2/models.py index c0754c70d..e4c09f3cc 100644 --- a/FusionIIIT/applications/iwdModuleV2/models.py +++ b/FusionIIIT/applications/iwdModuleV2/models.py @@ -1,5 +1,5 @@ from django.db import models - +from datetime import date # Create your models here. @@ -170,6 +170,24 @@ class Requests(models.Model): directorApproval = models.IntegerField() deanProcessed = models.IntegerField() status = models.CharField(max_length=200) + issuedWorkOrder = models.IntegerField() + workCompleted = models.IntegerField() + +class WorkOrder(models.Model): + request_id = models.IntegerField() + name = models.CharField(max_length=200) + date = models.DateField(default=date.today) + agency = models.CharField(max_length=200) + amount = models.IntegerField() + deposit = models.IntegerField() + alloted_time = models.CharField(max_length=200) + start_date = models.DateField() + completion_date = models.DateField() + +class Inventory(models.Model): + name = models.CharField(max_length=200) + quantity = models.IntegerField() + cost = models.IntegerField() class Bills(models.Model): key = models.ForeignKey(Projects, on_delete=models.CASCADE, unique=True) diff --git a/FusionIIIT/applications/iwdModuleV2/urls.py b/FusionIIIT/applications/iwdModuleV2/urls.py index 2f047d690..1530d11c5 100644 --- a/FusionIIIT/applications/iwdModuleV2/urls.py +++ b/FusionIIIT/applications/iwdModuleV2/urls.py @@ -46,6 +46,18 @@ url('handleDirectorApprovalRequests/', views.handleDirectorApprovalRequests, name='Director-Approval-Requests'), url('handleDirectorRejectionRequests/', views.handleDirectorRejectionRequests, name='Director-Rejection-Requests'), url('requestsStatus/', views.requestsStatus, name='Requests-Status'), - url('billsView/',views.billsView, name='Bills View'), + url('fetchDesignations/', views.fetchDesignations, name='Fetch-Designations'), + url('fetchRequest/', views.fetchRequest, name='Fetch-Request'), + url('issueWorkOrder/', views.issueWorkOrder, name='Issue Work Order'), + url('workOrder/', views.workOrder, name='Work Order'), + url('inventory/', views.inventory, name='Inventory'), + url('addItemsView/', views.addItemsView, name='Add Items View'), + url('addItems/', views.addItems, name='Add Items'), + url('editInventoryView/', views.editInventoryView, name='Edit Inventory View'), + url('editInventory/', views.editInventory, name='Edit Inventory'), + url('requestsInProgess/', views.requestsInProgess, name='Requests In Progress'), + url('workCompleted/', views.workCompleted, name='Work Completed'), + url('requestFromInventory/', views.requestFromInventory, name='Request From Inventory'), + # url('billsView/',views.billsView, name='Bills View'), ] diff --git a/FusionIIIT/applications/iwdModuleV2/views.py b/FusionIIIT/applications/iwdModuleV2/views.py index 0a532548d..d661d67b4 100644 --- a/FusionIIIT/applications/iwdModuleV2/views.py +++ b/FusionIIIT/applications/iwdModuleV2/views.py @@ -1,9 +1,11 @@ from django.shortcuts import render, redirect +from django.urls import reverse from django.db.models import Q from applications.globals.models import * from .models import * from django.http import HttpResponseRedirect - +from applications.filetracking.sdk.methods import * +from applications.globals.models import ExtraInfo, HoldsDesignation, Designation # Create your views here. @@ -409,6 +411,19 @@ def extensionFormView(request): extensionObjects = ExtensionOfTimeDetails.objects.filter(key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/ExtensionForm.html', {'extension': extensionObjects}) +def fetchDesignations(request): + print("yesslkednonmedcm") + designations = Designation.objects.filter() + + holdsDesignations = [] + + for d in designations: + if d.name == "Engineer" or d.name == "Dean" or d.name == "director" or d.name == "Accounts Admin": + list = HoldsDesignation.objects.filter(designation=d) + holdsDesignations.append(list) + + return render(request, 'iwdModuleV2/requestsView.html', {'holdsDesignations' : holdsDesignations}) + def requestsView(request): if request.method == 'POST': formObject = Requests() @@ -421,87 +436,243 @@ def requestsView(request): formObject.deanProcessed = 0 formObject.requestCreatedBy = request.user.username formObject.status = "Pending" + formObject.issuedWorkOrder = 0 + formObject.workCompleted = 0 formObject.save() + request_object = Requests.objects.get(pk=formObject.pk) + d = HoldsDesignation.objects.get(user__username=request.POST['designation']) + create_file(uploader=request.user.username, + uploader_designation="Engineer", + receiver=request.POST['designation'], + receiver_designation=d.designation, + src_module="IWD", + src_object_id= str(request_object.id), + file_extra_JSON= {"value": 2}, + attached_file = None) return redirect('http://127.0.0.1:8000/iwdModuleV2/') return render(request, 'http://127.0.0.1:8000/iwdModuleV2/', {}) - -def billsView(request): - if request.method == 'POST': - formObject = Requests() - # formObject.key = Projects.objects.get(id=request.session['projectId']) - formObject.name = request.POST['name'] - formObject.work = request.POST['work'] - formObject.description = request.POST['description'] - formObject.agency = request.POST['agency'] - formObject.bill_processed = request.POST['bill_processed'] - formObject.bill_settled = request.POST['bill_settled'] - formObject.save() - return redirect('iwdModuleV2/billsView.html') - return render(request, 'iwdModuleV2/billsView.html', {}) - def createdRequests(request): obj = [] - requestsObject = Requests.objects.exclude( - Q(requestCreatedBy=request.user.username) | - Q(engineerProcessed__gt=0) | - Q(deanProcessed__gt=0) | - Q(directorApproval__gt=0) + + inbox_files = view_inbox( + username=request.user, + designation="Engineer", + src_module="IWD" ) - for x in requestsObject: - element = [x.id, x.name, x.area, x.description, x.requestCreatedBy] - obj.append(element) - return render(request, 'iwdModuleV2/createdRequests.html', {'obj' : obj}) + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + designations = Designation.objects.filter() + + holdsDesignations = [] + + for d in designations: + if d.name == "Engineer" or d.name == "Dean" or d.name == "director" or d.name == "Accounts Admin": + list = HoldsDesignation.objects.filter(designation=d) + holdsDesignations.append(list) + + return render(request, 'iwdModuleV2/createdRequests.html', {'obj' : obj, 'holdsDesignations' : holdsDesignations}) def handleEngineerProcessRequests(request): if request.method == 'POST': + request_id = request.POST.get("id", 0) + + d = HoldsDesignation.objects.get(user__username=request.POST['designation']) + d1 = HoldsDesignation.objects.get(user__username=request.user) + + create_file(uploader=request.user.username, + uploader_designation=d1.designation, + receiver=request.POST['designation'], + receiver_designation=d.designation, + src_module="IWD", + src_object_id= str(request_id), + file_extra_JSON= {"value": 2}, + attached_file = None) + Requests.objects.filter(id=request_id).update(engineerProcessed=1, status="Approved by the engineer") + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + for p in inbox_files: + if p['src_object_id'] == request_id: + delete_file(file_id = p['id']) + break + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + obj = [] - requestsObject = Requests.objects.filter(engineerProcessed = 0, deanProcessed = 0, directorApproval = 0) - for x in requestsObject: - element = [x.id, x.name, x.area, x.description, x.requestCreatedBy] - obj.append(element) + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + return render(request, 'iwdModuleV2/createdRequests.html', {'obj' : obj}) def engineerProcessedRequests(request): + obj = [] - requestsObject = Requests.objects.filter(engineerProcessed = 1, deanProcessed = 0, directorApproval = 0) - for x in requestsObject: - element = [x.id, x.name, x.area, x.description, x.requestCreatedBy] - obj.append(element) - return render(request, 'iwdModuleV2/engineerProcessedRequests.html', {'obj' : obj}) + + d = HoldsDesignation.objects.get(user__username=request.user) + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + designations = Designation.objects.filter() + + holdsDesignations = [] + + for d in designations: + if d.name == "Engineer" or d.name == "Dean" or d.name == "director" or d.name == "Accounts Admin": + list = HoldsDesignation.objects.filter(designation=d) + holdsDesignations.append(list) + + return render(request, 'iwdModuleV2/engineerProcessedRequests.html', {'obj' : obj, 'holdsDesignations' : holdsDesignations}) def handleDeanProcessRequests(request): if request.method == 'POST': + request_id = request.POST.get("id", 0) + + d = HoldsDesignation.objects.get(user__username=request.POST['designation']) + d1 = HoldsDesignation.objects.get(user__username=request.user) + + create_file(uploader=request.user.username, + uploader_designation=d1.designation, + receiver=request.POST['designation'], + receiver_designation=d.designation, + src_module="IWD", + src_object_id= str(request_id), + file_extra_JSON= {"value": 2}, + attached_file = None) + Requests.objects.filter(id=request_id).update(deanProcessed=1, status="Approved by the dean") + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + for p in inbox_files: + if p['src_object_id'] == request_id: + delete_file(file_id = p['id']) + break + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + obj = [] - requestsObject = Requests.objects.filter(engineerProcessed = 1, deanProcessed = 0, directorApproval = 0) - for x in requestsObject: - element = [x.id, x.name, x.area, x.description, x.requestCreatedBy] - obj.append(element) + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + return render(request, 'iwdModuleV2/engineerProcessedRequests.html', {'obj' : obj}) def deanProcessedRequests(request): - print(request) obj = [] - requestsObject = Requests.objects.filter(engineerProcessed = 1, deanProcessed = 1, directorApproval = 0) - for x in requestsObject: - element = [x.id, x.name, x.area, x.description, x.requestCreatedBy] - obj.append(element) - return render(request, 'iwdModuleV2/deanProcessedRequests.html', {'obj' : obj}) + + d = HoldsDesignation.objects.get(user__username=request.user) + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + designations = Designation.objects.filter() + + holdsDesignations = [] + + for d in designations: + if d.name == "Engineer" or d.name == "Dean" or d.name == "director" or d.name == "Accounts Admin": + list = HoldsDesignation.objects.filter(designation=d) + holdsDesignations.append(list) + + return render(request, 'iwdModuleV2/deanProcessedRequests.html', {'obj' : obj, 'holdsDesignations' : holdsDesignations}) def handleDirectorApprovalRequests(request): if request.method == 'POST': request_id = request.POST.get("id", 0) + + d = HoldsDesignation.objects.get(user__username=request.POST['designation']) + d1 = HoldsDesignation.objects.get(user__username=request.user) + + create_file(uploader=request.user.username, + uploader_designation=d1.designation, + receiver=request.POST['designation'], + receiver_designation=d.designation, + src_module="IWD", + src_object_id= str(request_id), + file_extra_JSON= {"value": 2}, + attached_file = None) + Requests.objects.filter(id=request_id).update(directorApproval=1, status="Approved by the director") + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + for p in inbox_files: + if p['src_object_id'] == request_id: + delete_file(file_id = p['id']) + break + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + obj = [] - requestsObject = Requests.objects.filter(engineerProcessed = 1, deanProcessed = 1, directorApproval = 0) - for x in requestsObject: - element = [x.id, x.name, x.area, x.description, x.requestCreatedBy] - obj.append(element) + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + return render(request, 'iwdModuleV2/deanProcessedRequests.html', {'obj' : obj}) def handleDirectorRejectionRequests(request): @@ -515,8 +686,82 @@ def handleDirectorRejectionRequests(request): obj.append(element) return render(request, 'iwdModuleV2/deanProcessedRequests.html', {'obj' : obj}) +def issueWorkOrder(request): + obj = [] + + d = HoldsDesignation.objects.get(user__username=request.user) + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + for result in inbox_files: + uploader = result['sent_by_designation'] + if uploader == 'director': + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + return render(request, 'iwdModuleV2/issueWorkOrder.html', {'obj' : obj}) + +def fetchRequest(request): + request_id = request.POST.get("id", 0) + req_request = Requests.objects.get(id=request_id) + return render(request, 'iwdModuleV2/workOrder.html', {'req' : req_request}) + +def workOrder(request): + if request.method == 'POST': + formObject = WorkOrder() + formObject.request_id = request.POST['id'] + formObject.name = request.POST['name'] + formObject.date = request.POST['date'] + formObject.agency = request.POST['agency'] + formObject.amount = request.POST['amount'] + formObject.deposit = request.POST['deposit'] + formObject.alloted_time = request.POST['time'] + formObject.start_date = request.POST['startDate'] + formObject.completion_date = request.POST['completionDate'] + formObject.save() + + Requests.objects.filter(id=request.POST['id']).update(status="Work Order issued", issuedWorkOrder=1) + + d = HoldsDesignation.objects.get(user__username=request.user) + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + for result in inbox_files: + if result['src_object_id'] == request.POST['id'] and result['sent_by_designation'] == 'director': + delete_file(file_id = result['id']) + break + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + obj = [] + + for result in inbox_files: + uploader = result['sent_by_designation'] + if uploader == 'director': + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + return render(request, 'iwdModuleV2/issueWorkOrder.html', {'obj' : obj}) + def requestsStatus(request): - print(request) obj = [] requestsObject = Requests.objects.all() for x in requestsObject: @@ -524,3 +769,75 @@ def requestsStatus(request): obj.append(element) return render(request, 'iwdModuleV2/requestsStatus.html', {'obj' : obj}) +def inventory(request): + items = Inventory.objects.filter() + obj = [] + for i in items: + element = [i.id, i.name, i.quantity, i.cost] + obj.append(element) + return render(request, 'iwdModuleV2/inventory.html', {'obj' : obj}) + +def addItemsView(request): + return render(request, 'iwdModuleV2/addItemsView.html') + +def addItems(request): + if request.method == "POST": + formObject = Inventory() + formObject.name = request.POST['name'] + formObject.quantity = request.POST['quantity'] + formObject.cost = request.POST['cost'] + formObject.save() + return render(request, 'iwdModuleV2/addItemsView.html') + +def editInventoryView(request): + items = Inventory.objects.filter() + obj = [] + for i in items: + element = [i.id, i.name, i.quantity, i.cost] + obj.append(element) + return render(request, 'iwdModuleV2/editInventory.html', {'obj' : obj}) + +def editInventory(request): + if request.method == "POST": + itemId = request.POST['id'] + itemName = request.POST['name'] + itemQuantity = request.POST['quantity'] + itemCost = request.POST['cost'] + Inventory.objects.filter(id=itemId).update(name=itemName, quantity=itemQuantity, cost=itemCost) + items = Inventory.objects.filter() + obj = [] + for i in items: + element = [i.id, i.name, i.quantity, i.cost] + obj.append(element) + return render(request, 'iwdModuleV2/editInventory.html', {'obj' : obj}) + +def requestsInProgess(request): + obj = [] + requestsObject = Requests.objects.filter(issuedWorkOrder=1) + for x in requestsObject: + element = [x.id, x.name, x.area, x.description, x.requestCreatedBy, x.workCompleted] + obj.append(element) + return render(request, 'iwdModuleV2/requestsInProgress.html', {'obj' : obj}) + +def workCompleted(request): + if request.method == 'POST': + Requests.objects.filter(id=request.POST['id']).update(workCompleted=1, status="Work Completed") + obj = [] + requestsObject = Requests.objects.filter(issuedWorkOrder=1) + for x in requestsObject: + element = [x.id, x.name, x.area, x.description, x.requestCreatedBy, x.workCompleted] + obj.append(element) + return render(request, 'iwdModuleV2/requestsInProgress.html', {'obj' : obj}) + +def requestFromInventory(request): + if request.method == 'POST': + requestId = request.POST['id'] + Req = Requests.objects.filter(id=requestId) + Items = Inventory.objects.filter() + req = [] + items = [] + for i in Req: + print(i) + print(req) + print(items) + return render(request, 'iwdModuleV2/requestFromInventory.html', {'req' : req, 'items' : items}) \ No newline at end of file diff --git a/FusionIIIT/applications/programme_curriculum/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/programme_curriculum/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..fef68f722 --- /dev/null +++ b/FusionIIIT/applications/programme_curriculum/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('programme_curriculum', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='batch', + name='year', + field=models.PositiveIntegerField(default=2024), + ), + migrations.AlterField( + model_name='programme', + name='programme_begin_year', + field=models.PositiveIntegerField(default=2024), + ), + ] diff --git a/FusionIIIT/applications/scholarships/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/scholarships/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..997db0247 --- /dev/null +++ b/FusionIIIT/applications/scholarships/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('scholarships', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='previous_winner', + name='year', + field=models.IntegerField(default=2024), + ), + ] diff --git a/FusionIIIT/templates/iwdModuleV2/addItemsView.html b/FusionIIIT/templates/iwdModuleV2/addItemsView.html new file mode 100644 index 000000000..b9b1f003c --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/addItemsView.html @@ -0,0 +1,120 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} +Academic +{% endblock %} + + +{% block body %} +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} + +
+ Add Items +
+
+ {% csrf_token %} +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+{% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/createdRequests.html b/FusionIIIT/templates/iwdModuleV2/createdRequests.html index a7f86e523..cce743dec 100644 --- a/FusionIIIT/templates/iwdModuleV2/createdRequests.html +++ b/FusionIIIT/templates/iwdModuleV2/createdRequests.html @@ -61,6 +61,7 @@ Description Area Created By + Send to @@ -76,6 +77,13 @@
{% csrf_token %} +
diff --git a/FusionIIIT/templates/iwdModuleV2/dashboard.html b/FusionIIIT/templates/iwdModuleV2/dashboard.html index 12c27a550..f18a5c156 100644 --- a/FusionIIIT/templates/iwdModuleV2/dashboard.html +++ b/FusionIIIT/templates/iwdModuleV2/dashboard.html @@ -38,7 +38,7 @@ - {% comment %}The left-rail segment ends here!{% endcomment %} - - {% comment %}The central-rail segment starts here!{% endcomment %} -
- {% comment %}The Appointments Form starts here!{% endcomment %} -
- {% block appointment %} - {% include 'iwdModuleV2/requestsView.html' %} - {% endblock %} -
-
{% endif %} {% if eligible == "Dean" %} @@ -121,6 +119,26 @@
{% comment %}The left-rail segment ends here!{% endcomment %} + {% comment %}The central-rail segment starts here!{% endcomment %} + {% endif %} + {% if eligible == "Admin IWD" %} +
+ {% comment %}The Tab-Menu starts here!{% endcomment %} + + {% comment %}The Tab-Menu ends here!{% endcomment %} + +
+ {% comment %}ROW #2 ends here!{% endcomment %} + +
+ {% comment %}The left-rail segment ends here!{% endcomment %} + {% comment %}The central-rail segment starts here!{% endcomment %} {% endif %} {% comment %}The central-rail segment ends here!{% endcomment %} diff --git a/FusionIIIT/templates/iwdModuleV2/deanProcessedRequests.html b/FusionIIIT/templates/iwdModuleV2/deanProcessedRequests.html index dd9ba8ba8..98f9ad72f 100644 --- a/FusionIIIT/templates/iwdModuleV2/deanProcessedRequests.html +++ b/FusionIIIT/templates/iwdModuleV2/deanProcessedRequests.html @@ -68,11 +68,25 @@
{% csrf_token %} +
{% csrf_token %} +
diff --git a/FusionIIIT/templates/iwdModuleV2/editInventory.html b/FusionIIIT/templates/iwdModuleV2/editInventory.html new file mode 100644 index 000000000..1cc32767f --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/editInventory.html @@ -0,0 +1,124 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} +Academic +{% endblock %} + + +{% block body %} +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ + +
+
+ Inventory +
+
+
+
+ + + + + + + + + + + + + {% for f in obj %} + + + + {% csrf_token %} + + + + + + + + + {% endfor %} +
IdNameQuantityCost (in Rupees)
{{f.0}} + + + + + + + + +
+
+
+
+ + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+{% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/engineerProcessedRequests.html b/FusionIIIT/templates/iwdModuleV2/engineerProcessedRequests.html index 7c3bd813d..6b7386054 100644 --- a/FusionIIIT/templates/iwdModuleV2/engineerProcessedRequests.html +++ b/FusionIIIT/templates/iwdModuleV2/engineerProcessedRequests.html @@ -78,6 +78,13 @@
{% csrf_token %} +
diff --git a/FusionIIIT/templates/iwdModuleV2/inventory.html b/FusionIIIT/templates/iwdModuleV2/inventory.html new file mode 100644 index 000000000..4e35ce614 --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/inventory.html @@ -0,0 +1,111 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} +Academic +{% endblock %} + + +{% block body %} +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ + + +
+
+ Inventory +
+
+
+
+ + + + + + + + + + + + {% for f in obj %} + + + + + + + + + {% endfor %} +
IdNameQuantityCost (in Rupees)
{{f.0}}{{f.1}}{{f.2}}{{f.3}}
+
+
+
+ + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+{% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/issueWorkOrder.html b/FusionIIIT/templates/iwdModuleV2/issueWorkOrder.html new file mode 100644 index 000000000..7aef765b2 --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/issueWorkOrder.html @@ -0,0 +1,120 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} +Academic +{% endblock %} + + +{% block body %} +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ +
+
+ Issue Work Order +
+
+
+
+ + + + + + + + + + + + + + {% for f in obj %} + + + + + + + + + + + {% endfor %} +
Details:-
IdNameDescriptionAreaCreated By
{{f.0}}{{f.1}}{{f.3}}{{f.2}}{{f.4}} + +
+ {% csrf_token %} + + +
+
+
+
+
+ + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+{% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/requestFromInventory.html b/FusionIIIT/templates/iwdModuleV2/requestFromInventory.html new file mode 100644 index 000000000..c17aeb3da --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/requestFromInventory.html @@ -0,0 +1,172 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} +Academic +{% endblock %} + + +{% block body %} +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ +
+
+ Work Order +
+
{% csrf_token %} +
+ +
+ +
+
+ + + +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ + {% csrf_token %} + + +
+ +
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+{% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} + + + + diff --git a/FusionIIIT/templates/iwdModuleV2/requestsInProgress.html b/FusionIIIT/templates/iwdModuleV2/requestsInProgress.html new file mode 100644 index 000000000..67809a40c --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/requestsInProgress.html @@ -0,0 +1,134 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} +Academic +{% endblock %} + + +{% block body %} +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ +
+
+ Created Requests +
+
+
+
+ + + + + + + + + + + + + + {% for f in obj %} + + + + + + + + + + + {% endfor %} +
Details:-
IdNameDescriptionAreaCreated By
{{f.0}}{{f.1}}{{f.3}}{{f.2}}{{f.4}} + {% if f.5 == 1 %} +
+ {% csrf_token %} + + +
+ {% endif %} + {% if f.5 == 0 %} +
+ {% csrf_token %} + + +
+
+
+ {% csrf_token %} + + +
+ {% endif %} +
+
+
+
+ + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+{% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/requestsView.html b/FusionIIIT/templates/iwdModuleV2/requestsView.html index 230ebe362..882e84274 100644 --- a/FusionIIIT/templates/iwdModuleV2/requestsView.html +++ b/FusionIIIT/templates/iwdModuleV2/requestsView.html @@ -1,124 +1,135 @@ - +{% extends 'globals/base.html' %} {% load static %} {% block title %} - Academic +Academic {% endblock %} {% block body %} - {% block navBar %} - - {% endblock %} - - - - {% comment %}The left-margin segment!{% endcomment %} - +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} - {% comment %}The left-rail segment starts here!{% endcomment %} - - {% comment %}The user image card starts here!{% endcomment %} - {% block usercard %} - - {% endblock %} - {% comment %}The user image card ends here!{% endcomment %} +
- + {% comment %}The left-margin segment!{% endcomment %} +
- {% comment %}The Tab-Menu ends here!{% endcomment %} - - {% comment %} - The left-rail segment ends here! - {% endcomment %} + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} - {% comment %} - The central-rail segment starts here! - {% endcomment %} -
+
+ {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
- {% load static %} -
- Requests -
-
{% csrf_token %} -
+ {% load static %} + {% comment %}the main tab starts here {% endcomment %} +
+ +
+
+ Requests +
+ {% csrf_token %} +
-
+
+
- -
- -
- + +
+ +
+ +
-
- -
- -
- -
- -
-
- + +
+
- - -
- - + +
+
-
- - - -
-
+ +
+ +
+ +
+ +
+
+ +
+ + +
+ +
+ +
+ + + + +
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %}
-
- - - - {% comment %}The central-rail segment ends here!{% endcomment %} +{% endblock %} - {% comment %}The right-rail segment starts here!{% endcomment %} - - {% comment %}The right-rail segment ends here!{% endcomment %} +{% block javascript %} + + + + +{% endblock %} - {% comment %}The right-margin segment!{% endcomment %} - - {% comment %}The grid ends here!{% endcomment %} -{% endblock %} -{% block javascript %} - - - - -{% endblock %} \ No newline at end of file diff --git a/FusionIIIT/templates/iwdModuleV2/workOrder.html b/FusionIIIT/templates/iwdModuleV2/workOrder.html new file mode 100644 index 000000000..11f2f9d93 --- /dev/null +++ b/FusionIIIT/templates/iwdModuleV2/workOrder.html @@ -0,0 +1,175 @@ +{% extends 'globals/base.html' %} +{% load static %} + + +{% block title %} +Academic +{% endblock %} + + +{% block body %} +{% block navBar %} +{% include 'dashboard/navbar.html' %} +{% endblock %} + +
+ + {% comment %}The left-margin segment!{% endcomment %} +
+ + {% comment %}The left-rail segment starts here!{% endcomment %} +
+ {% comment %}The user image card starts here!{% endcomment %} + {% block usercard %} + {% include 'globals/usercard.html' %} + {% endblock %} + {% comment %}The user image card ends here!{% endcomment %} + +
+ + {% comment %}The Tab-Menu ends here!{% endcomment %} +
+ {% comment %} + The left-rail segment ends here! + {% endcomment %} + + {% comment %} + The central-rail segment starts here! + {% endcomment %} +
+ + + + {% load static %} + {% comment %}the main tab starts here {% endcomment %} + +
+ Work Order +
+
{% csrf_token %} +
+ +
+ + +
+
+ + + + + +
+ +
+ +
+ + +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ {% comment %}The central-rail segment ends here!{% endcomment %} + + {% comment %}The right-rail segment starts here!{% endcomment %} +
+
+ {% comment %} + TODO: the right rail! + {% endcomment %} +
+
+ {% comment %}The right-rail segment ends here!{% endcomment %} + + {% comment %}The right-margin segment!{% endcomment %} +
+ +
+{% comment %}The grid ends here!{% endcomment %} + +{% endblock %} + +{% block javascript %} + + + + +{% endblock %} + + + + From a823ed59081ca43ea171ccc5ec1a29b27a4ac330 Mon Sep 17 00:00:00 2001 From: Srivatsa19 <96564832+Srivatsa19@users.noreply.github.com> Date: Thu, 11 Apr 2024 13:21:37 +0530 Subject: [PATCH 05/19] Gad 2 2025 dashboard integrated (#1356) * GAD-5: Fix responsiveness (#1125) Co-authored-by: A Anunaya <76819712+Anunaya07@users.noreply.github.com> Co-authored-by: Aksh Bansal <63552235+Aksh-Bansal-dev@users.noreply.github.com> * Implemented the cerate_request, process_request and approve/reject_request use cases. * GAD -5 Dashboard Changes (#1325) * dashboard and usercard updated (#1329) * Fixing ui bugs (#1335) * Changes made --------- Co-authored-by: Harshvardhan Singh <73544247+Lawful2002@users.noreply.github.com> Co-authored-by: A Anunaya <76819712+Anunaya07@users.noreply.github.com> Co-authored-by: Aksh Bansal <63552235+Aksh-Bansal-dev@users.noreply.github.com> Co-authored-by: akshatnema <20bcs022@iiitdmj.ac.in> Co-authored-by: BlackHAWK2001 <150950834+BlackHAWK2001@users.noreply.github.com> Co-authored-by: Arpit Tak <140220904+Ishu-ji@users.noreply.github.com> Co-authored-by: SukulSarve <143542658+SukulSarve@users.noreply.github.com> --- FusionIIIT/Fusion/context_processors.py | 5 + .../Fusion/middleware/custom_middleware.py | 48 ++ FusionIIIT/Fusion/settings/common.py | 2 + .../migrations/0002_auto_20240308_1023.py | 38 + .../eis/migrations/0002_auto_20240308_1023.py | 53 ++ .../filetracking/api/serializers.py | 24 + .../applications/filetracking/api/urls.py | 22 + .../applications/filetracking/api/views.py | 111 +++ .../applications/filetracking/decorators.py | 38 + .../filetracking/filetracking/admin.py | 7 + .../filetracking/api/serializers.py | 24 + .../filetracking/filetracking/api/urls.py | 22 + .../filetracking/filetracking/api/views.py | 111 +++ .../filetracking/filetracking/apps.py | 5 + .../filetracking/filetracking/decorators.py | 38 + .../filetracking/migrations/0001_initial.py | 53 ++ .../filetracking/migrations/__init__.py | 0 .../filetracking/filetracking/models.py | 51 ++ .../filetracking/filetracking/sdk/methods.py | 423 ++++++++++ .../filetracking/filetracking/tests.py | 3 + .../filetracking/filetracking/urls.py | 43 + .../filetracking/filetracking/utils.py | 7 + .../filetracking/filetracking/views.py | 732 ++++++++++++++++++ .../migrations/0002_auto_20240308_1023.py | 33 + .../applications/filetracking/models.py | 12 +- .../applications/filetracking/sdk/methods.py | 424 ++++++++++ FusionIIIT/applications/filetracking/urls.py | 40 +- FusionIIIT/applications/filetracking/views.py | 555 +++++++------ .../migrations/0002_auto_20240308_1023.py | 18 + .../migrations/0003_auto_20240308_1025.py | 18 + FusionIIIT/applications/globals/urls.py | 3 +- FusionIIIT/applications/globals/views.py | 87 ++- .../migrations/0002_bills_requests.py | 41 + FusionIIIT/applications/iwdModuleV2/models.py | 39 +- FusionIIIT/applications/iwdModuleV2/urls.py | 25 +- FusionIIIT/applications/iwdModuleV2/views.py | 454 ++++++++++- .../migrations/0002_auto_20240308_1023.py | 23 + .../migrations/0002_auto_20240308_1023.py | 18 + .../academic_procedures/academic.html | 44 +- FusionIIIT/templates/dashboard/dashboard.html | 11 +- FusionIIIT/templates/dashboard/modules.html | 279 +++++-- FusionIIIT/templates/dashboard/navbar.html | 213 +++-- .../templates/dashboard/sidenavbar.html | 46 +- FusionIIIT/templates/globals/usercard.html | 95 ++- .../templates/iwdModuleV2/addItemsView.html | 120 +++ .../templates/iwdModuleV2/billsView.html | 147 ++++ .../iwdModuleV2/createdRequests.html | 128 +++ .../templates/iwdModuleV2/dashboard.html | 103 ++- .../iwdModuleV2/deanProcessedRequests.html | 110 +++ .../templates/iwdModuleV2/editInventory.html | 124 +++ .../engineerProcessedRequests.html | 128 +++ .../templates/iwdModuleV2/inventory.html | 111 +++ .../templates/iwdModuleV2/issueWorkOrder.html | 120 +++ .../iwdModuleV2/requestFromInventory.html | 172 ++++ .../iwdModuleV2/requestsInProgress.html | 134 ++++ .../templates/iwdModuleV2/requestsStatus.html | 114 +++ .../templates/iwdModuleV2/requestsView.html | 135 ++++ .../templates/iwdModuleV2/workOrder.html | 175 +++++ requirements.txt | 2 +- 59 files changed, 5632 insertions(+), 529 deletions(-) create mode 100644 FusionIIIT/Fusion/context_processors.py create mode 100644 FusionIIIT/Fusion/middleware/custom_middleware.py create mode 100644 FusionIIIT/applications/academic_procedures/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/eis/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/filetracking/api/serializers.py create mode 100644 FusionIIIT/applications/filetracking/api/urls.py create mode 100644 FusionIIIT/applications/filetracking/api/views.py create mode 100644 FusionIIIT/applications/filetracking/decorators.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/admin.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/api/serializers.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/api/urls.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/api/views.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/apps.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/decorators.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/migrations/0001_initial.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/migrations/__init__.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/models.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/sdk/methods.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/tests.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/urls.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/utils.py create mode 100644 FusionIIIT/applications/filetracking/filetracking/views.py create mode 100644 FusionIIIT/applications/filetracking/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/filetracking/sdk/methods.py create mode 100644 FusionIIIT/applications/globals/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/globals/migrations/0003_auto_20240308_1025.py create mode 100644 FusionIIIT/applications/iwdModuleV2/migrations/0002_bills_requests.py create mode 100644 FusionIIIT/applications/programme_curriculum/migrations/0002_auto_20240308_1023.py create mode 100644 FusionIIIT/applications/scholarships/migrations/0002_auto_20240308_1023.py mode change 100755 => 100644 FusionIIIT/templates/academic_procedures/academic.html mode change 100755 => 100644 FusionIIIT/templates/dashboard/dashboard.html mode change 100755 => 100644 FusionIIIT/templates/dashboard/modules.html mode change 100755 => 100644 FusionIIIT/templates/dashboard/navbar.html mode change 100755 => 100644 FusionIIIT/templates/globals/usercard.html create mode 100644 FusionIIIT/templates/iwdModuleV2/addItemsView.html create mode 100644 FusionIIIT/templates/iwdModuleV2/billsView.html create mode 100644 FusionIIIT/templates/iwdModuleV2/createdRequests.html create mode 100644 FusionIIIT/templates/iwdModuleV2/deanProcessedRequests.html create mode 100644 FusionIIIT/templates/iwdModuleV2/editInventory.html create mode 100644 FusionIIIT/templates/iwdModuleV2/engineerProcessedRequests.html create mode 100644 FusionIIIT/templates/iwdModuleV2/inventory.html create mode 100644 FusionIIIT/templates/iwdModuleV2/issueWorkOrder.html create mode 100644 FusionIIIT/templates/iwdModuleV2/requestFromInventory.html create mode 100644 FusionIIIT/templates/iwdModuleV2/requestsInProgress.html create mode 100644 FusionIIIT/templates/iwdModuleV2/requestsStatus.html create mode 100644 FusionIIIT/templates/iwdModuleV2/requestsView.html create mode 100644 FusionIIIT/templates/iwdModuleV2/workOrder.html diff --git a/FusionIIIT/Fusion/context_processors.py b/FusionIIIT/Fusion/context_processors.py new file mode 100644 index 000000000..54566d56e --- /dev/null +++ b/FusionIIIT/Fusion/context_processors.py @@ -0,0 +1,5 @@ +def global_vars(request): + return { + 'global_var': request.session.get('currentDesignationSelected', 'default_value'), + 'global_var2': request.session.get('allDesignations', 'default_value2'), + } \ No newline at end of file diff --git a/FusionIIIT/Fusion/middleware/custom_middleware.py b/FusionIIIT/Fusion/middleware/custom_middleware.py new file mode 100644 index 000000000..f77873534 --- /dev/null +++ b/FusionIIIT/Fusion/middleware/custom_middleware.py @@ -0,0 +1,48 @@ +# custom_middleware.py +from django.contrib.auth.signals import user_logged_in +from django.dispatch import receiver +from applications.globals.models import (ExtraInfo, Feedback, HoldsDesignation, + Issue, IssueImage, DepartmentInfo) +from django.shortcuts import get_object_or_404, redirect, render + +def user_logged_in_middleware(get_response): + @receiver(user_logged_in) + def user_logged_in_handler(sender, user, request, **kwargs): + if 'function_executed' not in request.session: + # Run the function only if the flag is not set + # Assuming user is a model with the desired data field, retrieve the data + # For example, if your User model has a field named 'custom_field', you can access it like: + if user.is_authenticated: + desig = list(HoldsDesignation.objects.select_related('user','working','designation').all().filter(working = request.user).values_list('designation')) + print(desig) + b = [i for sub in desig for i in sub] + design = HoldsDesignation.objects.select_related('user','designation').filter(working=request.user) + + designation=[] + + designation.append(str(user.extrainfo.user_type)) + for i in design: + if str(i.designation) != str(user.extrainfo.user_type): + print('-------') + print(i.designation) + print(user.extrainfo.user_type) + print('') + designation.append(str(i.designation)) + + for i in designation: + print(i) + + request.session['currentDesignationSelected'] = designation[0] + request.session['allDesignations'] = designation + print("logged iN") + + # Set the flag in the session to indicate that the function has bee+n executed + request.session['function_executed'] = True + + def middleware(request): + if request.user.is_authenticated: + user_logged_in_handler(request.user, request.user, request) + response = get_response(request) + return response + + return middleware \ No newline at end of file diff --git a/FusionIIIT/Fusion/settings/common.py b/FusionIIIT/Fusion/settings/common.py index b98ea6960..fabe81ec2 100644 --- a/FusionIIIT/Fusion/settings/common.py +++ b/FusionIIIT/Fusion/settings/common.py @@ -163,6 +163,7 @@ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'Fusion.middleware.custom_middleware.user_logged_in_middleware', ] ROOT_URLCONF = 'Fusion.urls' @@ -178,6 +179,7 @@ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', + 'Fusion.context_processors.global_vars', ], }, }, diff --git a/FusionIIIT/applications/academic_procedures/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/academic_procedures/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..2b5457988 --- /dev/null +++ b/FusionIIIT/applications/academic_procedures/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,38 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('academic_procedures', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='assistantshipclaim', + name='year', + field=models.IntegerField(choices=[(2024, 2024), (2023, 2023)]), + ), + migrations.AlterField( + model_name='course_registration', + name='working_year', + field=models.IntegerField(blank=True, choices=[(2024, 2024), (2023, 2023)], null=True), + ), + migrations.AlterField( + model_name='finalregistrations', + name='batch', + field=models.IntegerField(default=2024), + ), + migrations.AlterField( + model_name='messdue', + name='year', + field=models.IntegerField(choices=[(2024, 2024), (2023, 2023)]), + ), + migrations.AlterField( + model_name='register', + name='year', + field=models.IntegerField(default=2024), + ), + ] diff --git a/FusionIIIT/applications/eis/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/eis/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..217222095 --- /dev/null +++ b/FusionIIIT/applications/eis/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,53 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('eis', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='emp_achievement', + name='a_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_confrence_organised', + name='k_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_expert_lectures', + name='l_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_keynote_address', + name='k_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_mtechphd_thesis', + name='s_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_patents', + name='p_year', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_published_books', + name='pyear', + field=models.IntegerField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], null=True, verbose_name='year'), + ), + migrations.AlterField( + model_name='emp_research_papers', + name='year', + field=models.CharField(blank=True, choices=[(1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017), (2018, 2018), (2019, 2019), (2020, 2020), (2021, 2021), (2022, 2022), (2023, 2023), (2024, 2024)], max_length=10, null=True), + ), + ] diff --git a/FusionIIIT/applications/filetracking/api/serializers.py b/FusionIIIT/applications/filetracking/api/serializers.py new file mode 100644 index 000000000..bdae2024e --- /dev/null +++ b/FusionIIIT/applications/filetracking/api/serializers.py @@ -0,0 +1,24 @@ +from applications.filetracking.models import File, Tracking +from django.core.files import File as DjangoFile +from rest_framework import serializers + + +class FileSerializer(serializers.ModelSerializer): + class Meta: + model = File + fields = '__all__' + + +class TrackingSerializer(serializers.ModelSerializer): + class Meta: + model = Tracking + fields = '__all__' + + +class FileHeaderSerializer(serializers.ModelSerializer): + ''' + This serializes everything except the attachments of a file and whether it is read or not + ''' + class Meta: + model = File + exclude = ['upload_file', 'is_read'] diff --git a/FusionIIIT/applications/filetracking/api/urls.py b/FusionIIIT/applications/filetracking/api/urls.py new file mode 100644 index 000000000..90f03b2ef --- /dev/null +++ b/FusionIIIT/applications/filetracking/api/urls.py @@ -0,0 +1,22 @@ +from django.conf.urls import url +from .views import ( + CreateFileView, + ViewFileView, + DeleteFileView, + ViewInboxView, + ViewOutboxView, + ViewHistoryView, + ForwardFileView, + GetDesignationsView, +) + +urlpatterns = [ + url(r'^file/$', CreateFileView.as_view(), name='create_file'), + url(r'^file/(?P\d+)/$', ViewFileView.as_view(), name='view_file'), + url(r'^file/(?P\d+)/$', DeleteFileView.as_view(), name='delete_file'), + url(r'^inbox/$', ViewInboxView.as_view(), name='view_inbox'), + url(r'^outbox/$', ViewOutboxView.as_view(), name='view_outbox'), + url(r'^history/(?P\d+)/$', ViewHistoryView.as_view(), name='view_history'), + url(r'^file/(?P\d+)/$', ForwardFileView.as_view(), name='forward_file'), + url(r'^designations/(?P\w+)/$', GetDesignationsView.as_view(), name='get_designations'), +] diff --git a/FusionIIIT/applications/filetracking/api/views.py b/FusionIIIT/applications/filetracking/api/views.py new file mode 100644 index 000000000..c4bb01189 --- /dev/null +++ b/FusionIIIT/applications/filetracking/api/views.py @@ -0,0 +1,111 @@ +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status, permissions +from rest_framework.authentication import TokenAuthentication +from ..models import File +from ..sdk.methods import create_file, view_file, delete_file, view_inbox, view_outbox, view_history, forward_file, get_designations + +class CreateFileView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [permissions.IsAuthenticated] + + def post(self, request): + try: + current_user = request.user.username + current_designation = request.data.get('designation') + receiver_username = request.data.get('receiver_username') + receiver_designation = request.data.get('receiver_designation') + subject = request.data.get('subject') + description = request.data.get('description') + + if None in [current_designation, receiver_username, receiver_designation, subject, description]: + return Response({'error': 'One or more required fields are missing.'}, status=status.HTTP_400_BAD_REQUEST) + + file_id = create_file(uploader=current_user, uploader_designation=current_designation, + receiver=receiver_username, receiver_designation=receiver_designation, subject=subject, description=description) + + return Response({'file_id': file_id}, status=status.HTTP_201_CREATED) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class ViewFileView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [permissions.IsAuthenticated] + + def get(self, request, file_id): + try: + file_details = view_file(int(file_id)) + return Response(file_details, status=status.HTTP_200_OK) + except ValueError: + return Response({'error': 'Invalid file ID format.'}, status=status.HTTP_400_BAD_REQUEST) + except File.DoesNotExist: + return Response({'error': 'File not found.'}, status=status.HTTP_404_NOT_FOUND) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class DeleteFileView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def delete(self, request, file_id, *args, **kwargs): + success = delete_file(int(file_id)) + if success: + return Response({'message': 'File deleted successfully'}, + status=status.HTTP_204_NO_CONTENT) + else: + return Response({'error': 'File not found'}, + status=status.HTTP_404_NOT_FOUND) + + +class ViewInboxView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + inbox_files = view_inbox( + request.user.username, + request.query_params.get('designation'), + request.query_params.get('src_module')) + return Response(inbox_files) + + +class ViewOutboxView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + outbox_files = view_outbox( + request.user.username, + request.query_params.get('designation'), + request.query_params.get('src_module')) + return Response(outbox_files) + + +class ViewHistoryView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, file_id, *args, **kwargs): + history = view_history(int(file_id)) + return Response(history) + + +class ForwardFileView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def post(self, request, file_id, *args, **kwargs): + new_tracking_id = forward_file(int(file_id), **request.data) + return Response({'tracking_id': new_tracking_id}, + status=status.HTTP_201_CREATED) + + +class GetDesignationsView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, username, *args, **kwargs): + user_designations = get_designations(username) + return Response({'designations': user_designations}) diff --git a/FusionIIIT/applications/filetracking/decorators.py b/FusionIIIT/applications/filetracking/decorators.py new file mode 100644 index 000000000..05cc7cc51 --- /dev/null +++ b/FusionIIIT/applications/filetracking/decorators.py @@ -0,0 +1,38 @@ +from django.shortcuts import render, get_object_or_404 +from django.contrib.auth.models import User +from applications.globals.models import ExtraInfo, HoldsDesignation + + +def user_check(request): + """ + This function is used to check if the user is a student or not. + Its return type is bool. + @param: + request - contains metadata about the requested page + + @Variables: + current_user - get user from request + user_details - extract details of the user from the database + desig_id - check for designation + student - designation for a student + final_user - final designation of the request(our user) + """ + try: + current_user = get_object_or_404(User, username=request.user.username) + user_details = ExtraInfo.objects.select_related('user','department').get(user=request.user) + des = HoldsDesignation.objects.all().select_related().filter(user=request.user).first() + if str(des.designation) == "student": + return True + else: + return False + except Exception as e: + return False + +def user_is_student(view_func): + def _wrapped_view(request, *args, **kwargs): + if user_check(request): + return render(request, 'filetracking/fileTrackingNotAllowed.html') + else: + return view_func(request, *args, **kwargs) + return _wrapped_view + diff --git a/FusionIIIT/applications/filetracking/filetracking/admin.py b/FusionIIIT/applications/filetracking/filetracking/admin.py new file mode 100644 index 000000000..82b78df95 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +# Register your models here. +from applications.filetracking.models import File, Tracking + +admin.site.register(File) +admin.site.register(Tracking) diff --git a/FusionIIIT/applications/filetracking/filetracking/api/serializers.py b/FusionIIIT/applications/filetracking/filetracking/api/serializers.py new file mode 100644 index 000000000..bdae2024e --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/api/serializers.py @@ -0,0 +1,24 @@ +from applications.filetracking.models import File, Tracking +from django.core.files import File as DjangoFile +from rest_framework import serializers + + +class FileSerializer(serializers.ModelSerializer): + class Meta: + model = File + fields = '__all__' + + +class TrackingSerializer(serializers.ModelSerializer): + class Meta: + model = Tracking + fields = '__all__' + + +class FileHeaderSerializer(serializers.ModelSerializer): + ''' + This serializes everything except the attachments of a file and whether it is read or not + ''' + class Meta: + model = File + exclude = ['upload_file', 'is_read'] diff --git a/FusionIIIT/applications/filetracking/filetracking/api/urls.py b/FusionIIIT/applications/filetracking/filetracking/api/urls.py new file mode 100644 index 000000000..90f03b2ef --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/api/urls.py @@ -0,0 +1,22 @@ +from django.conf.urls import url +from .views import ( + CreateFileView, + ViewFileView, + DeleteFileView, + ViewInboxView, + ViewOutboxView, + ViewHistoryView, + ForwardFileView, + GetDesignationsView, +) + +urlpatterns = [ + url(r'^file/$', CreateFileView.as_view(), name='create_file'), + url(r'^file/(?P\d+)/$', ViewFileView.as_view(), name='view_file'), + url(r'^file/(?P\d+)/$', DeleteFileView.as_view(), name='delete_file'), + url(r'^inbox/$', ViewInboxView.as_view(), name='view_inbox'), + url(r'^outbox/$', ViewOutboxView.as_view(), name='view_outbox'), + url(r'^history/(?P\d+)/$', ViewHistoryView.as_view(), name='view_history'), + url(r'^file/(?P\d+)/$', ForwardFileView.as_view(), name='forward_file'), + url(r'^designations/(?P\w+)/$', GetDesignationsView.as_view(), name='get_designations'), +] diff --git a/FusionIIIT/applications/filetracking/filetracking/api/views.py b/FusionIIIT/applications/filetracking/filetracking/api/views.py new file mode 100644 index 000000000..c4bb01189 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/api/views.py @@ -0,0 +1,111 @@ +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status, permissions +from rest_framework.authentication import TokenAuthentication +from ..models import File +from ..sdk.methods import create_file, view_file, delete_file, view_inbox, view_outbox, view_history, forward_file, get_designations + +class CreateFileView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [permissions.IsAuthenticated] + + def post(self, request): + try: + current_user = request.user.username + current_designation = request.data.get('designation') + receiver_username = request.data.get('receiver_username') + receiver_designation = request.data.get('receiver_designation') + subject = request.data.get('subject') + description = request.data.get('description') + + if None in [current_designation, receiver_username, receiver_designation, subject, description]: + return Response({'error': 'One or more required fields are missing.'}, status=status.HTTP_400_BAD_REQUEST) + + file_id = create_file(uploader=current_user, uploader_designation=current_designation, + receiver=receiver_username, receiver_designation=receiver_designation, subject=subject, description=description) + + return Response({'file_id': file_id}, status=status.HTTP_201_CREATED) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class ViewFileView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [permissions.IsAuthenticated] + + def get(self, request, file_id): + try: + file_details = view_file(int(file_id)) + return Response(file_details, status=status.HTTP_200_OK) + except ValueError: + return Response({'error': 'Invalid file ID format.'}, status=status.HTTP_400_BAD_REQUEST) + except File.DoesNotExist: + return Response({'error': 'File not found.'}, status=status.HTTP_404_NOT_FOUND) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + +class DeleteFileView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def delete(self, request, file_id, *args, **kwargs): + success = delete_file(int(file_id)) + if success: + return Response({'message': 'File deleted successfully'}, + status=status.HTTP_204_NO_CONTENT) + else: + return Response({'error': 'File not found'}, + status=status.HTTP_404_NOT_FOUND) + + +class ViewInboxView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + inbox_files = view_inbox( + request.user.username, + request.query_params.get('designation'), + request.query_params.get('src_module')) + return Response(inbox_files) + + +class ViewOutboxView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, *args, **kwargs): + outbox_files = view_outbox( + request.user.username, + request.query_params.get('designation'), + request.query_params.get('src_module')) + return Response(outbox_files) + + +class ViewHistoryView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, file_id, *args, **kwargs): + history = view_history(int(file_id)) + return Response(history) + + +class ForwardFileView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def post(self, request, file_id, *args, **kwargs): + new_tracking_id = forward_file(int(file_id), **request.data) + return Response({'tracking_id': new_tracking_id}, + status=status.HTTP_201_CREATED) + + +class GetDesignationsView(APIView): + #authentication_classes = [TokenAuthentication] + #permission_classes = [permissions.IsAuthenticated] + + def get(self, request, username, *args, **kwargs): + user_designations = get_designations(username) + return Response({'designations': user_designations}) diff --git a/FusionIIIT/applications/filetracking/filetracking/apps.py b/FusionIIIT/applications/filetracking/filetracking/apps.py new file mode 100644 index 000000000..7e3d3b6d2 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class FileTrackingConfig(AppConfig): + name = 'applications.filetracking' diff --git a/FusionIIIT/applications/filetracking/filetracking/decorators.py b/FusionIIIT/applications/filetracking/filetracking/decorators.py new file mode 100644 index 000000000..05cc7cc51 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/decorators.py @@ -0,0 +1,38 @@ +from django.shortcuts import render, get_object_or_404 +from django.contrib.auth.models import User +from applications.globals.models import ExtraInfo, HoldsDesignation + + +def user_check(request): + """ + This function is used to check if the user is a student or not. + Its return type is bool. + @param: + request - contains metadata about the requested page + + @Variables: + current_user - get user from request + user_details - extract details of the user from the database + desig_id - check for designation + student - designation for a student + final_user - final designation of the request(our user) + """ + try: + current_user = get_object_or_404(User, username=request.user.username) + user_details = ExtraInfo.objects.select_related('user','department').get(user=request.user) + des = HoldsDesignation.objects.all().select_related().filter(user=request.user).first() + if str(des.designation) == "student": + return True + else: + return False + except Exception as e: + return False + +def user_is_student(view_func): + def _wrapped_view(request, *args, **kwargs): + if user_check(request): + return render(request, 'filetracking/fileTrackingNotAllowed.html') + else: + return view_func(request, *args, **kwargs) + return _wrapped_view + diff --git a/FusionIIIT/applications/filetracking/filetracking/migrations/0001_initial.py b/FusionIIIT/applications/filetracking/filetracking/migrations/0001_initial.py new file mode 100644 index 000000000..6924ae1ff --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/migrations/0001_initial.py @@ -0,0 +1,53 @@ +# Generated by Django 3.1.5 on 2023-03-15 18:53 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('globals', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='File', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('subject', models.CharField(blank=True, max_length=100, null=True)), + ('description', models.CharField(blank=True, max_length=400, null=True)), + ('upload_date', models.DateTimeField(auto_now_add=True)), + ('upload_file', models.FileField(blank=True, upload_to='')), + ('is_read', models.BooleanField(default=False)), + ('designation', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='upload_designation', to='globals.designation')), + ('uploader', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='uploaded_files', to='globals.extrainfo')), + ], + options={ + 'db_table': 'File', + }, + ), + migrations.CreateModel( + name='Tracking', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('receive_date', models.DateTimeField(auto_now_add=True)), + ('forward_date', models.DateTimeField(auto_now_add=True)), + ('remarks', models.CharField(blank=True, max_length=250, null=True)), + ('upload_file', models.FileField(blank=True, upload_to='')), + ('is_read', models.BooleanField(default=False)), + ('current_design', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='globals.holdsdesignation')), + ('current_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='globals.extrainfo')), + ('file_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='filetracking.file')), + ('receive_design', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rec_design', to='globals.designation')), + ('receiver_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='receiver_id', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'Tracking', + }, + ), + ] diff --git a/FusionIIIT/applications/filetracking/filetracking/migrations/__init__.py b/FusionIIIT/applications/filetracking/filetracking/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/FusionIIIT/applications/filetracking/filetracking/models.py b/FusionIIIT/applications/filetracking/filetracking/models.py new file mode 100644 index 000000000..9d78b24c9 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/models.py @@ -0,0 +1,51 @@ +from django.db import models +from django.contrib.auth.models import User +from applications.globals.models import ExtraInfo, HoldsDesignation, Designation + + +class File(models.Model): + """ + This is file table which contains the all the files created by user + """ + uploader = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE, related_name='uploaded_files') + designation = models.ForeignKey(Designation, on_delete=models.CASCADE, null=True, related_name='upload_designation') + subject = models.CharField(max_length=100, null=True, blank=True) + description = models.CharField(max_length=400, null=True, blank=True) + upload_date = models.DateTimeField(auto_now_add=True) + upload_file = models.FileField(blank=True) + is_read = models.BooleanField(default = False) + + + # additions for API + src_module = models.CharField(max_length=100, default='filetracking') + src_object_id = models.CharField(max_length=100,null=True) + file_extra_JSON = models.JSONField(null=True) + + class Meta: + db_table = 'File' + + #def __str__(self): + #return str(self.ref_id) + + +class Tracking(models.Model): + """ + This is File Tracing Table which contains the status of each individual file created by the user + """ + file_id = models.ForeignKey(File, on_delete=models.CASCADE, null=True) + current_id = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE) + current_design = models.ForeignKey(HoldsDesignation, null=True, on_delete=models.CASCADE) + receiver_id = models.ForeignKey(User,null = True, on_delete=models.CASCADE, related_name='receiver_id') + receive_design = models.ForeignKey(Designation, null=True, on_delete=models.CASCADE, related_name='rec_design') + + receive_date = models.DateTimeField(auto_now_add=True) + forward_date = models.DateTimeField(auto_now_add=True) + remarks = models.CharField(max_length=250, null=True, blank=True) + upload_file = models.FileField(blank=True) + is_read = models.BooleanField(default = False) + + # additions for API + tracking_extra_JSON = models.JSONField(null=True) + + class Meta: + db_table = 'Tracking' diff --git a/FusionIIIT/applications/filetracking/filetracking/sdk/methods.py b/FusionIIIT/applications/filetracking/filetracking/sdk/methods.py new file mode 100644 index 000000000..c6f9ebc53 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/sdk/methods.py @@ -0,0 +1,423 @@ +from django.contrib.auth.models import User +from applications.filetracking.models import Tracking, File +from applications.globals.models import Designation, HoldsDesignation, ExtraInfo +from applications.filetracking.api.serializers import FileSerializer, FileHeaderSerializer, TrackingSerializer +from django.core.exceptions import ValidationError +from typing import Any + + +def create_file( + uploader: str, + uploader_designation: str, + receiver: str, + receiver_designation: str, + subject: str = "", + description: str = "", + src_module: str = "filetracking", + src_object_id: str = "", + file_extra_JSON: dict = {}, + attached_file: Any = None) -> int: + ''' + This function is used to create a file object corresponding to any object of a module that needs to be tracked + ''' + + ''' + Functioning: + create base file with params + create tracking with params + if both complete then return id of file + else raise error + + also, delete file object if tracking isnt created + ''' + uploader_user_obj = get_user_object_from_username(uploader) + uploader_extrainfo_obj = get_ExtraInfo_object_from_username(uploader) + uploader_designation_obj = Designation.objects.get( + name=uploader_designation) + receiver_obj = get_user_object_from_username(receiver) + receiver_designation_obj = Designation.objects.get( + name=receiver_designation) + + new_file = File.objects.create( + uploader=uploader_extrainfo_obj, + subject=subject, + description=description, + designation=uploader_designation_obj, + src_module=src_module, + src_object_id=src_object_id, + file_extra_JSON=file_extra_JSON, + ) + + + if attached_file is not None: + new_file.upload_file.save(attached_file.name, attached_file, save=True) + + uploader_holdsdesignation_obj = HoldsDesignation.objects.get( + user=uploader_user_obj, designation=uploader_designation_obj) + + new_tracking = Tracking.objects.create( + file_id=new_file, + current_id=uploader_extrainfo_obj, + current_design=uploader_holdsdesignation_obj, + receiver_id=receiver_obj, + receive_design=receiver_designation_obj, + tracking_extra_JSON=file_extra_JSON, + remarks=f"File with id:{str(new_file.id)} created by {uploader} and sent to {receiver}" + # upload_file = None, dont add file for first tracking + ) + if new_tracking is None: + new_file.delete() + raise ValidationError('Tracking model data is incorrect') + else: + return new_file.id + + +def view_file(file_id: int) -> dict: + ''' + This function returns all the details of a given file + ''' + try: + requested_file = File.objects.get(id=file_id) + serializer = FileSerializer(requested_file) + file_details = serializer.data + return file_details + except File.DoesNotExist: + raise NotFound("File Not Found with provided ID") + + +def delete_file(file_id: int) -> bool: + ''' + This function is used to delete a file from being tracked, all the tracking history is deleted as well and returns true if the deletion was successful + ''' + try: + File.objects.filter(id=file_id).delete() + return True + except File.DoesNotExist: + return False + +# inbox and outbox could be sorted based on most recent linked tracking entry + +def view_inbox(username: str, designation: str, src_module: str) -> list: + ''' + This function is used to get all the files in the inbox of a particular user and designation + ''' + user_designation = Designation.objects.get(name=designation) + recipient_object = get_user_object_from_username(username) + received_files_tracking = Tracking.objects.select_related('file_id').filter( + receiver_id=recipient_object, + receive_design=user_designation, + file_id__src_module=src_module, + file_id__is_read=False).order_by('receive_date'); + received_files = [tracking.file_id for tracking in received_files_tracking] + + # remove duplicate file ids (from sending back and forth) + received_files_unique = uniqueList(received_files) + + received_files_serialized = list(FileHeaderSerializer( + received_files_unique, many=True).data) + + for file in received_files_serialized: + file['sent_by_user'] = get_last_file_sender(file['id']).username + file['sent_by_designation'] = get_last_file_sender_designation(file['id']).name + + return received_files_serialized + + +def view_outbox(username: str, designation: str, src_module: str) -> list: + ''' + This function is used to get all the files in the outbox of a particular user and designation + ''' + user_designation = get_designation_obj_from_name(designation=designation) + user_object = get_user_object_from_username(username) + user_HoldsDesignation_object = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + sender_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + sent_files_tracking = Tracking.objects.select_related('file_id').filter( + current_id=sender_ExtraInfo_object, + current_design=user_HoldsDesignation_object, + file_id__src_module=src_module, + file_id__is_read=False).order_by('-receive_date') + sent_files = [tracking.file_id for tracking in sent_files_tracking] + + # remove duplicate file ids (from sending back and forth) + sent_files_unique = uniqueList(sent_files) + + sent_files_serialized = FileHeaderSerializer(sent_files_unique, many=True) + return sent_files_serialized.data + + + +def view_archived(username: str, designation: str, src_module: str) -> dict: + ''' + This function is used to get all the files in the archive of a particular user and designation + Archived file mean those which the user has ever interacted with, and are now finished or archived + ''' + user_designation = Designation.objects.get(name=designation) + user_object = get_user_object_from_username(username) + received_archived_tracking = Tracking.objects.select_related('file_id').filter( + receiver_id=user_object, + receive_design=user_designation, + file_id__src_module=src_module, + file_id__is_read=True) + + user_HoldsDesignation_object = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + sender_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + sent_archived_tracking = Tracking.objects.select_related('file_id').filter( + current_id=sender_ExtraInfo_object, + current_design=user_HoldsDesignation_object, + file_id__src_module=src_module, + file_id__is_read=True) + + archived_tracking = received_archived_tracking | sent_archived_tracking + archived_files = [tracking.file_id for tracking in archived_tracking] + + # remove duplicate file ids (from sending back and forth) + archived_files_unique = uniqueList(archived_files) + + archived_files_serialized = FileHeaderSerializer(archived_files_unique, many=True) + return archived_files_serialized.data + + + +def archive_file(file_id: int) -> bool: + ''' + This function is used to archive a file and returns true if the archiving was successful + ''' + try: + File.objects.filter(id=file_id).update(is_read=True) + return True + except File.DoesNotExist: + return False + +def unarchive_file(file_id: int) -> bool: + ''' + This functions is used to unarchive a file and returns true if the unarchiving was successful + ''' + try: + File.objects.filter(id=file_id).update(is_read=False) + return True + except File.DoesNotExist: + return False + + + +def create_draft( + uploader: str, + uploader_designation: str, + src_module: str = "filetracking", + src_object_id: str = "", + file_extra_JSON: dict = {}, + attached_file: Any = None) -> int: + ''' + This function is used to create a draft file object corresponding to any object of a module that needs to be tracked + It is similar to create_file but is not sent to anyone + Later this file can be sent to someone by forward_file by using draft file_id + ''' + uploader_extrainfo_obj = get_ExtraInfo_object_from_username(uploader) + uploader_designation_obj = Designation.objects.get( + name=uploader_designation) + + new_file = File.objects.create( + uploader=uploader_extrainfo_obj, + designation=uploader_designation_obj, + src_module=src_module, + src_object_id=src_object_id, + file_extra_JSON=file_extra_JSON, + upload_file=attached_file + ) + return new_file.id + + +def view_drafts(username: str, designation: str, src_module: str) -> dict: + ''' + This function is used to get all the files in the drafts (has not been sent) of a particular user and designation + ''' + user_designation = Designation.objects.get(name=designation) + user_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + draft_files = File.objects.filter( + tracking__isnull=True, uploader=user_ExtraInfo_object, designation=user_designation, src_module=src_module) + draft_files_serialized = FileHeaderSerializer(draft_files, many=True) + return draft_files_serialized.data + + + +def forward_file( + file_id: int, + receiver: str, + receiver_designation: str, + file_extra_JSON: dict, + remarks: str = "", + file_attachment: Any = None) -> int: + ''' + This function forwards the file and inserts a new tracking history into the file tracking table + Note that only the current owner(with appropriate designation) of the file has the ability to forward files + ''' + # HoldsDesignation and ExtraInfo object are used instead + # of Designation and User object because of the legacy code being that way + + current_owner = get_current_file_owner(file_id) + current_owner_designation = get_current_file_owner_designation(file_id) + current_owner_extra_info = ExtraInfo.objects.get(user=current_owner) + current_owner_holds_designation = HoldsDesignation.objects.get( + user=current_owner, designation=current_owner_designation) + receiver_obj = User.objects.get(username=receiver) + receiver_designation_obj = Designation.objects.get( + name=receiver_designation) + tracking_data = { + 'file_id': file_id, + 'current_id': current_owner_extra_info.id, + 'current_design': current_owner_holds_designation.id, + 'receiver_id': receiver_obj.id, + 'receive_design': receiver_designation_obj.id, + 'tracking_extra_JSON': file_extra_JSON, + 'remarks': remarks, + } + if file_attachment is not None: + tracking_data['upload_file'] = file_attachment + + tracking_entry = TrackingSerializer(data=tracking_data) + if tracking_entry.is_valid(): + tracking_entry.save() + return tracking_entry.instance.id + else: + raise ValidationError('forward data is incomplete') + + +def view_history(file_id: int) -> dict: + ''' + This function is used to get the history of a particular file with the given file_id + ''' + Tracking_history = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date') + Tracking_history_serialized = TrackingSerializer( + Tracking_history, many=True) + return Tracking_history_serialized.data + + +# HELPER FUNCTIONS + +def get_current_file_owner(file_id: int) -> User: + ''' + This functions returns the current owner of the file. + The current owner is the latest recipient of the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_recipient = latest_tracking.receiver_id + return latest_recipient + + +def get_current_file_owner_designation(file_id: int) -> Designation: + ''' + This function returns the designation of the current owner of the file. + The current owner is the latest recipient of the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_recipient_designation = latest_tracking.receive_design + return latest_recipient_designation + +def get_last_file_sender(file_id: int) -> User: + ''' + This Function returns the last file sender, + one who has last forwarded/sent the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_sender_extra_info = latest_tracking.current_id + return latest_sender_extra_info.user + +def get_last_file_sender_designation(file_id: int) -> Designation: + ''' + This Function returns the last file sender's Designation, + one who has last forwarded/sent the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('receive_date').first() + latest_sender_holds_designation = latest_tracking.current_design + return latest_sender_holds_designation.designation + +def get_designations(username: str) -> list: + ''' + This function is used to return a list of all the designation names of a particular user + ''' + user = User.objects.get(username=username) + designations_held = HoldsDesignation.objects.filter(user=user) + designation_name = [hold_designation.designation.name for hold_designation in designations_held] + return designation_name + + +def get_user_object_from_username(username: str) -> User: + user = User.objects.get(username=username) + return user + +def get_ExtraInfo_object_from_username(username: str) -> ExtraInfo: + user = User.objects.get(username=username) + extrainfo = ExtraInfo.objects.get(user=user) + return extrainfo + +def uniqueList(l: list) -> list: + ''' + This function is used to return a list with unique elements + O(n) time and space + ''' + seen = set() + unique_list = [] + for item in l: + if item not in seen: + unique_list.append(item) + seen.add(item) + return unique_list + +def add_uploader_department_to_files_list(files: list) -> list: + ''' + This function is used to add the department of the uploader to the file + ''' + for file in files: + uploader_Extrainfo = file['uploader'] + file['uploader_department'] = (str(uploader_Extrainfo.department)).split(': ')[1] + + return files + +def get_designation_obj_from_name(designation: str) -> Designation: + des = Designation.objects.get(name = designation) + return des + +def get_HoldsDesignation_obj(username: str, designation:str) -> HoldsDesignation: + user_object = get_user_object_from_username(username=username) + user_designation = get_designation_obj_from_name(designation=designation) + obj = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + return obj + +def get_last_recv_tracking_for_user(file_id: int, username: str, designation: str)-> Tracking: + ''' + This returns the last tracking where username+designation recieved file_id + ''' + + recv_user_obj = get_user_object_from_username(username) + recv_design_obj = get_designation_obj_from_name(designation) + + last_tracking = Tracking.objects.filter(file_id=file_id, + receiver_id=recv_user_obj, + receive_design=recv_design_obj).order_by('-receive_date')[0] + return last_tracking + +def get_last_forw_tracking_for_user(file_id: int, username: str, designation: str) -> Tracking: + ''' + Returns the last tracking where the specified user forwarded the file. + ''' + + # Get user and designation objects + sender_user_obj = get_ExtraInfo_object_from_username(username) + sender_designation_obj = get_HoldsDesignation_obj(username=username, designation=designation) + + # Filter Tracking objects by file_id, sender_id, and sender_designation + last_tracking = Tracking.objects.filter(file_id=file_id, + current_id=sender_user_obj, + current_design=sender_designation_obj).order_by('-forward_date').first() + return last_tracking + +def get_extra_info_object_from_id(id: int): + return ExtraInfo.objects.get(id=id) diff --git a/FusionIIIT/applications/filetracking/filetracking/tests.py b/FusionIIIT/applications/filetracking/filetracking/tests.py new file mode 100644 index 000000000..a79ca8be5 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/tests.py @@ -0,0 +1,3 @@ +# from django.test import TestCase + +# Create your tests here. diff --git a/FusionIIIT/applications/filetracking/filetracking/urls.py b/FusionIIIT/applications/filetracking/filetracking/urls.py new file mode 100644 index 000000000..9236b8c36 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/urls.py @@ -0,0 +1,43 @@ +from django.conf.urls import url, include + +from . import views +from .api import urls + +app_name = 'filetracking' + +urlpatterns = [ + + url(r'^$', views.filetracking, name='filetracking'), + url(r'^draftdesign/$', views.draft_design, name='draft_design'), + url(r'^drafts/(?P\d+)$', views.drafts_view, name='drafts_view'), + url(r'^outbox/(?P\d+)$', views.outbox_view, name='outbox_view'), + url(r'^inbox/(?P\d+)$', views.inbox_view, name='inbox_view'), + url(r'^outward/$', views.outward, name='outward'), + url(r'^inward/$', views.inward, name='inward'), + url(r'^confirmdelete/(?P\d+)$', + views.confirmdelete, name='confirm_delete'), + url(r'^archive/(?P\d+)/$', views.archive_view, name='archive_view'), + url(r'^finish/(?P\d+)/$', views.archive_file, name='finish_file'), + url(r'^viewfile/(?P\d+)/$', views.view_file, name='view_file_view'), + url(r'^forward/(?P\d+)/$', views.forward, name='forward'), + url(r'^ajax/$', views.AjaxDropdown1, name='ajax_dropdown1'), + url(r'^ajax_dropdown/$', views.AjaxDropdown, name='ajax_dropdown'), + url(r'^test/$', views.test, name='test'), + url(r'^delete/(?P\d+)$', views.delete, name='delete'), + url(r'^forward_inward/(?P\d+)/$', + views.forward_inward, name='forward_inward'), + + # correction team 24 + url(r'^finish_design/$', views.finish_design, name='finish_design'), + url(r'^finish_fileview/(?P\d+)$', + views.finish_fileview, + name='finish_fileview'), + url(r'^archive_design/$', views.archive_design, name='archive_design'), + url(r'^archive_finish/(?P\d+)/$', + views.archive_finish, name='archive_finish'), + url(r'^getdesignations/(?P\w+)/$', views.get_designations_view, name="get_user_designations"), + + # REST api urls + url(r'^api/', include(urls)) + +] diff --git a/FusionIIIT/applications/filetracking/filetracking/utils.py b/FusionIIIT/applications/filetracking/filetracking/utils.py new file mode 100644 index 000000000..5ebd27374 --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/utils.py @@ -0,0 +1,7 @@ +from .models import File, Tracking +from applications.globals.models import ExtraInfo, HoldsDesignation, Designation +from django.contrib.auth.models import User + +def get_designation(userid): + user_designation=HoldsDesignation.objects.select_related('user','working','designation').filter(user=userid) + return user_designation \ No newline at end of file diff --git a/FusionIIIT/applications/filetracking/filetracking/views.py b/FusionIIIT/applications/filetracking/filetracking/views.py new file mode 100644 index 000000000..b6d9e3bff --- /dev/null +++ b/FusionIIIT/applications/filetracking/filetracking/views.py @@ -0,0 +1,732 @@ +from django.contrib import messages +from django.shortcuts import render, get_object_or_404, redirect +from .models import File, Tracking +from applications.globals.models import ExtraInfo, HoldsDesignation, Designation +from django.template.defaulttags import csrf_token +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse +from django.contrib.auth.decorators import login_required +from django.db import IntegrityError +from django.core import serializers +from django.contrib.auth.models import User +from django.http import JsonResponse +from timeit import default_timer as time +from notification.views import office_module_notif, file_tracking_notif +from .utils import * +from django.utils.dateparse import parse_datetime +from .sdk.methods import * +from .decorators import * + +@login_required(login_url="/accounts/login/") +@user_is_student +def filetracking(request): + """ + The function is used to create files by current user(employee). + It adds the employee(uploader) and file datails to a file(table) of filetracking(model) + if he intends to create file. + + @param: + request - trivial. + + @variables: + + + uploader - Employee who creates file. + subject - Title of the file. + description - Description of the file. + upload_file - Attachment uploaded while creating file. + file - The file object. + extrainfo - The Extrainfo object. + holdsdesignations - The HoldsDesignation object. + context - Holds data needed to make necessary changes in the template. + """ + if request.method == "POST": + try: + if 'save' in request.POST: + uploader = request.user.extrainfo + subject = request.POST.get('title') + description = request.POST.get('desc') + design = request.POST.get('design') + designation = Designation.objects.get(id=HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=design).designation_id) + upload_file = request.FILES.get('myfile') + if upload_file and upload_file.size / 1000 > 10240: + messages.error( + request, "File should not be greater than 10MB") + return redirect("/filetracking") + + File.objects.create( + uploader=uploader, + description=description, + subject=subject, + designation=designation, + upload_file=upload_file + ) + + messages.success(request, 'File Draft Saved Successfully') + + if 'send' in request.POST: + uploader = request.user.extrainfo + subject = request.POST.get('title') + description = request.POST.get('desc') + design = request.POST.get('design') + designation = Designation.objects.get(id=HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=design).designation_id) + + upload_file = request.FILES.get('myfile') + if upload_file and upload_file.size / 1000 > 10240: + messages.error( + request, "File should not be greater than 10MB") + return redirect("/filetracking") + + file = File.objects.create( + uploader=uploader, + description=description, + subject=subject, + designation=designation, + upload_file=upload_file + ) + + current_id = request.user.extrainfo + remarks = request.POST.get('remarks') + + sender = request.POST.get('design') + current_design = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=sender) + + receiver = request.POST.get('receiver') + try: + receiver_id = User.objects.get(username=receiver) + except Exception as e: + messages.error(request, 'Enter a valid Username') + return redirect('/filetracking/') + receive = request.POST.get('recieve') + try: + receive_design = Designation.objects.get(name=receive) + except Exception as e: + messages.error(request, 'Enter a valid Designation') + return redirect('/filetracking/') + + upload_file = request.FILES.get('myfile') + + Tracking.objects.create( + file_id=file, + current_id=current_id, + current_design=current_design, + receive_design=receive_design, + receiver_id=receiver_id, + remarks=remarks, + upload_file=upload_file, + ) + # office_module_notif(request.user, receiver_id) + file_tracking_notif(request.user, receiver_id, subject) + messages.success(request, 'File sent successfully') + + except IntegrityError: + message = "FileID Already Taken.!!" + return HttpResponse(message) + + file = File.objects.select_related( + 'uploader__user', 'uploader__department', 'designation').all() + extrainfo = ExtraInfo.objects.select_related('user', 'department').all() + holdsdesignations = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').all() + designations = get_designation(request.user) + + context = { + 'file': file, + 'extrainfo': extrainfo, + 'holdsdesignations': holdsdesignations, + 'designations': designations, + } + return render(request, 'filetracking/composefile.html', context) + + +@login_required(login_url="/accounts/login") +def draft_design(request): + """ + The function is used to get the designation of the user and renders it on draft template. + + @param: + request - trivial. + + @variables: + + + context - Holds data needed to make necessary changes in the template. + """ + designation = get_designation(request.user) + context = { + 'designation': designation, + } + return render(request, 'filetracking/draft_design.html', context) + + +@login_required(login_url="/accounts/login") +def drafts_view(request, id): + """ + This function is used to view all the drafts created by the user ordered by upload date.it collects all the created files from File object. + + @param: + request - trivial + id - user id + + @parameters + draft - file obeject containing all the files created by user + context - holds data needed to render the template + + + + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + draft_files = view_drafts( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # Correct upload_date type + for f in draft_files: + f['upload_date'] = parse_datetime(f['upload_date']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + draft_files = add_uploader_department_to_files_list(draft_files) + + context = { + 'draft_files': draft_files, + 'designations': designation, + } + return render(request, 'filetracking/drafts.html', context) + + +@login_required(login_url="/accounts/login") +def outbox_view(request, id): + """ + The function is used to get all the files sent by user(employee) to other employees + which are filtered from Tracking(table) objects by current user i.e. current_id. + It displays files sent by user to other employees of a Tracking(table) of filetracking(model) + in the 'Outbox' tab of template. + + @param: + request - trivial. + id - user id + + @variables: + outward_files - File objects filtered by current_id i.e, present working user. + context - Holds data needed to make necessary changes in the template. + + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + + outward_files = view_outbox(username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking') + + for f in outward_files: + last_forw_tracking = get_last_forw_tracking_for_user(file_id=f['id'], + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation) + f['sent_to_user'] = last_forw_tracking.receiver_id + f['sent_to_design'] = last_forw_tracking.receive_design + f['last_sent_date'] = last_forw_tracking.forward_date + + f['upload_date'] = parse_datetime(f['upload_date']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + outward_files = add_uploader_department_to_files_list(outward_files) + + context = { + + 'out_files': outward_files, + 'viewer_designation': designation, + } + return render(request, 'filetracking/outbox.html', context) + + +@login_required(login_url="/accounts/login") +def inbox_view(request, id): + """ + The function is used to fetch the files received by the user form other employees. + These files are filtered by receiver id and ordered by receive date. + + @param: + request - trivial. + id - HoldsDesignation object id + + @variables: + inward_files - File object with additional sent by information + context - Holds data needed to make necessary changes in the template. + + """ + + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + inward_files = view_inbox( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # correct upload_date type and add recieve_date + for f in inward_files: + f['upload_date'] = parse_datetime(f['upload_date']) + + last_recv_tracking = get_last_recv_tracking_for_user(file_id=f['id'], + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation) + f['receive_date'] = last_recv_tracking.receive_date + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + inward_files = add_uploader_department_to_files_list(inward_files) + + + context = { + + 'in_file': inward_files, + 'designations': designation, + } + return render(request, 'filetracking/inbox.html', context) + + +@login_required(login_url="/accounts/login") +def outward(request): + """ + This function fetches the different designations of the user and renders it on outward template + @param: + request - trivial. + + @variables: + context - Holds the different designation data of the user + + """ + designation = get_designation(request.user) + + context = { + 'designation': designation, + } + return render(request, 'filetracking/outward.html', context) + + +@login_required(login_url="/accounts/login") +def inward(request): + """ + This function fetches the different designations of the user and renders it on inward template + + + @param: + request - trivial. + + @variables: + context - Holds the different designation data of the user + """ + designation = get_designation(request.user) + context = { + + 'designation': designation, + } + return render(request, 'filetracking/inward.html', context) + + +@login_required(login_url = "/accounts/login") +def confirmdelete(request,id): + """ + The function is used to confirm the deletion of a file. + @param: + request - trivial. + id - user id + + @variables: + context - Holds data needed to make necessary changes in the template. + """ + file = File.objects.select_related( + 'uploader__user', 'uploader__department', 'designation').get(pk=id) + + context = { + 'j': file, + } + + return render(request, 'filetracking/confirmdelete.html', context) + +@login_required(login_url="/accounts/login") +def view_file(request, id): + ''' + This function is used to view a particular file received by an employee from another. + This function also conditionally renders two forms 'forward_file' and 'archive_file' + based on if the user has necessary permissions or not. + The business permissions are as follows: + 1. User can forward file only if they are the last recipient of the file + 2. User can archive a file only if they have received it last and they are also the original owner of the file + + To forward the file and to archive the file separate views with POST request are called + + It displays the details file of a File and remarks as well as the attachments of all the users + who have been involved till that point of the workflow. + + @param: + request - Trivial. + id - ID of the file object which the user intends to forward to another employee. + + @variables: + file - The File object. + track - The Tracking object. + designation - the designations of the user + ''' + + file = get_object_or_404(File, id=id) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file).order_by('receive_date') + designations = get_designation(request.user) + + forward_enable = False + archive_enable = False + + current_owner = get_current_file_owner(file.id) + file_uploader = get_user_object_from_username(file.uploader.user.username) + + + if current_owner == request.user and file.is_read is False: + forward_enable = True + if current_owner == request.user and file_uploader == request.user and file.is_read is False: + archive_enable = True + + context = { + 'designations': designations, + 'file': file, + 'track': track, + 'forward_enable': forward_enable, + 'archive_enable': archive_enable, + } + return render(request, 'filetracking/viewfile.html', context) + +@login_required(login_url="/accounts/login") +def archive_file(request, id): + '''This function is used to archive a file. + It returns unauthorized access if the user is not file uploader + and the current owner of the file + ''' + if request.method == "POST": + file = get_object_or_404(File, id=id); + current_owner = get_current_file_owner(file.id) + file_uploader = get_user_object_from_username(file.uploader.user.username) + if current_owner == request.user and file_uploader == request.user: + file.is_read = True + file.save() + messages.success(request, 'File Archived') + else: + messages.error(request, 'Unauthorized access') + + return render(request, 'filetracking/composefile.html') + +@login_required(login_url="/accounts/login") +def forward(request, id): + """ + The function is used to forward files received by user(employee) from other + employees which are filtered from Tracking(table) objects by current user + i.e. receiver_id to other employees. + It also gets track of file created by uploader through all users involved in file + along with their remarks and attachments + It displays details file of a File(table) and remarks and attachments of user involved + in file of Tracking(table) of filetracking(model) in the template. + + @param: + request - trivial. + id - id of the file object which the user intends to forward to other employee. + + @variables: + file - The File object. + track - The Tracking object. + remarks = Remarks posted by user. + receiver = Receiver to be selected by user for forwarding file. + receiver_id = Receiver_id who has been selected for forwarding file. + upload_file = File attached by user. + extrainfo = ExtraInfo object. + holdsdesignations = HoldsDesignation objects. + context - Holds data needed to make necessary changes in the template. + """ + + file = get_object_or_404(File, id=id) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file).order_by('receive_date') + + if request.method == "POST": + if 'finish' in request.POST: + file.is_read = True + file.save() + if 'send' in request.POST: + current_id = request.user.extrainfo + remarks = request.POST.get('remarks') + track.update(is_read=True) + + sender = request.POST.get('sender') + current_design = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=sender) + + receiver = request.POST.get('receiver') + try: + receiver_id = User.objects.get(username=receiver) + except Exception as e: + messages.error(request, 'Enter a valid destination') + designations = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + receive = request.POST.get('recieve') + try: + receive_design = Designation.objects.get(name=receive) + except Exception as e: + messages.error(request, 'Enter a valid Designation') + designations = get_designation(request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + + upload_file = request.FILES.get('myfile') + + Tracking.objects.create( + file_id=file, + current_id=current_id, + current_design=current_design, + receive_design=receive_design, + receiver_id=receiver_id, + remarks=remarks, + upload_file=upload_file, + ) + messages.success(request, 'File sent successfully') + + designations = get_designation(request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + + return render(request, 'filetracking/forward.html', context) + + +@login_required(login_url="/accounts/login") +def archive_design(request): + designation = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) + + context = { + 'designation': designation, + } + return render(request, 'filetracking/archive_design.html', context) + + +@login_required(login_url="/accounts/login") +def archive_view(request, id): + """ + The function is used to fetch the files in the user's archive + (those which have passed by user and been archived/finished) + + @param: + request - trivial. + id - HoldsDesignation object id + + @variables: + archive_files - File object with additional information + context - Holds data needed to make necessary changes in the template. + + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + + archive_files = view_archived( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # correct upload_date type and add receive_date + for f in archive_files: + f['upload_date'] = parse_datetime(f['upload_date']) + f['designation'] = Designation.objects.get(id=f['designation']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + archive_files = add_uploader_department_to_files_list(archive_files) + + context = { + 'archive_files': archive_files, + 'designations': designation, + } + return render(request, 'filetracking/archive.html', context) + + + +@login_required(login_url="/accounts/login") +def archive_finish(request, id): + # file = get_object_or_404(File, ref_id=id) + file1 = get_object_or_404(File, id=id) + track = Tracking.objects.filter(file_id=file1) + + return render(request, 'filetracking/archive_finish.html', {'file': file1, 'track': track}) + + +@login_required(login_url="/accounts/login") +def finish_design(request): + + designation = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) + + context = { + 'designation': designation, + } + return render(request, 'filetracking/finish_design.html', context) + + +@login_required(login_url="/accounts/login") +def finish_fileview(request, id): + + out = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id__uploader=request.user.extrainfo, is_read=False).order_by('-forward_date') + + abcd = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + + context = { + + 'out': out, + 'abcd': abcd, + } + return render(request, 'filetracking/finish_fileview.html', context) + + +@login_required(login_url="/accounts/login") +def finish(request, id): + # file = get_object_or_404(File, ref_id=id) + file1 = get_object_or_404(File, id=id) + track = Tracking.objects.filter(file_id=file1) + + if request.method == "POST": + if 'Finished' in request.POST: + File.objects.filter(pk=id).update(is_read=True) + track.update(is_read=True) + messages.success(request, 'File Archived') + + return render(request, 'filetracking/finish.html', {'file': file1, 'track': track, 'fileid': id}) + + +def AjaxDropdown1(request): + + """ + This function returns the designation of receiver on the forward or compose file template. + + @param: + request - trivial. + + + @variables: + context - return the httpresponce containing the matched designation of the user + """ + if request.method == 'POST': + value = request.POST.get('value') + + hold = Designation.objects.filter(name__startswith=value) + holds = serializers.serialize('json', list(hold)) + context = { + 'holds': holds + } + + return HttpResponse(JsonResponse(context), content_type='application/json') + + +def AjaxDropdown(request): + """ + This function returns the usernames of receiver on the forward or compose file template. + + @param: + request - trivial. + + + @variables: + context - return the httpresponce containing the matched username + """ + if request.method == 'POST': + value = request.POST.get('value') + users = User.objects.filter(username__startswith=value) + users = serializers.serialize('json', list(users)) + + context = { + 'users': users + } + return HttpResponse(JsonResponse(context), content_type='application/json') + + +def test(request): + return HttpResponse('success') + + + +@login_required(login_url = "/accounts/login") +def delete(request,id): + """ + The function is used the delete of a file and it returns to the drafts page. + + @param: + request - trivial. + id - id of the file that is going to be deleted + + """ + file = File.objects.get(pk=id) + file.delete() + return redirect('/filetracking/draftdesign/') + + + + +def forward_inward(request,id): + """ This function is used forward the files which are available in the inbox of the user . + + @param: + request - trivial + id - id of the file that is going to forward + + @variables: + file - file object + track - tracking object of the file + context - necessary data to render + + """ + + file = get_object_or_404(File, id=id) + file.is_read = True + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file) + designations = get_designation(request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + +def get_designations_view(request, username): + designations = get_designations(username) + print(designations) + return JsonResponse(designations, safe=False) + diff --git a/FusionIIIT/applications/filetracking/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/filetracking/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..31015f1ec --- /dev/null +++ b/FusionIIIT/applications/filetracking/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,33 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('filetracking', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='file', + name='file_extra_JSON', + field=models.JSONField(null=True), + ), + migrations.AddField( + model_name='file', + name='src_module', + field=models.CharField(default='filetracking', max_length=100), + ), + migrations.AddField( + model_name='file', + name='src_object_id', + field=models.CharField(max_length=100, null=True), + ), + migrations.AddField( + model_name='tracking', + name='tracking_extra_JSON', + field=models.JSONField(null=True), + ), + ] diff --git a/FusionIIIT/applications/filetracking/models.py b/FusionIIIT/applications/filetracking/models.py index 5f9581a08..9d78b24c9 100644 --- a/FusionIIIT/applications/filetracking/models.py +++ b/FusionIIIT/applications/filetracking/models.py @@ -16,6 +16,11 @@ class File(models.Model): is_read = models.BooleanField(default = False) + # additions for API + src_module = models.CharField(max_length=100, default='filetracking') + src_object_id = models.CharField(max_length=100,null=True) + file_extra_JSON = models.JSONField(null=True) + class Meta: db_table = 'File' @@ -25,13 +30,11 @@ class Meta: class Tracking(models.Model): """ - This is File Tracing Table which contains the status of each indivisual file created by the user + This is File Tracing Table which contains the status of each individual file created by the user """ file_id = models.ForeignKey(File, on_delete=models.CASCADE, null=True) current_id = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE) current_design = models.ForeignKey(HoldsDesignation, null=True, on_delete=models.CASCADE) - # receiver_id = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE, related_name='receiver_id') - # receive_design = models.ForeignKey(HoldsDesignation, null=True, on_delete=models.CASCADE, related_name='rec_design') receiver_id = models.ForeignKey(User,null = True, on_delete=models.CASCADE, related_name='receiver_id') receive_design = models.ForeignKey(Designation, null=True, on_delete=models.CASCADE, related_name='rec_design') @@ -41,5 +44,8 @@ class Tracking(models.Model): upload_file = models.FileField(blank=True) is_read = models.BooleanField(default = False) + # additions for API + tracking_extra_JSON = models.JSONField(null=True) + class Meta: db_table = 'Tracking' diff --git a/FusionIIIT/applications/filetracking/sdk/methods.py b/FusionIIIT/applications/filetracking/sdk/methods.py new file mode 100644 index 000000000..97b7c87a1 --- /dev/null +++ b/FusionIIIT/applications/filetracking/sdk/methods.py @@ -0,0 +1,424 @@ +from django.contrib.auth.models import User +from applications.filetracking.models import Tracking, File +from applications.globals.models import Designation, HoldsDesignation, ExtraInfo +from applications.filetracking.api.serializers import FileSerializer, FileHeaderSerializer, TrackingSerializer +from django.core.exceptions import ValidationError +from typing import Any + + +def create_file( + uploader: str, + uploader_designation: str, + receiver: str, + receiver_designation: str, + subject: str = "", + description: str = "", + src_module: str = "filetracking", + src_object_id: str = "", + file_extra_JSON: dict = {}, + attached_file: Any = None) -> int: + ''' + This function is used to create a file object corresponding to any object of a module that needs to be tracked + ''' + + ''' + Functioning: + create base file with params + create tracking with params + if both complete then return id of file + else raise error + + also, delete file object if tracking isnt created + ''' + uploader_user_obj = get_user_object_from_username(uploader) + uploader_extrainfo_obj = get_ExtraInfo_object_from_username(uploader) + uploader_designation_obj = Designation.objects.get( + name=uploader_designation) + receiver_obj = get_user_object_from_username(receiver) + receiver_designation_obj = Designation.objects.get( + name=receiver_designation) + + new_file = File.objects.create( + uploader=uploader_extrainfo_obj, + subject=subject, + description=description, + designation=uploader_designation_obj, + src_module=src_module, + src_object_id=src_object_id, + file_extra_JSON=file_extra_JSON, + ) + + + if attached_file is not None: + new_file.upload_file.save(attached_file.name, attached_file, save=True) + + uploader_holdsdesignation_obj = HoldsDesignation.objects.get( + user=uploader_user_obj, designation=uploader_designation_obj) + + new_tracking = Tracking.objects.create( + file_id=new_file, + current_id=uploader_extrainfo_obj, + current_design=uploader_holdsdesignation_obj, + receiver_id=receiver_obj, + receive_design=receiver_designation_obj, + tracking_extra_JSON=file_extra_JSON, + remarks=f"File with id:{str(new_file.id)} created by {uploader} and sent to {receiver}" + # upload_file = None, dont add file for first tracking + ) + if new_tracking is None: + new_file.delete() + raise ValidationError('Tracking model data is incorrect') + else: + return new_file.id + + +def view_file(file_id: int) -> dict: + ''' + This function returns all the details of a given file + ''' + try: + requested_file = File.objects.get(id=file_id) + serializer = FileSerializer(requested_file) + file_details = serializer.data + print(file_details) + return file_details + except File.DoesNotExist: + raise NotFound("File Not Found with provided ID") + + +def delete_file(file_id: int) -> bool: + ''' + This function is used to delete a file from being tracked, all the tracking history is deleted as well and returns true if the deletion was successful + ''' + try: + File.objects.filter(id=file_id).delete() + return True + except File.DoesNotExist: + return False + +# inbox and outbox could be sorted based on most recent linked tracking entry + +def view_inbox(username: str, designation: str, src_module: str) -> list: + ''' + This function is used to get all the files in the inbox of a particular user and designation + ''' + user_designation = Designation.objects.get(name=designation) + recipient_object = get_user_object_from_username(username) + received_files_tracking = Tracking.objects.select_related('file_id').filter( + receiver_id=recipient_object, + receive_design=user_designation, + file_id__src_module=src_module, + file_id__is_read=False).order_by('receive_date'); + received_files = [tracking.file_id for tracking in received_files_tracking] + + # remove duplicate file ids (from sending back and forth) + received_files_unique = uniqueList(received_files) + + received_files_serialized = list(FileHeaderSerializer( + received_files_unique, many=True).data) + + for file in received_files_serialized: + file['sent_by_user'] = get_last_file_sender(file['id']).username + file['sent_by_designation'] = get_last_file_sender_designation(file['id']).name + + return received_files_serialized + + +def view_outbox(username: str, designation: str, src_module: str) -> list: + ''' + This function is used to get all the files in the outbox of a particular user and designation + ''' + user_designation = get_designation_obj_from_name(designation=designation) + user_object = get_user_object_from_username(username) + user_HoldsDesignation_object = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + sender_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + sent_files_tracking = Tracking.objects.select_related('file_id').filter( + current_id=sender_ExtraInfo_object, + current_design=user_HoldsDesignation_object, + file_id__src_module=src_module, + file_id__is_read=False).order_by('-receive_date') + sent_files = [tracking.file_id for tracking in sent_files_tracking] + + # remove duplicate file ids (from sending back and forth) + sent_files_unique = uniqueList(sent_files) + + sent_files_serialized = FileHeaderSerializer(sent_files_unique, many=True) + return sent_files_serialized.data + + + +def view_archived(username: str, designation: str, src_module: str) -> dict: + ''' + This function is used to get all the files in the archive of a particular user and designation + Archived file mean those which the user has ever interacted with, and are now finished or archived + ''' + user_designation = Designation.objects.get(name=designation) + user_object = get_user_object_from_username(username) + received_archived_tracking = Tracking.objects.select_related('file_id').filter( + receiver_id=user_object, + receive_design=user_designation, + file_id__src_module=src_module, + file_id__is_read=True) + + user_HoldsDesignation_object = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + sender_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + sent_archived_tracking = Tracking.objects.select_related('file_id').filter( + current_id=sender_ExtraInfo_object, + current_design=user_HoldsDesignation_object, + file_id__src_module=src_module, + file_id__is_read=True) + + archived_tracking = received_archived_tracking | sent_archived_tracking + archived_files = [tracking.file_id for tracking in archived_tracking] + + # remove duplicate file ids (from sending back and forth) + archived_files_unique = uniqueList(archived_files) + + archived_files_serialized = FileHeaderSerializer(archived_files_unique, many=True) + return archived_files_serialized.data + + + +def archive_file(file_id: int) -> bool: + ''' + This function is used to archive a file and returns true if the archiving was successful + ''' + try: + File.objects.filter(id=file_id).update(is_read=True) + return True + except File.DoesNotExist: + return False + +def unarchive_file(file_id: int) -> bool: + ''' + This functions is used to unarchive a file and returns true if the unarchiving was successful + ''' + try: + File.objects.filter(id=file_id).update(is_read=False) + return True + except File.DoesNotExist: + return False + + + +def create_draft( + uploader: str, + uploader_designation: str, + src_module: str = "filetracking", + src_object_id: str = "", + file_extra_JSON: dict = {}, + attached_file: Any = None) -> int: + ''' + This function is used to create a draft file object corresponding to any object of a module that needs to be tracked + It is similar to create_file but is not sent to anyone + Later this file can be sent to someone by forward_file by using draft file_id + ''' + uploader_extrainfo_obj = get_ExtraInfo_object_from_username(uploader) + uploader_designation_obj = Designation.objects.get( + name=uploader_designation) + + new_file = File.objects.create( + uploader=uploader_extrainfo_obj, + designation=uploader_designation_obj, + src_module=src_module, + src_object_id=src_object_id, + file_extra_JSON=file_extra_JSON, + upload_file=attached_file + ) + return new_file.id + + +def view_drafts(username: str, designation: str, src_module: str) -> dict: + ''' + This function is used to get all the files in the drafts (has not been sent) of a particular user and designation + ''' + user_designation = Designation.objects.get(name=designation) + user_ExtraInfo_object = get_ExtraInfo_object_from_username(username) + draft_files = File.objects.filter( + tracking__isnull=True, uploader=user_ExtraInfo_object, designation=user_designation, src_module=src_module) + draft_files_serialized = FileHeaderSerializer(draft_files, many=True) + return draft_files_serialized.data + + + +def forward_file( + file_id: int, + receiver: str, + receiver_designation: str, + file_extra_JSON: dict, + remarks: str = "", + file_attachment: Any = None) -> int: + ''' + This function forwards the file and inserts a new tracking history into the file tracking table + Note that only the current owner(with appropriate designation) of the file has the ability to forward files + ''' + # HoldsDesignation and ExtraInfo object are used instead + # of Designation and User object because of the legacy code being that way + + current_owner = get_current_file_owner(file_id) + current_owner_designation = get_current_file_owner_designation(file_id) + current_owner_extra_info = ExtraInfo.objects.get(user=current_owner) + current_owner_holds_designation = HoldsDesignation.objects.get( + user=current_owner, designation=current_owner_designation) + receiver_obj = User.objects.get(username=receiver) + receiver_designation_obj = Designation.objects.get( + name=receiver_designation) + tracking_data = { + 'file_id': file_id, + 'current_id': current_owner_extra_info.id, + 'current_design': current_owner_holds_designation.id, + 'receiver_id': receiver_obj.id, + 'receive_design': receiver_designation_obj.id, + 'tracking_extra_JSON': file_extra_JSON, + 'remarks': remarks, + } + if file_attachment is not None: + tracking_data['upload_file'] = file_attachment + + tracking_entry = TrackingSerializer(data=tracking_data) + if tracking_entry.is_valid(): + tracking_entry.save() + return tracking_entry.instance.id + else: + raise ValidationError('forward data is incomplete') + + +def view_history(file_id: int) -> dict: + ''' + This function is used to get the history of a particular file with the given file_id + ''' + Tracking_history = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date') + Tracking_history_serialized = TrackingSerializer( + Tracking_history, many=True) + return Tracking_history_serialized.data + + +# HELPER FUNCTIONS + +def get_current_file_owner(file_id: int) -> User: + ''' + This functions returns the current owner of the file. + The current owner is the latest recipient of the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_recipient = latest_tracking.receiver_id + return latest_recipient + + +def get_current_file_owner_designation(file_id: int) -> Designation: + ''' + This function returns the designation of the current owner of the file. + The current owner is the latest recipient of the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_recipient_designation = latest_tracking.receive_design + return latest_recipient_designation + +def get_last_file_sender(file_id: int) -> User: + ''' + This Function returns the last file sender, + one who has last forwarded/sent the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('-receive_date').first() + latest_sender_extra_info = latest_tracking.current_id + return latest_sender_extra_info.user + +def get_last_file_sender_designation(file_id: int) -> Designation: + ''' + This Function returns the last file sender's Designation, + one who has last forwarded/sent the file + ''' + latest_tracking = Tracking.objects.filter( + file_id=file_id).order_by('receive_date').first() + latest_sender_holds_designation = latest_tracking.current_design + return latest_sender_holds_designation.designation + +def get_designations(username: str) -> list: + ''' + This function is used to return a list of all the designation names of a particular user + ''' + user = User.objects.get(username=username) + designations_held = HoldsDesignation.objects.filter(user=user) + designation_name = [hold_designation.designation.name for hold_designation in designations_held] + return designation_name + + +def get_user_object_from_username(username: str) -> User: + user = User.objects.get(username=username) + return user + +def get_ExtraInfo_object_from_username(username: str) -> ExtraInfo: + user = User.objects.get(username=username) + extrainfo = ExtraInfo.objects.get(user=user) + return extrainfo + +def uniqueList(l: list) -> list: + ''' + This function is used to return a list with unique elements + O(n) time and space + ''' + seen = set() + unique_list = [] + for item in l: + if item not in seen: + unique_list.append(item) + seen.add(item) + return unique_list + +def add_uploader_department_to_files_list(files: list) -> list: + ''' + This function is used to add the department of the uploader to the file + ''' + for file in files: + uploader_Extrainfo = file['uploader'] + file['uploader_department'] = (str(uploader_Extrainfo.department)).split(': ')[1] + + return files + +def get_designation_obj_from_name(designation: str) -> Designation: + des = Designation.objects.get(name = designation) + return des + +def get_HoldsDesignation_obj(username: str, designation:str) -> HoldsDesignation: + user_object = get_user_object_from_username(username=username) + user_designation = get_designation_obj_from_name(designation=designation) + obj = HoldsDesignation.objects.get( + user=user_object, designation=user_designation) + return obj + +def get_last_recv_tracking_for_user(file_id: int, username: str, designation: str)-> Tracking: + ''' + This returns the last tracking where username+designation recieved file_id + ''' + + recv_user_obj = get_user_object_from_username(username) + recv_design_obj = get_designation_obj_from_name(designation) + + last_tracking = Tracking.objects.filter(file_id=file_id, + receiver_id=recv_user_obj, + receive_design=recv_design_obj).order_by('-receive_date')[0] + return last_tracking + +def get_last_forw_tracking_for_user(file_id: int, username: str, designation: str) -> Tracking: + ''' + Returns the last tracking where the specified user forwarded the file. + ''' + + # Get user and designation objects + sender_user_obj = get_ExtraInfo_object_from_username(username) + sender_designation_obj = get_HoldsDesignation_obj(username=username, designation=designation) + + # Filter Tracking objects by file_id, sender_id, and sender_designation + last_tracking = Tracking.objects.filter(file_id=file_id, + current_id=sender_user_obj, + current_design=sender_designation_obj).order_by('-forward_date').first() + return last_tracking + +def get_extra_info_object_from_id(id: int): + return ExtraInfo.objects.get(id=id) diff --git a/FusionIIIT/applications/filetracking/urls.py b/FusionIIIT/applications/filetracking/urls.py index cb4a7563d..28c8deac1 100644 --- a/FusionIIIT/applications/filetracking/urls.py +++ b/FusionIIIT/applications/filetracking/urls.py @@ -1,31 +1,43 @@ -from django.conf.urls import url +from django.conf.urls import url, include from . import views +from .api import urls app_name = 'filetracking' urlpatterns = [ url(r'^$', views.filetracking, name='filetracking'), - url(r'^drafts/$', views.drafts, name='drafts'), - url(r'^fileview/(?P\d+)$', views.fileview, name='fileview'), - url(r'^fileview1/(?P\d+)$', views.fileview1, name='fileview1'), - url(r'^fileview2/(?P\d+)$', views.fileview2, name='fileview2'), + url(r'^draftdesign/$', views.draft_design, name='draft_design'), + url(r'^drafts/(?P\d+)$', views.drafts_view, name='drafts_view'), + url(r'^outbox/(?P\d+)$', views.outbox_view, name='outbox_view'), + url(r'^inbox/(?P\d+)$', views.inbox_view, name='inbox_view'), url(r'^outward/$', views.outward, name='outward'), url(r'^inward/$', views.inward, name='inward'), - url(r'^confirmdelete/(?P\d+)$', views.confirmdelete, name='confirm_delete'), - url(r'^archive/(?P\d+)/$', views.archive, name='archive'), - url(r'^finish/(?P\d+)/$', views.finish, name='finish'), + url(r'^confirmdelete/(?P\d+)$', + views.confirmdelete, name='confirm_delete'), + url(r'^archive/(?P\d+)/$', views.archive_view, name='archive_view'), + url(r'^finish/(?P\d+)/$', views.archive_file, name='finish_file'), + url(r'^viewfile/(?P\d+)/$', views.view_file, name='view_file_view'), url(r'^forward/(?P\d+)/$', views.forward, name='forward'), url(r'^ajax/$', views.AjaxDropdown1, name='ajax_dropdown1'), url(r'^ajax_dropdown/$', views.AjaxDropdown, name='ajax_dropdown'), - url(r'^test/$',views.test, name='test'), - url(r'^delete/(?P\d+)$',views.delete, name='delete'), - url(r'^forward_inward/(?P\d+)/$', views.forward_inward, name='forward_inward'), + url(r'^test/$', views.test, name='test'), + url(r'^delete/(?P\d+)$', views.delete, name='delete'), + url(r'^forward_inward/(?P\d+)/$', + views.forward_inward, name='forward_inward'), - ## correction team 24 + # correction team 24 url(r'^finish_design/$', views.finish_design, name='finish_design'), - url(r'^finish_fileview/(?P\d+)$', views.finish_fileview, name='finish_fileview'), + url(r'^finish_fileview/(?P\d+)$', + views.finish_fileview, + name='finish_fileview'), url(r'^archive_design/$', views.archive_design, name='archive_design'), - url(r'^archive_finish/(?P\d+)/$', views.archive_finish, name='archive_finish'), + url(r'^archive_finish/(?P\d+)/$', + views.archive_finish, name='archive_finish'), + url(r'^getdesignations/(?P\w+)/$', views.get_designations_view, name="get_user_designations"), + + # REST api urls + url(r'^api/', include(urls)) + ] diff --git a/FusionIIIT/applications/filetracking/views.py b/FusionIIIT/applications/filetracking/views.py index ef5d8f347..b6d9e3bff 100644 --- a/FusionIIIT/applications/filetracking/views.py +++ b/FusionIIIT/applications/filetracking/views.py @@ -8,12 +8,16 @@ from django.db import IntegrityError from django.core import serializers from django.contrib.auth.models import User +from django.http import JsonResponse from timeit import default_timer as time -from notification.views import office_module_notif,file_tracking_notif +from notification.views import office_module_notif, file_tracking_notif from .utils import * +from django.utils.dateparse import parse_datetime +from .sdk.methods import * +from .decorators import * - -@login_required(login_url = "/accounts/login/") +@login_required(login_url="/accounts/login/") +@user_is_student def filetracking(request): """ The function is used to create files by current user(employee). @@ -35,18 +39,20 @@ def filetracking(request): holdsdesignations - The HoldsDesignation object. context - Holds data needed to make necessary changes in the template. """ - if request.method =="POST": + if request.method == "POST": try: if 'save' in request.POST: uploader = request.user.extrainfo subject = request.POST.get('title') description = request.POST.get('desc') design = request.POST.get('design') - designation = Designation.objects.get(id = HoldsDesignation.objects.select_related('user','working','designation').get(id = design).designation_id) + designation = Designation.objects.get(id=HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=design).designation_id) upload_file = request.FILES.get('myfile') - if(upload_file.size / 1000 > 10240): - messages.error(request,"File should not be greater than 10MB") - return redirect("/filetracking") + if upload_file and upload_file.size / 1000 > 10240: + messages.error( + request, "File should not be greater than 10MB") + return redirect("/filetracking") File.objects.create( uploader=uploader, @@ -56,18 +62,20 @@ def filetracking(request): upload_file=upload_file ) - messages.success(request,'File Draft Saved Successfully') + messages.success(request, 'File Draft Saved Successfully') if 'send' in request.POST: uploader = request.user.extrainfo subject = request.POST.get('title') description = request.POST.get('desc') design = request.POST.get('design') - designation = Designation.objects.get(id = HoldsDesignation.objects.select_related('user','working','designation').get(id = design).designation_id) + designation = Designation.objects.get(id=HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=design).designation_id) upload_file = request.FILES.get('myfile') - if(upload_file.size / 1000 > 10240): - messages.error(request,"File should not be greater than 10MB") + if upload_file and upload_file.size / 1000 > 10240: + messages.error( + request, "File should not be greater than 10MB") return redirect("/filetracking") file = File.objects.create( @@ -78,12 +86,12 @@ def filetracking(request): upload_file=upload_file ) - current_id = request.user.extrainfo remarks = request.POST.get('remarks') sender = request.POST.get('design') - current_design = HoldsDesignation.objects.select_related('user','working','designation').get(id=sender) + current_design = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=sender) receiver = request.POST.get('receiver') try: @@ -109,19 +117,19 @@ def filetracking(request): remarks=remarks, upload_file=upload_file, ) - #office_module_notif(request.user, receiver_id) - file_tracking_notif(request.user,receiver_id,subject) - messages.success(request,'File sent successfully') + # office_module_notif(request.user, receiver_id) + file_tracking_notif(request.user, receiver_id, subject) + messages.success(request, 'File sent successfully') except IntegrityError: message = "FileID Already Taken.!!" return HttpResponse(message) - - - file = File.objects.select_related('uploader__user','uploader__department','designation').all() - extrainfo = ExtraInfo.objects.select_related('user','department').all() - holdsdesignations = HoldsDesignation.objects.select_related('user','working','designation').all() + file = File.objects.select_related( + 'uploader__user', 'uploader__department', 'designation').all() + extrainfo = ExtraInfo.objects.select_related('user', 'department').all() + holdsdesignations = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').all() designations = get_designation(request.user) context = { @@ -133,8 +141,8 @@ def filetracking(request): return render(request, 'filetracking/composefile.html', context) -@login_required(login_url = "/accounts/login") -def drafts(request): +@login_required(login_url="/accounts/login") +def draft_design(request): """ The function is used to get the designation of the user and renders it on draft template. @@ -142,22 +150,21 @@ def drafts(request): request - trivial. @variables: - - + + context - Holds data needed to make necessary changes in the template. """ designation = get_designation(request.user) context = { 'designation': designation, } - return render(request, 'filetracking/drafts.html', context) + return render(request, 'filetracking/draft_design.html', context) -@login_required(login_url = "/accounts/login") -def fileview(request,id): - +@login_required(login_url="/accounts/login") +def drafts_view(request, id): """ - This function is used to veiw all all created files by the user ordered by upload date.it collects all the created files from File object. + This function is used to view all the drafts created by the user ordered by upload date.it collects all the created files from File object. @param: request - trivial @@ -166,45 +173,36 @@ def fileview(request,id): @parameters draft - file obeject containing all the files created by user context - holds data needed to render the template - - - """ - # draft = File.objects.select_related('uploader__user','uploader__department','designation').filter(uploader=request.user.extrainfo).order_by('-upload_date') - # extrainfo = ExtraInfo.objects.select_related('user','department').all() - - extrainfo = ExtraInfo.objects.select_related('user','department').all() - - ids = File.objects.filter(uploader=request.user.extrainfo).order_by('-upload_date').values_list('id', flat=True) - draft_files_pk=[] - - for i in ids: - file_tracking_ids = Tracking.objects.filter(file_id=i).values_list('id', flat=True) - if(len(file_tracking_ids)==0): - draft_files_pk.append(i) - - draft_file_list=[] - for i in draft_files_pk: - draft_file_list.append(File.objects.get(pk=i)) + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + draft_files = view_drafts( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # Correct upload_date type + for f in draft_files: + f['upload_date'] = parse_datetime(f['upload_date']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + draft_files = add_uploader_department_to_files_list(draft_files) - user_designation = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) - s = str(user_designation).split(" - ") - designations = s[1] context = { - - 'draft': draft_file_list, - 'extrainfo': extrainfo, - 'designations': designations, + 'draft_files': draft_files, + 'designations': designation, } - return render(request, 'filetracking/fileview.html', context) - - + return render(request, 'filetracking/drafts.html', context) -@login_required(login_url = "/accounts/login") -def fileview1(request,id): +@login_required(login_url="/accounts/login") +def outbox_view(request, id): """ The function is used to get all the files sent by user(employee) to other employees which are filtered from Tracking(table) objects by current user i.e. current_id. @@ -216,56 +214,88 @@ def fileview1(request,id): id - user id @variables: - out - The Tracking object filtered by current_id i.e, present working user. + outward_files - File objects filtered by current_id i.e, present working user. context - Holds data needed to make necessary changes in the template. - + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + + outward_files = view_outbox(username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking') + + for f in outward_files: + last_forw_tracking = get_last_forw_tracking_for_user(file_id=f['id'], + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation) + f['sent_to_user'] = last_forw_tracking.receiver_id + f['sent_to_design'] = last_forw_tracking.receive_design + f['last_sent_date'] = last_forw_tracking.forward_date - outward_files = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(current_id=request.user.extrainfo).order_by('-forward_date') + f['upload_date'] = parse_datetime(f['upload_date']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) - user_designation = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) + outward_files = add_uploader_department_to_files_list(outward_files) context = { - 'out': outward_files, - 'abcd': user_designation, + 'out_files': outward_files, + 'viewer_designation': designation, } - return render(request, 'filetracking/fileview1.html', context) + return render(request, 'filetracking/outbox.html', context) -@login_required(login_url = "/accounts/login") -def fileview2(request,id): - +@login_required(login_url="/accounts/login") +def inbox_view(request, id): """ The function is used to fetch the files received by the user form other employees. These files are filtered by receiver id and ordered by receive date. @param: request - trivial. - id - user id + id - HoldsDesignation object id @variables: - inward_file - The Tracking object filtered by receiver_id i.e, present working user. + inward_files - File object with additional sent by information context - Holds data needed to make necessary changes in the template. """ - inward_file = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(receiver_id=request.user).order_by('-receive_date') - user_designation = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) - s = str(user_designation).split(" - ") - designations = s[1] + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] + inward_files = view_inbox( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + + # correct upload_date type and add recieve_date + for f in inward_files: + f['upload_date'] = parse_datetime(f['upload_date']) + + last_recv_tracking = get_last_recv_tracking_for_user(file_id=f['id'], + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation) + f['receive_date'] = last_recv_tracking.receive_date + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + + inward_files = add_uploader_department_to_files_list(inward_files) + context = { - 'in_file': inward_file, - 'designations': designations, + 'in_file': inward_files, + 'designations': designation, } - return render(request, 'filetracking/fileview2.html', context) + return render(request, 'filetracking/inbox.html', context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def outward(request): """ This function fetches the different designations of the user and renders it on outward template @@ -274,22 +304,22 @@ def outward(request): @variables: context - Holds the different designation data of the user - + """ designation = get_designation(request.user) context = { 'designation': designation, } - return render( request, 'filetracking/outward.html', context) + return render(request, 'filetracking/outward.html', context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def inward(request): """ This function fetches the different designations of the user and renders it on inward template - + @param: request - trivial. @@ -298,7 +328,7 @@ def inward(request): """ designation = get_designation(request.user) context = { - + 'designation': designation, } return render(request, 'filetracking/inward.html', context) @@ -306,7 +336,6 @@ def inward(request): @login_required(login_url = "/accounts/login") def confirmdelete(request,id): - """ The function is used to confirm the deletion of a file. @param: @@ -316,16 +345,86 @@ def confirmdelete(request,id): @variables: context - Holds data needed to make necessary changes in the template. """ - file = File.objects.select_related('uploader__user','uploader__department','designation').get(pk = id) + file = File.objects.select_related( + 'uploader__user', 'uploader__department', 'designation').get(pk=id) context = { 'j': file, } - return render(request, 'filetracking/confirmdelete.html',context) + return render(request, 'filetracking/confirmdelete.html', context) +@login_required(login_url="/accounts/login") +def view_file(request, id): + ''' + This function is used to view a particular file received by an employee from another. + This function also conditionally renders two forms 'forward_file' and 'archive_file' + based on if the user has necessary permissions or not. + The business permissions are as follows: + 1. User can forward file only if they are the last recipient of the file + 2. User can archive a file only if they have received it last and they are also the original owner of the file -@login_required(login_url = "/accounts/login") + To forward the file and to archive the file separate views with POST request are called + + It displays the details file of a File and remarks as well as the attachments of all the users + who have been involved till that point of the workflow. + + @param: + request - Trivial. + id - ID of the file object which the user intends to forward to another employee. + + @variables: + file - The File object. + track - The Tracking object. + designation - the designations of the user + ''' + + file = get_object_or_404(File, id=id) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file).order_by('receive_date') + designations = get_designation(request.user) + + forward_enable = False + archive_enable = False + + current_owner = get_current_file_owner(file.id) + file_uploader = get_user_object_from_username(file.uploader.user.username) + + + if current_owner == request.user and file.is_read is False: + forward_enable = True + if current_owner == request.user and file_uploader == request.user and file.is_read is False: + archive_enable = True + + context = { + 'designations': designations, + 'file': file, + 'track': track, + 'forward_enable': forward_enable, + 'archive_enable': archive_enable, + } + return render(request, 'filetracking/viewfile.html', context) + +@login_required(login_url="/accounts/login") +def archive_file(request, id): + '''This function is used to archive a file. + It returns unauthorized access if the user is not file uploader + and the current owner of the file + ''' + if request.method == "POST": + file = get_object_or_404(File, id=id); + current_owner = get_current_file_owner(file.id) + file_uploader = get_user_object_from_username(file.uploader.user.username) + if current_owner == request.user and file_uploader == request.user: + file.is_read = True + file.save() + messages.success(request, 'File Archived') + else: + messages.error(request, 'Unauthorized access') + + return render(request, 'filetracking/composefile.html') + +@login_required(login_url="/accounts/login") def forward(request, id): """ The function is used to forward files received by user(employee) from other @@ -351,73 +450,72 @@ def forward(request, id): holdsdesignations = HoldsDesignation objects. context - Holds data needed to make necessary changes in the template. """ - - file = get_object_or_404(File, id=id) - track = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(file_id=file) - - if request.method == "POST": - if 'finish' in request.POST: - file.complete_flag = True - file.save() - - if 'send' in request.POST: - current_id = request.user.extrainfo - remarks = request.POST.get('remarks') - track.update(is_read=True) - sender = request.POST.get('sender') - current_design = HoldsDesignation.objects.select_related('user','working','designation').get(id=sender) - - receiver = request.POST.get('receiver') - try: - receiver_id = User.objects.get(username=receiver) - except Exception as e: - messages.error(request, 'Enter a valid destination') - designations = HoldsDesignation.objects.select_related('user','working','designation').filter(user=request.user) - - context = { - - 'designations': designations, - 'file': file, - 'track': track, - } - return render(request, 'filetracking/forward.html', context) - receive = request.POST.get('recieve') - try: - receive_design = Designation.objects.get(name=receive) - except Exception as e: - messages.error(request, 'Enter a valid Designation') - designations = get_designation(request.user) + file = get_object_or_404(File, id=id) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file).order_by('receive_date') - context = { - - 'designations': designations, - 'file': file, - 'track': track, - } - return render(request, 'filetracking/forward.html', context) + if request.method == "POST": + if 'finish' in request.POST: + file.is_read = True + file.save() + if 'send' in request.POST: + current_id = request.user.extrainfo + remarks = request.POST.get('remarks') + track.update(is_read=True) + + sender = request.POST.get('sender') + current_design = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(id=sender) + + receiver = request.POST.get('receiver') + try: + receiver_id = User.objects.get(username=receiver) + except Exception as e: + messages.error(request, 'Enter a valid destination') + designations = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + receive = request.POST.get('recieve') + try: + receive_design = Designation.objects.get(name=receive) + except Exception as e: + messages.error(request, 'Enter a valid Designation') + designations = get_designation(request.user) + + context = { + + 'designations': designations, + 'file': file, + 'track': track, + } + return render(request, 'filetracking/forward.html', context) + + upload_file = request.FILES.get('myfile') + + Tracking.objects.create( + file_id=file, + current_id=current_id, + current_design=current_design, + receive_design=receive_design, + receiver_id=receiver_id, + remarks=remarks, + upload_file=upload_file, + ) + messages.success(request, 'File sent successfully') - - upload_file = request.FILES.get('myfile') - - Tracking.objects.create( - file_id=file, - current_id=current_id, - current_design=current_design, - receive_design=receive_design, - receiver_id=receiver_id, - remarks=remarks, - upload_file=upload_file, - ) - messages.success(request, 'File sent successfully') - - designations = get_designation(request.user) context = { - - 'designations':designations, + + 'designations': designations, 'file': file, 'track': track, } @@ -425,83 +523,88 @@ def forward(request, id): return render(request, 'filetracking/forward.html', context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def archive_design(request): - - designation = HoldsDesignation.objects.select_related('user','working','designation').filter(user=request.user) + designation = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) context = { 'designation': designation, } - return render( request, 'filetracking/archive_design.html', context) - - + return render(request, 'filetracking/archive_design.html', context) +@login_required(login_url="/accounts/login") +def archive_view(request, id): + """ + The function is used to fetch the files in the user's archive + (those which have passed by user and been archived/finished) -@login_required(login_url = "/accounts/login") -def archive(request , id): - - draft = File.objects.select_related('uploader__user','uploader__department','designation').filter(is_read=True).order_by('-upload_date') - + @param: + request - trivial. + id - HoldsDesignation object id - extrainfo = ExtraInfo.objects.select_related('user','department').all() - # designations = Designation.objects.filter(upload_designation=extrainfo.id) - abcd = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) - s = str(abcd).split(" - ") - designations = s[1] - #designations = HoldsDesignation.objects.filter(user=request.user) - # for x in designations: - # if abcd==x: - # designations=abcd + @variables: + archive_files - File object with additional information + context - Holds data needed to make necessary changes in the template. - context = { + """ + user_HoldsDesignation_obj = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) + s = str(user_HoldsDesignation_obj).split(" - ") + designation = s[1] - 'draft': draft, - 'extrainfo': extrainfo, - 'designations': designations, - } + archive_files = view_archived( + username=user_HoldsDesignation_obj.user, + designation=user_HoldsDesignation_obj.designation, + src_module='filetracking' + ) + # correct upload_date type and add receive_date + for f in archive_files: + f['upload_date'] = parse_datetime(f['upload_date']) + f['designation'] = Designation.objects.get(id=f['designation']) + f['uploader'] = get_extra_info_object_from_id(f['uploader']) + archive_files = add_uploader_department_to_files_list(archive_files) + context = { + 'archive_files': archive_files, + 'designations': designation, + } + return render(request, 'filetracking/archive.html', context) - return render(request, 'filetracking/archive.html' , context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def archive_finish(request, id): - file1 = get_object_or_404(File, id=id) ##file = get_object_or_404(File, ref_id=id) + # file = get_object_or_404(File, ref_id=id) + file1 = get_object_or_404(File, id=id) track = Tracking.objects.filter(file_id=file1) - - return render(request, 'filetracking/archive_finish.html', {'file': file1, 'track': track}) - - -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def finish_design(request): - designation = HoldsDesignation.objects.select_related('user','working','designation').filter(user=request.user) + designation = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').filter(user=request.user) context = { 'designation': designation, } - return render( request, 'filetracking/finish_design.html', context) + return render(request, 'filetracking/finish_design.html', context) -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def finish_fileview(request, id): - out = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(file_id__uploader=request.user.extrainfo, is_read=False).order_by('-forward_date') - - - - - abcd = HoldsDesignation.objects.select_related('user','working','designation').get(pk=id) + out = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id__uploader=request.user.extrainfo, is_read=False).order_by('-forward_date') + abcd = HoldsDesignation.objects.select_related( + 'user', 'working', 'designation').get(pk=id) context = { @@ -511,38 +614,29 @@ def finish_fileview(request, id): return render(request, 'filetracking/finish_fileview.html', context) - - -@login_required(login_url = "/accounts/login") +@login_required(login_url="/accounts/login") def finish(request, id): - file1 = get_object_or_404(File, id=id) ##file = get_object_or_404(File, ref_id=id) + # file = get_object_or_404(File, ref_id=id) + file1 = get_object_or_404(File, id=id) track = Tracking.objects.filter(file_id=file1) - if request.method == "POST": - if 'Finished' in request.POST: - File.objects.filter(pk=id).update(is_read=True) - track.update(is_read=True) - messages.success(request,'File Archived') - - - - - - - - return render(request, 'filetracking/finish.html', {'file': file1, 'track': track,'fileid':id}) - + if 'Finished' in request.POST: + File.objects.filter(pk=id).update(is_read=True) + track.update(is_read=True) + messages.success(request, 'File Archived') + return render(request, 'filetracking/finish.html', {'file': file1, 'track': track, 'fileid': id}) def AjaxDropdown1(request): + """ This function returns the designation of receiver on the forward or compose file template. @param: request - trivial. - + @variables: context - return the httpresponce containing the matched designation of the user @@ -553,20 +647,19 @@ def AjaxDropdown1(request): hold = Designation.objects.filter(name__startswith=value) holds = serializers.serialize('json', list(hold)) context = { - 'holds' : holds + 'holds': holds } return HttpResponse(JsonResponse(context), content_type='application/json') def AjaxDropdown(request): - """ This function returns the usernames of receiver on the forward or compose file template. @param: request - trivial. - + @variables: context - return the httpresponce containing the matched username @@ -589,24 +682,22 @@ def test(request): @login_required(login_url = "/accounts/login") def delete(request,id): - """ The function is used the delete of a file and it returns to the drafts page. @param: request - trivial. id - id of the file that is going to be deleted - + """ - file = File.objects.get(pk = id) + file = File.objects.get(pk=id) file.delete() - return redirect('/filetracking/drafts/') + return redirect('/filetracking/draftdesign/') def forward_inward(request,id): - """ This function is used forward the files which are available in the inbox of the user . @param: @@ -617,21 +708,25 @@ def forward_inward(request,id): file - file object track - tracking object of the file context - necessary data to render - + """ file = get_object_or_404(File, id=id) file.is_read = True - track = Tracking.objects.select_related('file_id__uploader__user','file_id__uploader__department','file_id__designation','current_id__user','current_id__department', - 'current_design__user','current_design__working','current_design__designation','receiver_id','receive_design').filter(file_id=file) + track = Tracking.objects.select_related('file_id__uploader__user', 'file_id__uploader__department', 'file_id__designation', 'current_id__user', 'current_id__department', + 'current_design__user', 'current_design__working', 'current_design__designation', 'receiver_id', 'receive_design').filter(file_id=file) designations = get_designation(request.user) context = { - - 'designations':designations, + + 'designations': designations, 'file': file, 'track': track, } return render(request, 'filetracking/forward.html', context) - +def get_designations_view(request, username): + designations = get_designations(username) + print(designations) + return JsonResponse(designations, safe=False) + diff --git a/FusionIIIT/applications/globals/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/globals/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..9fa2bfc59 --- /dev/null +++ b/FusionIIIT/applications/globals/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('globals', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='extrainfo', + name='user_status', + field=models.CharField(choices=[('NEW', 'NEW'), ('PRESENT', 'PRESENT')], default='PRESENT', max_length=50), + ), + ] diff --git a/FusionIIIT/applications/globals/migrations/0003_auto_20240308_1025.py b/FusionIIIT/applications/globals/migrations/0003_auto_20240308_1025.py new file mode 100644 index 000000000..2f9f4c3d6 --- /dev/null +++ b/FusionIIIT/applications/globals/migrations/0003_auto_20240308_1025.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('globals', '0002_auto_20240308_1023'), + ] + + operations = [ + migrations.AlterField( + model_name='extrainfo', + name='user_status', + field=models.CharField(choices=[('PRESENT', 'PRESENT'), ('NEW', 'NEW')], default='PRESENT', max_length=50), + ), + ] diff --git a/FusionIIIT/applications/globals/urls.py b/FusionIIIT/applications/globals/urls.py index f8d82ee71..2dea4e77d 100644 --- a/FusionIIIT/applications/globals/urls.py +++ b/FusionIIIT/applications/globals/urls.py @@ -23,5 +23,6 @@ # Endpoint to reset all passwords in DEV environment url(r'^resetallpass/$', views.reset_all_pass, name='resetallpass'), # API urls - url(r'^api/', include('applications.globals.api.urls')) + url(r'^api/', include('applications.globals.api.urls')), + url(r'^update_global_variable/$', views.update_global_variable, name='update_global_var'), ] diff --git a/FusionIIIT/applications/globals/views.py b/FusionIIIT/applications/globals/views.py index a7f3886c9..5b023abb5 100644 --- a/FusionIIIT/applications/globals/views.py +++ b/FusionIIIT/applications/globals/views.py @@ -740,21 +740,26 @@ def dashboard(request): } # a=HoldsDesignation.objects.select_related('user','working','designation').filter(designation = user) + print(context) + print(type(user.extrainfo.user_type)) if(request.user.get_username() == 'director'): return render(request, "dashboard/director_dashboard2.html", {}) elif( "dean_rspc" in designation): return render(request, "dashboard/dashboard.html", context) - elif user.extrainfo.user_type != 'student': + elif user.extrainfo.user_type != "student": + print ("inside") designat = HoldsDesignation.objects.select_related().filter(user=user) response = {'designat':designat} context.update(response) return render(request, "dashboard/dashboard.html", context) else: + print ("inside2") + return render(request, "dashboard/dashboard.html", context) @login_required(login_url=LOGIN_URL) -def profile(request, username=None): +def profile(request, username=None): """ Generic endpoint for views. If it's a faculty, redirects to /eis/profile/* @@ -768,16 +773,76 @@ def profile(request, username=None): """ user = get_object_or_404(User, Q(username=username)) if username else request.user - editable = request.user == user + print("editable",editable) profile = get_object_or_404(ExtraInfo, Q(user=user)) + print("profile",profile) if(str(user.extrainfo.user_type)=='faculty'): + print("profile") return HttpResponseRedirect('/eis/profile/' + (username if username else '')) if(str(user.extrainfo.department)=='department: Academics'): + print("profile2") return HttpResponseRedirect('/aims') - current = HoldsDesignation.objects.select_related('user','working','designation').filter(Q(working=user, designation__name="student")) + + array = [ + "student", + "CC convenor", + "Mechatronic convenor", + "mess_committee", + "mess_convener", + "alumini", + "Electrical_AE", + "Electrical_JE", + "Civil_AE", + "Civil_JE", + "co-ordinator", + "co co-ordinator", + "Convenor", + "Convener", + "cc1convener", + "CC2 convener", + "mess_convener_mess2", + "mess_committee_mess2" +] + + # queryset = HoldsDesignation.objects.select_related('user','working','designation').filter(Q(working=user)) + + # for obj in queryset: + # designation_name = obj.designation.name + # print("designation_name",designation_name) + + # design = False + # if designation_name in array: + # design = True + # print("design",design) + # print("designation_name",designation_name) + # if design: + # current = HoldsDesignation.objects.select_relapted('user','working','designation').filter(Q(working=user, designation__name=designation_name)) + # for obj in current: + # obj.designation.name = obj.designation.name.replace(designation_name, 'student') + + designation_name = "" + design = False + + current = HoldsDesignation.objects.select_related('user', 'working', 'designation').filter(Q(working=user)) + + for obj in current: + designation_name = obj.designation.name + if designation_name in array: + design = True + break + + if design: + current = HoldsDesignation.objects.filter(working=user, designation__name=designation_name) + for obj in current: + obj.designation.name = obj.designation.name.replace(designation_name, 'student') + + print(user.extrainfo.user_type) + print("current",current) if current: + print("profile3") student = get_object_or_404(Student, Q(id=profile.id)) + print("student",student) if editable and request.method == 'POST': if 'studentapprovesubmit' in request.POST: status = PlacementStatus.objects.select_related('notify_id','unique_id__id__user','unique_id__id__department').filter(pk=request.POST['studentapprovesubmit']).update(invitation='ACCEPTED', timestamp=timezone.now()) @@ -979,6 +1044,7 @@ def profile(request, username=None): return render(request, "globals/student_profile4.html", context) if 'achievementsubmit' in request.POST or 'deleteach' in request.POST: return render(request, "globals/student_profile5.html", context) + print("context",context) return render(request, "globals/student_profile.html", context) else: return redirect("/") @@ -1176,4 +1242,15 @@ def search(request): if len(search_results) == 0: search_results = [] context = {'sresults':search_results} - return render(request, "globals/search.html", context) + return render(request, "globals/search.html", context), + +@login_required(login_url=LOGIN_URL) +def update_global_variable(request): + if request.method == 'POST': + selected_option = request.POST.get('dropdown') + request.session['currentDesignationSelected'] = selected_option + print(selected_option) + print(request.session['currentDesignationSelected']) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + # Redirect to home if not a POST request or some issue occurs + return HttpResponseRedirect(reverse('home')) diff --git a/FusionIIIT/applications/iwdModuleV2/migrations/0002_bills_requests.py b/FusionIIIT/applications/iwdModuleV2/migrations/0002_bills_requests.py new file mode 100644 index 000000000..24909bc10 --- /dev/null +++ b/FusionIIIT/applications/iwdModuleV2/migrations/0002_bills_requests.py @@ -0,0 +1,41 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('iwdModuleV2', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Requests', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('description', models.CharField(max_length=200)), + ('area', models.CharField(max_length=200)), + ('requestCreatedBy', models.CharField(max_length=200)), + ('engineerProcessed', models.IntegerField()), + ('directorApproval', models.IntegerField()), + ('deanProcessed', models.IntegerField()), + ('status', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='Bills', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('work', models.CharField(max_length=200)), + ('description', models.CharField(max_length=200)), + ('agency', models.CharField(max_length=200)), + ('bill_processed', models.IntegerField()), + ('bill_settled', models.IntegerField()), + ('key', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='iwdModuleV2.projects', unique=True)), + ], + ), + ] diff --git a/FusionIIIT/applications/iwdModuleV2/models.py b/FusionIIIT/applications/iwdModuleV2/models.py index a5c40c7b2..e4c09f3cc 100644 --- a/FusionIIIT/applications/iwdModuleV2/models.py +++ b/FusionIIIT/applications/iwdModuleV2/models.py @@ -1,5 +1,5 @@ from django.db import models - +from datetime import date # Create your models here. @@ -160,3 +160,40 @@ class NoOfTechnicalBidTimes(models.Model): key = models.ForeignKey(Projects, on_delete=models.CASCADE, unique=True) number = models.IntegerField() +class Requests(models.Model): + # id = models.IntegerField(primary_key=True, max_length=200) + name = models.CharField(max_length=200) + description = models.CharField(max_length=200) + area = models.CharField(max_length=200) + requestCreatedBy = models.CharField(max_length=200) + engineerProcessed = models.IntegerField() + directorApproval = models.IntegerField() + deanProcessed = models.IntegerField() + status = models.CharField(max_length=200) + issuedWorkOrder = models.IntegerField() + workCompleted = models.IntegerField() + +class WorkOrder(models.Model): + request_id = models.IntegerField() + name = models.CharField(max_length=200) + date = models.DateField(default=date.today) + agency = models.CharField(max_length=200) + amount = models.IntegerField() + deposit = models.IntegerField() + alloted_time = models.CharField(max_length=200) + start_date = models.DateField() + completion_date = models.DateField() + +class Inventory(models.Model): + name = models.CharField(max_length=200) + quantity = models.IntegerField() + cost = models.IntegerField() + +class Bills(models.Model): + key = models.ForeignKey(Projects, on_delete=models.CASCADE, unique=True) + name = models.CharField(max_length=200) + work = models.CharField(max_length=200) + description = models.CharField(max_length=200) + agency = models.CharField(max_length=200) + bill_processed = models.IntegerField() + bill_settled = models.IntegerField() \ No newline at end of file diff --git a/FusionIIIT/applications/iwdModuleV2/urls.py b/FusionIIIT/applications/iwdModuleV2/urls.py index 6ad401098..1530d11c5 100644 --- a/FusionIIIT/applications/iwdModuleV2/urls.py +++ b/FusionIIIT/applications/iwdModuleV2/urls.py @@ -36,5 +36,28 @@ url(r'milestoneView/$', views.milestoneView, name='Milestones'), url(r'addendumView/$', views.addendumView, name='Addendum View'), url('agreementView/$', views.agreementView, name='Agreement VIew'), - url(r'corrigendumView/$', views.corrigendumView, name='Corrigendum View') + url(r'corrigendumView/$', views.corrigendumView, name='Corrigendum View'), + url('requestsView/',views.requestsView, name='Requests view'), + url('createdRequestsView/',views.createdRequests, name='Created Requests view'), + url('handleEngineerProcessRequests/', views.handleEngineerProcessRequests, name='Engineer-Process-Requests'), + url('engineerProcessedRequestsView/',views.engineerProcessedRequests, name='Engineer-Processed-Requests view'), + url('handleDeanProcessRequests/', views.handleDeanProcessRequests, name='Dean-Process-Requests'), + url('deanProcessedRequestsView/',views.deanProcessedRequests, name='Dean-Processed-Requests view'), + url('handleDirectorApprovalRequests/', views.handleDirectorApprovalRequests, name='Director-Approval-Requests'), + url('handleDirectorRejectionRequests/', views.handleDirectorRejectionRequests, name='Director-Rejection-Requests'), + url('requestsStatus/', views.requestsStatus, name='Requests-Status'), + url('fetchDesignations/', views.fetchDesignations, name='Fetch-Designations'), + url('fetchRequest/', views.fetchRequest, name='Fetch-Request'), + url('issueWorkOrder/', views.issueWorkOrder, name='Issue Work Order'), + url('workOrder/', views.workOrder, name='Work Order'), + url('inventory/', views.inventory, name='Inventory'), + url('addItemsView/', views.addItemsView, name='Add Items View'), + url('addItems/', views.addItems, name='Add Items'), + url('editInventoryView/', views.editInventoryView, name='Edit Inventory View'), + url('editInventory/', views.editInventory, name='Edit Inventory'), + url('requestsInProgess/', views.requestsInProgess, name='Requests In Progress'), + url('workCompleted/', views.workCompleted, name='Work Completed'), + url('requestFromInventory/', views.requestFromInventory, name='Request From Inventory'), + # url('billsView/',views.billsView, name='Bills View'), + ] diff --git a/FusionIIIT/applications/iwdModuleV2/views.py b/FusionIIIT/applications/iwdModuleV2/views.py index 7cc9cf67c..25c299199 100644 --- a/FusionIIIT/applications/iwdModuleV2/views.py +++ b/FusionIIIT/applications/iwdModuleV2/views.py @@ -1,9 +1,11 @@ from django.shortcuts import render, redirect - +from django.urls import reverse +from django.db.models import Q from applications.globals.models import * from .models import * from django.http import HttpResponseRedirect - +from applications.filetracking.sdk.methods import * +from applications.globals.models import ExtraInfo, HoldsDesignation, Designation # Create your views here. @@ -17,17 +19,24 @@ # owing to length and inherent extensiveness of code. Rather than, whosoever read this code is advised to do so # in conjunction with SRS. After that, everything will become easier. +# def dashboard(request): +# eligible = False +# userObj = request.user +# userDesignationObjects = HoldsDesignation.objects.filter(user=userObj) +# for p in userDesignationObjects: +# if p.designation.name == 'Admin IWD': +# eligible = True +# break +# return render(request, 'iwdModuleV2/dashboard.html', {'eligible': eligible}) + def dashboard(request): - eligible = True + eligible = "" userObj = request.user userDesignationObjects = HoldsDesignation.objects.filter(user=userObj) for p in userDesignationObjects: - if p.designation.name == 'Admin IWD': - eligible = True - break + eligible = p.designation.name return render(request, 'iwdModuleV2/dashboard.html', {'eligible': eligible}) - def page1_1(request): if request.method == 'POST': formObject = PageOneDetails() @@ -434,3 +443,434 @@ def extensionFormView(request): extensionObjects = ExtensionOfTimeDetails.objects.filter( key=Projects.objects.get(id=request.session['projectId'])) return render(request, 'iwdModuleV2/ExtensionForm.html', {'extension': extensionObjects}) + +def fetchDesignations(request): + print("yesslkednonmedcm") + designations = Designation.objects.filter() + + holdsDesignations = [] + + for d in designations: + if d.name == "Engineer" or d.name == "Dean" or d.name == "director" or d.name == "Accounts Admin": + list = HoldsDesignation.objects.filter(designation=d) + holdsDesignations.append(list) + + return render(request, 'iwdModuleV2/requestsView.html', {'holdsDesignations' : holdsDesignations}) + +def requestsView(request): + if request.method == 'POST': + formObject = Requests() + # formObject.key = Projects.objects.get(id=request.session['projectId']) + formObject.name = request.POST['name'] + formObject.description = request.POST['description'] + formObject.area = request.POST['area'] + formObject.engineerProcessed = 0 + formObject.directorApproval = 0 + formObject.deanProcessed = 0 + formObject.requestCreatedBy = request.user.username + formObject.status = "Pending" + formObject.issuedWorkOrder = 0 + formObject.workCompleted = 0 + formObject.save() + request_object = Requests.objects.get(pk=formObject.pk) + d = HoldsDesignation.objects.get(user__username=request.POST['designation']) + create_file(uploader=request.user.username, + uploader_designation="Engineer", + receiver=request.POST['designation'], + receiver_designation=d.designation, + src_module="IWD", + src_object_id= str(request_object.id), + file_extra_JSON= {"value": 2}, + attached_file = None) + return redirect('http://127.0.0.1:8000/iwdModuleV2/') + return render(request, 'http://127.0.0.1:8000/iwdModuleV2/', {}) + +def createdRequests(request): + obj = [] + + inbox_files = view_inbox( + username=request.user, + designation="Engineer", + src_module="IWD" + ) + + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + designations = Designation.objects.filter() + + holdsDesignations = [] + + for d in designations: + if d.name == "Engineer" or d.name == "Dean" or d.name == "director" or d.name == "Accounts Admin": + list = HoldsDesignation.objects.filter(designation=d) + holdsDesignations.append(list) + + return render(request, 'iwdModuleV2/createdRequests.html', {'obj' : obj, 'holdsDesignations' : holdsDesignations}) + +def handleEngineerProcessRequests(request): + if request.method == 'POST': + + request_id = request.POST.get("id", 0) + + d = HoldsDesignation.objects.get(user__username=request.POST['designation']) + d1 = HoldsDesignation.objects.get(user__username=request.user) + + create_file(uploader=request.user.username, + uploader_designation=d1.designation, + receiver=request.POST['designation'], + receiver_designation=d.designation, + src_module="IWD", + src_object_id= str(request_id), + file_extra_JSON= {"value": 2}, + attached_file = None) + + Requests.objects.filter(id=request_id).update(engineerProcessed=1, status="Approved by the engineer") + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + for p in inbox_files: + if p['src_object_id'] == request_id: + delete_file(file_id = p['id']) + break + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + obj = [] + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + return render(request, 'iwdModuleV2/createdRequests.html', {'obj' : obj}) + +def engineerProcessedRequests(request): + + obj = [] + + d = HoldsDesignation.objects.get(user__username=request.user) + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + designations = Designation.objects.filter() + + holdsDesignations = [] + + for d in designations: + if d.name == "Engineer" or d.name == "Dean" or d.name == "director" or d.name == "Accounts Admin": + list = HoldsDesignation.objects.filter(designation=d) + holdsDesignations.append(list) + + return render(request, 'iwdModuleV2/engineerProcessedRequests.html', {'obj' : obj, 'holdsDesignations' : holdsDesignations}) + +def handleDeanProcessRequests(request): + if request.method == 'POST': + + request_id = request.POST.get("id", 0) + + d = HoldsDesignation.objects.get(user__username=request.POST['designation']) + d1 = HoldsDesignation.objects.get(user__username=request.user) + + create_file(uploader=request.user.username, + uploader_designation=d1.designation, + receiver=request.POST['designation'], + receiver_designation=d.designation, + src_module="IWD", + src_object_id= str(request_id), + file_extra_JSON= {"value": 2}, + attached_file = None) + + Requests.objects.filter(id=request_id).update(deanProcessed=1, status="Approved by the dean") + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + for p in inbox_files: + if p['src_object_id'] == request_id: + delete_file(file_id = p['id']) + break + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + obj = [] + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + return render(request, 'iwdModuleV2/engineerProcessedRequests.html', {'obj' : obj}) + +def deanProcessedRequests(request): + obj = [] + + d = HoldsDesignation.objects.get(user__username=request.user) + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + designations = Designation.objects.filter() + + holdsDesignations = [] + + for d in designations: + if d.name == "Engineer" or d.name == "Dean" or d.name == "director" or d.name == "Accounts Admin": + list = HoldsDesignation.objects.filter(designation=d) + holdsDesignations.append(list) + + return render(request, 'iwdModuleV2/deanProcessedRequests.html', {'obj' : obj, 'holdsDesignations' : holdsDesignations}) + +def handleDirectorApprovalRequests(request): + if request.method == 'POST': + request_id = request.POST.get("id", 0) + + d = HoldsDesignation.objects.get(user__username=request.POST['designation']) + d1 = HoldsDesignation.objects.get(user__username=request.user) + + create_file(uploader=request.user.username, + uploader_designation=d1.designation, + receiver=request.POST['designation'], + receiver_designation=d.designation, + src_module="IWD", + src_object_id= str(request_id), + file_extra_JSON= {"value": 2}, + attached_file = None) + + Requests.objects.filter(id=request_id).update(directorApproval=1, status="Approved by the director") + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + for p in inbox_files: + if p['src_object_id'] == request_id: + delete_file(file_id = p['id']) + break + + inbox_files = view_inbox( + username=request.user, + designation=d1.designation, + src_module="IWD" + ) + + obj = [] + for result in inbox_files: + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + return render(request, 'iwdModuleV2/deanProcessedRequests.html', {'obj' : obj}) + +def handleDirectorRejectionRequests(request): + if request.method == 'POST': + request_id = request.POST.get("id", 0) + Requests.objects.filter(id=request_id).update(directorApproval=-1, status="Rejected by the director") + obj = [] + requestsObject = Requests.objects.filter(engineerProcessed = 1, deanProcessed = 1, directorApproval = 0) + for x in requestsObject: + element = [x.id, x.name, x.area, x.description, x.requestCreatedBy] + obj.append(element) + return render(request, 'iwdModuleV2/deanProcessedRequests.html', {'obj' : obj}) + +def issueWorkOrder(request): + obj = [] + + d = HoldsDesignation.objects.get(user__username=request.user) + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + for result in inbox_files: + uploader = result['sent_by_designation'] + if uploader == 'director': + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + return render(request, 'iwdModuleV2/issueWorkOrder.html', {'obj' : obj}) + +def fetchRequest(request): + request_id = request.POST.get("id", 0) + req_request = Requests.objects.get(id=request_id) + return render(request, 'iwdModuleV2/workOrder.html', {'req' : req_request}) + +def workOrder(request): + if request.method == 'POST': + formObject = WorkOrder() + formObject.request_id = request.POST['id'] + formObject.name = request.POST['name'] + formObject.date = request.POST['date'] + formObject.agency = request.POST['agency'] + formObject.amount = request.POST['amount'] + formObject.deposit = request.POST['deposit'] + formObject.alloted_time = request.POST['time'] + formObject.start_date = request.POST['startDate'] + formObject.completion_date = request.POST['completionDate'] + formObject.save() + + Requests.objects.filter(id=request.POST['id']).update(status="Work Order issued", issuedWorkOrder=1) + + d = HoldsDesignation.objects.get(user__username=request.user) + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + for result in inbox_files: + if result['src_object_id'] == request.POST['id'] and result['sent_by_designation'] == 'director': + delete_file(file_id = result['id']) + break + + inbox_files = view_inbox( + username=request.user, + designation=d.designation, + src_module="IWD" + ) + + obj = [] + + for result in inbox_files: + uploader = result['sent_by_designation'] + if uploader == 'director': + src_object_id = result['src_object_id'] + request_object = Requests.objects.filter(id=src_object_id).first() + if request_object: + element = [request_object.id, request_object.name, request_object.area, request_object.description, request_object.requestCreatedBy] + obj.append(element) + + return render(request, 'iwdModuleV2/issueWorkOrder.html', {'obj' : obj}) + +def requestsStatus(request): + obj = [] + requestsObject = Requests.objects.all() + for x in requestsObject: + element = [x.id, x.name, x.area, x.description, x.requestCreatedBy, x.status] + obj.append(element) + return render(request, 'iwdModuleV2/requestsStatus.html', {'obj' : obj}) + +def inventory(request): + items = Inventory.objects.filter() + obj = [] + for i in items: + element = [i.id, i.name, i.quantity, i.cost] + obj.append(element) + return render(request, 'iwdModuleV2/inventory.html', {'obj' : obj}) + +def addItemsView(request): + return render(request, 'iwdModuleV2/addItemsView.html') + +def addItems(request): + if request.method == "POST": + formObject = Inventory() + formObject.name = request.POST['name'] + formObject.quantity = request.POST['quantity'] + formObject.cost = request.POST['cost'] + formObject.save() + return render(request, 'iwdModuleV2/addItemsView.html') + +def editInventoryView(request): + items = Inventory.objects.filter() + obj = [] + for i in items: + element = [i.id, i.name, i.quantity, i.cost] + obj.append(element) + return render(request, 'iwdModuleV2/editInventory.html', {'obj' : obj}) + +def editInventory(request): + if request.method == "POST": + itemId = request.POST['id'] + itemName = request.POST['name'] + itemQuantity = request.POST['quantity'] + itemCost = request.POST['cost'] + Inventory.objects.filter(id=itemId).update(name=itemName, quantity=itemQuantity, cost=itemCost) + items = Inventory.objects.filter() + obj = [] + for i in items: + element = [i.id, i.name, i.quantity, i.cost] + obj.append(element) + return render(request, 'iwdModuleV2/editInventory.html', {'obj' : obj}) + +def requestsInProgess(request): + obj = [] + requestsObject = Requests.objects.filter(issuedWorkOrder=1) + for x in requestsObject: + element = [x.id, x.name, x.area, x.description, x.requestCreatedBy, x.workCompleted] + obj.append(element) + return render(request, 'iwdModuleV2/requestsInProgress.html', {'obj' : obj}) + +def workCompleted(request): + if request.method == 'POST': + Requests.objects.filter(id=request.POST['id']).update(workCompleted=1, status="Work Completed") + obj = [] + requestsObject = Requests.objects.filter(issuedWorkOrder=1) + for x in requestsObject: + element = [x.id, x.name, x.area, x.description, x.requestCreatedBy, x.workCompleted] + obj.append(element) + return render(request, 'iwdModuleV2/requestsInProgress.html', {'obj' : obj}) + +def requestFromInventory(request): + if request.method == 'POST': + requestId = request.POST['id'] + Req = Requests.objects.filter(id=requestId) + Items = Inventory.objects.filter() + req = [] + items = [] + for i in Req: + print(i) + print(req) + print(items) + return render(request, 'iwdModuleV2/requestFromInventory.html', {'req' : req, 'items' : items}) \ No newline at end of file diff --git a/FusionIIIT/applications/programme_curriculum/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/programme_curriculum/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..fef68f722 --- /dev/null +++ b/FusionIIIT/applications/programme_curriculum/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('programme_curriculum', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='batch', + name='year', + field=models.PositiveIntegerField(default=2024), + ), + migrations.AlterField( + model_name='programme', + name='programme_begin_year', + field=models.PositiveIntegerField(default=2024), + ), + ] diff --git a/FusionIIIT/applications/scholarships/migrations/0002_auto_20240308_1023.py b/FusionIIIT/applications/scholarships/migrations/0002_auto_20240308_1023.py new file mode 100644 index 000000000..997db0247 --- /dev/null +++ b/FusionIIIT/applications/scholarships/migrations/0002_auto_20240308_1023.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2024-03-08 10:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('scholarships', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='previous_winner', + name='year', + field=models.IntegerField(default=2024), + ), + ] diff --git a/FusionIIIT/templates/academic_procedures/academic.html b/FusionIIIT/templates/academic_procedures/academic.html old mode 100755 new mode 100644 index 6b04a54fb..35eebf446 --- a/FusionIIIT/templates/academic_procedures/academic.html +++ b/FusionIIIT/templates/academic_procedures/academic.html @@ -22,6 +22,39 @@ } + + {% endblock css %} @@ -30,13 +63,12 @@ {% include 'dashboard/navbar.html' %} {% endblock %} -
+
- {% comment %}The left-margin segment!{% endcomment %} -
+ {% comment %}The left-rail segment starts here!{% endcomment %} -
+
{% comment %}The user image card starts here!{% endcomment %} {% block usercard %} {% include 'globals/usercard.html' %} @@ -46,8 +78,8 @@
{% comment %}The Tab-Menu starts here!{% endcomment %} -