diff --git a/csc/api/utility.py b/csc/api/utility.py index ef36bce..678cae5 100644 --- a/csc/api/utility.py +++ b/csc/api/utility.py @@ -8,9 +8,9 @@ from django.conf import settings import random, string -from csc.models import Student_certificate_course,CategoryCourses,Student_Foss +from csc.models import Student_certificate_course,CategoryCourses,Student_Foss, Invigilator from django.db import IntegrityError -from csc.utils import is_user_vle, is_user_student +from csc.utils import is_user_vle, is_user_student, is_user_invigilator from django.template.loader import render_to_string def send_pwd_mail(u): print(u.username) @@ -61,7 +61,33 @@ def send_pwd_mail(u): Spoken Tutorial """ path = 'vle_mail_template.html' - html_content = render_to_string(path, {'full_name':u.get_full_name(),'username':u.username,'password':pwd}) + if is_user_invigilator(u): + inv = Invigilator.objects.get(user=u) + name = inv.vle.all()[0].user.get_full_name() + message = f""" + Dear {u.get_full_name()}, + + Welcome to IIT Bombay Spoken Tutorial Program. We are happy to be partnered with CSC Academy to + empower youth from all over the country via VLEs. + + You have been added as an invigilator by VLE {name}. + + Please use the below Login details for the Spoken Tutorial Dashboard: + Link to Login: https://spoken-tutorial.in/login/ + username : {u.username} + password : {pwd} + Please click the following training link to know the process of + Student Registration Instructions : https://docs.google.com/document/d/1z8-s4sSl7viPqJ8WAFeeNmoJUVLRPv2L9jLOrfN6ln0/edit?usp=sharing + Course Allotment Instructions : https://docs.google.com/document/d/1Mv23iijOVuS6eCcHCgYKbbxopjk_SkSfExXW-61G2AQ/edit?usp=sharing + + In case of any query, please feel free to contact at animation-hackathon@cscacademy.org. + + Thanks & Regards, + Team, + Spoken Tutorial + """ + path = 'invigilator_mail_template.html' + html_content = render_to_string(path, {'full_name':u.get_full_name(), 'vle': name,'username':u.username,'password':pwd}) try: print(f"/n/nSending mail ; username,pwd : {u.username},{pwd}".ljust(40,'*')) send_mail( diff --git a/csc/stats/urls.py b/csc/stats/urls.py index e301bf9..0e2a113 100644 --- a/csc/stats/urls.py +++ b/csc/stats/urls.py @@ -13,9 +13,9 @@ path('vle_stats/',VLEListView.as_view(),name="vle_stats"), path('student_stats/',StudentListView.as_view(),name="student_stats"), path('vle_report/',vle_report,name="vle_report"), - path('student_report/',student_report,name="student_report") - + path('student_report/',student_report,name="student_report"), + path('test_report/',test_report,name="test_report") ] \ No newline at end of file diff --git a/csc/stats/views.py b/csc/stats/views.py index d0035f7..86ab972 100644 --- a/csc/stats/views.py +++ b/csc/stats/views.py @@ -7,12 +7,14 @@ from django.utils.decorators import method_decorator from django.contrib.auth.mixins import LoginRequiredMixin -from csc.models import CSC,VLE,Student, FossCategory, CertifiateCategories, Student_Foss +from csc.models import CSC,VLE,Student, FossCategory, CertifiateCategories, Student_Foss, Test from cms.models import State, District from csc.decorators import is_csc_team as dec_is_csc_team from csc.utils import is_csc_team_role from .utility import * +from datetime import datetime + @login_required @dec_is_csc_team @@ -27,6 +29,8 @@ def stats(request): context['total_students'] = total_students context['total_foss'] = total_foss context['total_certificate_course'] = total_certificate_course + context['total_test_conducted'] = Test.objects.filter(tdate__lt=datetime.now().date()).count() + context['total_upcoming_tests'] = Test.objects.filter(tdate__gte=datetime.now().date()).count() student_gender = get_student_gender_stats() context['student_gender'] = student_gender @@ -153,7 +157,7 @@ def get_context_data(self, **kwargs): return context def get_queryset(self): qs = super().get_queryset() - qs = qs_vle + qs = qs_vle.annotate(Count('test')) if self.request.GET.get('name'): name = self.request.GET.get('name') qs = qs.filter(Q(user__first_name__icontains=name)|Q(user__last_name__icontains=name)|Q(user__email__icontains=name)) @@ -198,6 +202,8 @@ def ajax_vle_detail(request): data['students'] = [x for x in Student.objects.filter(vle_id=vle_id).values('user__first_name', 'user__last_name','user__email')] cert_category = CertifiateCategories.objects.get(code='INDI') data['indi_fosses'] = [x for x in Student_Foss.objects.filter(student__vle_id=vle_id,cert_category=cert_category).values('csc_foss__foss').annotate(count=Count('csc_foss'))] + data['conducted_test'] = Test.objects.filter(vle=vle, tdate__lt=datetime.now().date()).count() + data['upcoming_test'] = Test.objects.filter(vle=vle, tdate__gte=datetime.now().date()).count() return JsonResponse(data) @@ -233,4 +239,24 @@ def vle_report(request): csc_district = CSC.objects.values('district').annotate(count=Count('district')).order_by('district') context['csc_district'] = csc_district - return render(request, 'stats/vle_report.html', context) \ No newline at end of file + return render(request, 'stats/vle_report.html', context) + +@login_required +@dec_is_csc_team +def test_report(request): + context = {} + all_foss = FossCategory.objects.annotate(upcoming_tests = Count('test', distinct=True, filter=Q(test__tdate__gte=datetime.now().date())), conducted_tests=Count('test', distinct=True, filter=Q(test__tdate__lt=datetime.now().date()))).order_by() + all_test = Test.objects.annotate(upcoming_students = Count('csctestatttendance', distinct=True, filter=Q(csctestatttendance__status__lte=2)), appeared_students = Count('csctestatttendance', distinct=True, filter=Q(csctestatttendance__status__gt=2)), all_certificates = Count('csctestatttendance', distinct=True, filter=Q(csctestatttendance__status__gte=3))) + foss = {} + for item in all_foss: + for value in all_test: + foss[item.foss] = { + 'upcoming_tests': item.upcoming_tests, + 'conducted_tests': item.conducted_tests, + 'upcoming_students': value.upcoming_students, + 'appeared_students': value.appeared_students, + 'all_certificates': value.all_certificates, + } + context['fosses'] = foss + print(context['fosses']['Blender']) + return render(request, 'stats/test_report.html', context) \ No newline at end of file diff --git a/csc/templates/csc/invigilator_mail_template.html b/csc/templates/csc/invigilator_mail_template.html new file mode 100644 index 0000000..dcf5d64 --- /dev/null +++ b/csc/templates/csc/invigilator_mail_template.html @@ -0,0 +1,31 @@ + + + + + Order received + + + +

Dear {{full_name}},

+

Welcome to IIT Bombay Spoken Tutorial Program. We are happy to be partnered with CSC Academy to + empower youth from all over the country via VLEs.

+ +

You have been added as an invigilator by VLE {{vle}}.

+ +

Please use the below Login details for the Spoken Tutorial Dashboard:

+

Link to Login: https://spoken-tutorial.in/login/

+ +

username : {{username}}

+

password : {{password}}

+ +

Please click the following training link to know the process of

+

Student Registration Instructions : Click Here

+

Course Allotment Instructions : Click Here

+ +

In case of any query, please feel free to contact at animation-hackathon@cscacademy.org.

+ +

Thanks & Regards,

+

Team,

+

Spoken Tutorial

+ + \ No newline at end of file diff --git a/csc/templates/csc/test_list.html b/csc/templates/csc/test_list.html index 8edc759..afa4771 100644 --- a/csc/templates/csc/test_list.html +++ b/csc/templates/csc/test_list.html @@ -17,13 +17,14 @@ # - Title FOSS Date Time - {% comment %} Published {% endcomment %} - {% comment %} Delete - Edit {% endcomment %} + Delete + Edit + Students + Upcoming + Appeared @@ -31,26 +32,15 @@ {% for test in tests %} {{forloop.counter}} - - {% if test.test_name %} - {{test.test_name | title}} - {% else %} - {{test.foss | title}} Test - {% endif %} - {{test.foss | title }} {{test.tdate}} {{test.ttime}} - {% comment %} - {% if test.publish %} - - {% else %} - - {% endif %} - {% endcomment %} - {% comment %} - {% endcomment %} - {% if test.tdate|is_gte_today %} + + + + {{test.upcoming_students}} + {{test.appeared_students}} + {% if test.tdate|is_today %} diff --git a/csc/templates/csc/test_students.html b/csc/templates/csc/test_students.html new file mode 100644 index 0000000..d02bc4e --- /dev/null +++ b/csc/templates/csc/test_students.html @@ -0,0 +1,74 @@ +{% extends 'csc_base.html'%} +{% load static %} +{% load csc_tags %} +{% block css %} + + + +{% endblock css %} +{% block content %} +
+
+
+ + + + + + + + + + + + + + + + + + {% for test in tests %} + + + + + + + + + + + {% if test.status == 0%} + + {% elif test.status == 1%} + + {% elif test.status == 2%} + + {% elif test.status == 3%} + + {% elif test.status == 4%} + + {% endif %} + + + {% endfor %} + +
#NameEmailGenderAgePhoneEdu QualificationOccupationCategoryStatusGrade
{{forloop.counter}}{{test.student.user.first_name | title}} {{test.student.user.last_name | title}}{{test.student.user.email}}{{test.student.gender | title}}{{test.student.dob | timesince}}{{test.student.phone}}{{test.student.edu_qualification}}{{test.student.occupation}}{{test.student.category}}OpenAttendance MarkedOngoingCompleted by StudentClosed by VLE{{test.mdlgrade}}
+
+
+
+
+
+{% endblock %} +{% block script %} + + + + +{% endblock %} \ No newline at end of file diff --git a/csc/templates/stats/stats.html b/csc/templates/stats/stats.html index 80db1cb..754c351 100644 --- a/csc/templates/stats/stats.html +++ b/csc/templates/stats/stats.html @@ -71,6 +71,18 @@

{{total_certificate_course}}

+
+
+

Total Tests Conducted

+

{{total_test_conducted}}

+
+
+
+
+

Total Upcoming Tests

+

{{total_upcoming_tests}}

+
+
diff --git a/csc/templates/stats/stats_base.html b/csc/templates/stats/stats_base.html index 357ccb4..67dc03c 100644 --- a/csc/templates/stats/stats_base.html +++ b/csc/templates/stats/stats_base.html @@ -132,6 +132,12 @@
Search VLE
District Plan Date of Joining + Total Tests @@ -114,6 +115,7 @@
Search VLE
{{vle.csc.district}} {{vle.csc.plan}} {{vle.user.date_joined}} + {{vle.test__count}} {% endfor %} @@ -155,6 +157,16 @@
VLE De Total Students :

+
+

+ Conducted Tests : +

+
+
+

+ Upcoming Tests : +

+
@@ -244,6 +256,8 @@
VLE De document.getElementById("pr_district").innerHTML = data['district']; document.getElementById("pin").innerHTML = data['pin']; document.getElementById("total_students").innerHTML = data['total_students']; + document.getElementById("conducted_test").innerHTML = data['conducted_test']; + document.getElementById("upcoming_test").innerHTML = data['upcoming_test']; $("#tb_students tr").remove(); var tb_students = document.getElementById("tb_students"); diff --git a/csc/vle_urls.py b/csc/vle_urls.py index 6a344f3..254f839 100644 --- a/csc/vle_urls.py +++ b/csc/vle_urls.py @@ -25,6 +25,7 @@ path('detail_test/', TestDetailView.as_view(), name="detail_test"), # path('update_test/', TestUpdateView.as_view(), name="update_test"), path('update_test/', update_test, name="update_test"), + path('test_students/', test_students, name="test_students"), path('delete_test/', TestDeleteView.as_view(), name="delete_test"), path('list_test/', TestListView.as_view(), name="list_test"), path('invigilator/', invigilator, name="invigilator"), diff --git a/csc/vle_views.py b/csc/vle_views.py index ef80e3e..7e5b368 100644 --- a/csc/vle_views.py +++ b/csc/vle_views.py @@ -648,10 +648,16 @@ def test_assign(request): def test_list(request): context = {} vle = VLE.objects.get(user=request.user) - tests = Test.objects.filter(vle=vle) + tests = Test.objects.filter(vle=vle).annotate(upcoming_students = Count('csctestatttendance', distinct=True, filter=Q(csctestatttendance__status__lte=2)), appeared_students = Count('csctestatttendance', distinct=True, filter=Q(csctestatttendance__status__gt=2))) context['tests'] = tests return render(request,'csc/test_list.html',context) +def test_students(request, pk): + context = {} + tests = CSCTestAtttendance.objects.filter(test=pk) + context['tests'] = tests + return render(request,'csc/test_students.html', context) + def update_test(request,pk): context = {} if request.method == 'GET': diff --git a/spokenlogin/templates/registration/change.html b/spokenlogin/templates/registration/change.html index 1ed27a2..3ebf369 100644 --- a/spokenlogin/templates/registration/change.html +++ b/spokenlogin/templates/registration/change.html @@ -1,7 +1,7 @@ {% extends 'spoken/base.html' %} {% load crispy_forms_tags %} {% block content %} -
+
{% include 'spokenlogin/messages.html' %}

Change Password

diff --git a/spokenlogin/templates/registration/password.html b/spokenlogin/templates/registration/password.html index a59d379..f4c7bbe 100644 --- a/spokenlogin/templates/registration/password.html +++ b/spokenlogin/templates/registration/password.html @@ -1,7 +1,7 @@ {% extends 'spoken/base.html' %} {% load crispy_forms_tags %} {% block content %} -
+
{% include 'spokenlogin/messages.html' %}

Forget Password

diff --git a/spokenlogin/templates/spokenlogin/messages.html b/spokenlogin/templates/spokenlogin/messages.html index 551d132..0388598 100644 --- a/spokenlogin/templates/spokenlogin/messages.html +++ b/spokenlogin/templates/spokenlogin/messages.html @@ -1,7 +1,7 @@
{% if messages %} {% for message in messages %} -
+
{{ message|safe }}
{% endfor %} diff --git a/spokenlogin/views.py b/spokenlogin/views.py index 2600b2e..6508e82 100644 --- a/spokenlogin/views.py +++ b/spokenlogin/views.py @@ -1,5 +1,6 @@ from django.shortcuts import render, redirect from django.contrib.auth.models import User +from django.contrib.auth.decorators import login_required from csc.api.utility import send_pwd_mail from django.contrib import messages @@ -11,20 +12,26 @@ def password(request): user = User.objects.get(username=email) send_pwd_mail(user) messages.add_message(request, messages.SUCCESS, 'Password Mail Sent Successfully.') - return redirect('/') + return redirect('/accounts/login') except User.DoesNotExist: - messages.add_message(request, messages.WARNING, 'User DoesNotExist.') - return redirect('/') + messages.add_message(request, messages.ERROR, 'User Does Not Exist.') + return redirect('/accounts/login') return render(request, 'registration/password.html') +@login_required(login_url='/accounts/login') def change(request): if request.method == 'POST': user = User.objects.get(username=request.user.username) new = request.POST['new'] confirm = request.POST['confirm'] - if new == confirm: + if new != confirm: + messages.add_message(request, messages.ERROR, 'Password did not match.') + elif len(new) < 8: + messages.add_message(request, messages.ERROR, 'Password should be 8 characters long.') + elif not str(new).isalnum(): + messages.add_message(request, messages.ERROR, 'Password should contain only numbers and letters.') + else: user.set_password(new) user.save() - messages.add_message(request, messages.SUCCESS, 'Password Changed Successfully') - return redirect('/') + messages.add_message(request, messages.SUCCESS, 'Password Changed Successfully') return render(request, 'registration/change.html')