From d38a4be0bd67a989f6f93f791aa280a3debf7eda Mon Sep 17 00:00:00 2001 From: ayishanishana21 Date: Fri, 7 Nov 2025 15:11:21 +0530 Subject: [PATCH 1/8] Update training request template and logic in viewsv2 --- events/templates/training_request.html | 21 ++++---- events/viewsv2.py | 74 ++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 20 deletions(-) diff --git a/events/templates/training_request.html b/events/templates/training_request.html index eefa160f..e2bccdc7 100644 --- a/events/templates/training_request.html +++ b/events/templates/training_request.html @@ -142,6 +142,10 @@ {% render_field form.fossmdlmap class+="form-control fossmdlmap" tabindex="1" %} {{ form.fossmdlmap.errors }} + +
@@ -394,28 +398,25 @@ } }); -// Helper function to load language/level options // Helper function to load language/level options function loadLanguageLevelOptions(foss_category, course_id) { - console.log('Loading language/level options...1'); - + var batch_id = $('.batch').val(); + $.ajax({ url: "/software-training/get-language-level-option/", type: "POST", data: { foss_category: foss_category, - course_id: course_id || '' - }, - beforeSend: function() { + course_id: course_id || '', + batch_id: batch_id || '' }, success: function(res) { - console.log('Language/Level response:', res); - $('#id_fossmdlmap').html(res.fossmdl); - $('.language-level-fields').show(); + $('#id_fossmdlmap').html(res.fossmdl); + $('.language-level-fields').show(); }, error: function(xhr, status, error) { console.error('Error loading language/level:', error); - $('.language-level-fields').show(); + $('.language-level-fields').hide(); } }); } diff --git a/events/viewsv2.py b/events/viewsv2.py index a9c6162a..26c5129b 100755 --- a/events/viewsv2.py +++ b/events/viewsv2.py @@ -76,6 +76,8 @@ from donate.utils import send_transaction_email from .certificates import * +from spoken.config import BASIC_LEVEL_INSTITUTIONS + class JSONResponseMixin(object): """ A mixin that can be used to render a JSON response. @@ -177,35 +179,87 @@ def get_next_planner(self, current_planner): print(e) return False + @csrf_exempt def get_language_level_option(request): """ AJAX endpoint that returns HTML for language and level ' + + # Determine institution type from batch + include_basic = False + if batch_id: + try: + batch = StudentBatch.objects.get(id=batch_id) + inst_type_id = batch.academic.institution_type.id + if inst_type_id in BASIC_LEVEL_INSTITUTIONS: + include_basic = True + except StudentBatch.DoesNotExist: + pass + + # Fetch FOSS levels for the selected course + if course_id: + cm = CourseMap.objects.get(id=course_id) + fmdl = FossMdlCourses.objects.filter(foss_id=cm.foss_id) + + # ✅ Filter options dynamically based on institution type + for item in fmdl: + item_name = str(item).strip().lower() + # Skip "Basic" for non-school/NGO/Eka institutions + if not include_basic and "basic" in item_name: + continue + fmdl_options += f'' data['fossmdl'] = fmdl_options return JsonResponse(data) + except Exception as e: - print(f"\033[91m Exception : {e} \033[0m") + print(f"\033[91m Exception in get_language_level_option: {e} \033[0m") return JsonResponse(data) +# @csrf_exempt +# def get_language_level_option(request): +# """ +# AJAX endpoint that returns HTML for language and level ' + +# data['fossmdl'] = fmdl_options +# return JsonResponse(data) +# except Exception as e: +# print(f"\033[91m Exception : {e} \033[0m") +# return JsonResponse(data) + + class StudentBatchCreateView(CreateView): form_class = None template_name = None From 888fa880a884f781a7101592344794d5d700b238 Mon Sep 17 00:00:00 2001 From: ayishanishana21 Date: Fri, 7 Nov 2025 16:00:23 +0530 Subject: [PATCH 2/8] Address PR review feedback: updated text, removed commented code, and cleaned function --- events/templates/training_request.html | 35 +---- events/viewsv2.py | 181 ------------------------- 2 files changed, 5 insertions(+), 211 deletions(-) diff --git a/events/templates/training_request.html b/events/templates/training_request.html index e2bccdc7..f17232d4 100644 --- a/events/templates/training_request.html +++ b/events/templates/training_request.html @@ -142,10 +142,7 @@ {% render_field form.fossmdlmap class+="form-control fossmdlmap" tabindex="1" %} {{ form.fossmdlmap.errors }} - - +
@@ -195,8 +192,6 @@ if($('.department').val() == '') { $('.course_type').val(''); $('.course_type').prop('disabled', 'disabled'); - // $('.course').html(''); - // $('.course').prop('disabled', 'disabled'); } @@ -299,17 +294,14 @@ training_planner: $('.training-planner').val() }, beforeSend: function() { - //$('.ajax-refresh-language').show(); }, success: function(data) { - // loading languages if(data && data['batch_status']) { $('.course_type').prop('disabled', false); } else { $('.batch').val(''); alert('No. of training requests for selected batch exceeded.'); } - //$('.ajax-refresh-language').hide(); } }); } @@ -329,31 +321,24 @@ department: department, }, beforeSend: function() { - //$('.ajax-refresh-language').show(); }, success: function(data) { - // loading languages + if(data && data['batch_option']) { $('.batch').html(data['batch_option']); } - //$('.ajax-refresh-language').hide(); } }); } }); $('.course').html(''); - // When FOSS category changes - $('.foss_category').on('change', function() { - var foss_category = $(this).val(); - // console.log('FOSS Category changed:', foss_category); - + var foss_category = $(this).val(); $('#course_label').html("Course list loading..."); - $('.language-level-fields').hide(); // Hide by default + $('.language-level-fields').hide(); if (foss_category != '') { - // Fetch course options $.ajax({ url: "/software-training/get-course-option/", type: "POST", @@ -365,15 +350,11 @@ if (data && data['course_option']) { $('.course').html(data['course_option']); } - - // Show language/level only for "Training and Test" (value '1') + if (foss_category == '1') { - // console.log('Showing language/level fields for Training and Test'); - // Load language/level options when category is Training and Test var course_id = $('.course').val(); loadLanguageLevelOptions(foss_category, course_id); } else { - // console.log('Hiding language/level fields'); $('.language-level-fields').hide(); } }, @@ -386,19 +367,14 @@ } }); -// When course selection changes $('.course').on('change', function() { var foss_category = $('.foss_category').val(); var course_id = $(this).val(); - // console.log('Course changed - FOSS:', foss_category, 'Course ID:', course_id); - - // Only load language/level if FOSS category is Training and Test if (foss_category == '1') { loadLanguageLevelOptions(foss_category, course_id); } }); -// Helper function to load language/level options function loadLanguageLevelOptions(foss_category, course_id) { var batch_id = $('.batch').val(); @@ -421,7 +397,6 @@ }); } -// On page load, check if we need to show language/level fields $(document).ready(function() { var initialFossCategory = $('.foss_category').val(); if (initialFossCategory == '1') { diff --git a/events/viewsv2.py b/events/viewsv2.py index 26c5129b..167c79be 100755 --- a/events/viewsv2.py +++ b/events/viewsv2.py @@ -192,14 +192,9 @@ def get_language_level_option(request): foss_category = request.POST.get('foss_category', '').strip() course_id = request.POST.get('course_id', '').strip() batch_id = request.POST.get('batch_id', '').strip() - - # Show language/level only for "Training and Test" if foss_category != '1': return JsonResponse(data) - fmdl_options = '' - - # Determine institution type from batch include_basic = False if batch_id: try: @@ -209,16 +204,11 @@ def get_language_level_option(request): include_basic = True except StudentBatch.DoesNotExist: pass - - # Fetch FOSS levels for the selected course if course_id: cm = CourseMap.objects.get(id=course_id) fmdl = FossMdlCourses.objects.filter(foss_id=cm.foss_id) - - # ✅ Filter options dynamically based on institution type for item in fmdl: item_name = str(item).strip().lower() - # Skip "Basic" for non-school/NGO/Eka institutions if not include_basic and "basic" in item_name: continue fmdl_options += f'' @@ -230,36 +220,6 @@ def get_language_level_option(request): print(f"\033[91m Exception in get_language_level_option: {e} \033[0m") return JsonResponse(data) - -# @csrf_exempt -# def get_language_level_option(request): -# """ -# AJAX endpoint that returns HTML for language and level ' - -# data['fossmdl'] = fmdl_options -# return JsonResponse(data) -# except Exception as e: -# print(f"\033[91m Exception : {e} \033[0m") -# return JsonResponse(data) - - class StudentBatchCreateView(CreateView): form_class = None template_name = None @@ -1263,147 +1223,6 @@ def post(self, request, *args, **kwargs): } return self.render_to_json_response(context) - -# class TrainingRequestListView(ListView): -# queryset = None -# paginate_by = 20 -# user = None -# template_name = None -# header = None -# raw_get_data = None -# role = None -# status = None -# now= datetime.now() -# year = now.year -# month =now.month - -# current_sem_type_even = 0 #odd -# if month < 6: -# current_sem_type_even = 1 #even - -# prev_sem_type = 'even' -# prev_sem_year = year -# if current_sem_type_even: -# prev_sem_type = 'odd' -# prev_sem_year = (year - 1) -# prev_sem_start_date, prev_sem_end_date = get_prev_semester_duration(prev_sem_type, prev_sem_year) - -# @method_decorator(group_required("Resource Person","Administrator")) -# def dispatch(self, *args, **kwargs): -# if (not 'role' in kwargs) or (not 'status' in kwargs): -# raise PermissionDenied() -# self.role = kwargs['role'] -# self.status = kwargs['status'] -# status_list = {'pending': 0, 'completed': 1, 'markcomplete':2, 'pendingattendance':3} -# roles = ['rp', 'em'] -# self.user = self.request.user -# if self.role in roles and self.status in status_list: -# if self.status == 'completed': -# self.queryset = TrainingRequest.objects.filter( -# training_planner__academic_id__in=AcademicCenter.objects.filter( -# state__in = State.objects.filter( -# resourceperson__user_id=self.user, -# resourceperson__status=1 -# ) -# ).values_list('id'), -# status=1, -# participants__gt=0 -# ).order_by('-updated') -# elif self.status == 'pending': -# self.queryset = TrainingRequest.objects.filter( -# training_planner__academic_id__in=AcademicCenter.objects.filter( -# state__in = State.objects.filter( -# resourceperson__user_id=self.user, -# resourceperson__status=1 -# ) -# ).values_list('id'), -# status=0 -# ).order_by('-updated') -# elif self.status == 'markcomplete': -# if is_administrator(self.user): -# self.queryset = TrainingRequest.objects.filter(status=2).order_by('-updated') -# else: -# self.queryset = TrainingRequest.objects.filter( -# training_planner__academic_id__in=AcademicCenter.objects.filter( -# state__in = State.objects.filter( -# resourceperson__user_id=self.user, -# resourceperson__status=1 -# ) -# ).values_list('id'), -# status=2 -# ).order_by('-updated') -# elif self.status == 'pendingattendance': -# self.queryset = TrainingRequest.objects.filter( -# training_planner__academic_id__in=AcademicCenter.objects.filter( -# state__in = State.objects.filter( -# resourceperson__user_id=self.user, -# resourceperson__status=1, -# ) -# ).values_list('id'), -# status = 1, participants = 0, training_planner__semester__name = self.prev_sem_type , sem_start_date__gte = self.prev_sem_start_date -# ) - -# self.header = { -# 1: SortableHeader('#', False), -# 2: SortableHeader( -# 'training_planner__academic__state__name', -# True, -# 'State' -# ), -# 3: SortableHeader( -# 'training_planner__academic__academic_code', -# True, -# 'Code' -# ), -# 4: SortableHeader( -# 'training_planner__academic__institution_name', -# True, -# 'Institution' -# ), -# 5: SortableHeader('batch__department__name', True, 'Department / Batch'), -# 6: SortableHeader('course__foss__foss', True, 'Course Name'), -# 7: SortableHeader('course_type', True, 'Course Type'), -# 8: SortableHeader( -# 'training_planner__organiser__user__first_name', -# True, -# 'Organiser' -# ), -# 9: SortableHeader( -# 'sem_start_date', -# True, -# 'Sem Start Date / Training Date' -# ), -# 10: SortableHeader('participants', True, 'Participants'), -# #11: SortableHeader('Action', False) -# } -# self.raw_get_data = self.request.GET.get('o', None) -# self.queryset = get_sorted_list( -# self.request, -# self.queryset, -# self.header, -# self.raw_get_data -# ) -# if self.status == 'completed': -# self.queryset.qs = TrainingRequestFilter(self.request.GET, queryset=self.queryset, user=self.user, rp_completed=True) -# elif self.status == 'pending': -# self.queryset.qs = TrainingRequestFilter(self.request.GET, queryset=self.queryset, user=self.user, rp_ongoing=True) -# elif self.status == 'markcomplete': -# self.queryset.qs = TrainingRequestFilter(self.request.GET, queryset=self.queryset, user=self.user, rp_markcomplete=True) -# elif self.status == 'pendingattendance': -# self.queryset.qs = TrainingRequestFilter(self.request.GET, queryset=self.queryset, user=self.user, rp_pendingattendance=True) -# else: -# raise PermissionDenied() -# return super(TrainingRequestListView, self).dispatch(*args, **kwargs) - -# def get_context_data(self, **kwargs): -# context = super(TrainingRequestListView, self).get_context_data(**kwargs) -# context['form'] = self.queryset.qs.form -# context['collection'] = self.queryset.qs -# context['role'] = self.role -# context['status'] = self.status -# context['header'] = self.header -# context['ordering'] = get_field_index(self.raw_get_data) -# return context class TrainingRequestListView(ListView): queryset = None paginate_by = 20 From 37ed8dc9b9f6ea5ffa4b40f5db94f4998dd01948 Mon Sep 17 00:00:00 2001 From: ayishanishana21 Date: Tue, 18 Nov 2025 15:43:25 +0530 Subject: [PATCH 3/8] Fix: Updated events/views.py for reset student password --- events/views.py | 141 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 110 insertions(+), 31 deletions(-) diff --git a/events/views.py b/events/views.py index 970809c1..888ff1e8 100644 --- a/events/views.py +++ b/events/views.py @@ -1,4 +1,5 @@ from django.http import JsonResponse +from django.http import HttpResponseForbidden from .models import StudentBatch from django.urls import reverse @@ -3262,43 +3263,121 @@ def handover(request): return render(request, 'handover.html', context) -def reset_student_pwd(request): - context = {} - template = 'events/templates/reset_student_password.html' - form = StudentPasswordResetForm() - context['form'] = form +# def reset_student_pwd(request): +# context = {} +# template = 'events/templates/reset_student_password.html' +# form = StudentPasswordResetForm() +# context['form'] = form - if request.method == "POST": - form = StudentPasswordResetForm(request.POST) - context['form'] = form +# if request.method == "POST": +# form = StudentPasswordResetForm(request.POST) +# context['form'] = form - if form.is_valid(): - school = form.cleaned_data['school'] - batches = form.cleaned_data['batches'] - new_password = form.cleaned_data['new_password'] +# if form.is_valid(): +# school = form.cleaned_data['school'] +# batches = form.cleaned_data['batches'] +# new_password = form.cleaned_data['new_password'] - batch_ids = [x.id for x in batches] - batches = StudentBatch.objects.filter(id__in=batch_ids) - student_ids = StudentMaster.objects.filter(batch__in=batches).values_list('student_id', flat=True) - students = Student.objects.filter(id__in=student_ids) - students.update(verified=1, error=0) - user_ids = [stu.user_id for stu in students] - users = User.objects.filter(id__in=user_ids) - new_hashed_pwd = make_password(new_password) - users.update(password=new_hashed_pwd, is_active=1) - emails = [user.email for user in users] - mdlUsers = MdlUser.objects.filter(email__in=emails) - mdlUsers.update(password=encript_password(new_password)) - send_bulk_student_reset_mail(school,batches,users.count(), new_password,request.user) +# batch_ids = [x.id for x in batches] +# batches = StudentBatch.objects.filter(id__in=batch_ids) +# student_ids = StudentMaster.objects.filter(batch__in=batches).values_list('student_id', flat=True) +# students = Student.objects.filter(id__in=student_ids) +# students.update(verified=1, error=0) +# user_ids = [stu.user_id for stu in students] +# users = User.objects.filter(id__in=user_ids) +# new_hashed_pwd = make_password(new_password) +# users.update(password=new_hashed_pwd, is_active=1) +# emails = [user.email for user in users] +# mdlUsers = MdlUser.objects.filter(email__in=emails) +# mdlUsers.update(password=encript_password(new_password)) +# send_bulk_student_reset_mail(school,batches,users.count(), new_password,request.user) - # Add the success message - success_msg = "Password updated for {} students.".format(users.count()) - messages.success(request, success_msg) +# # Add the success message +# success_msg = "Password updated for {} students.".format(users.count()) +# messages.success(request, success_msg) - redirect_url = reverse('events:reset_student_pwd') - return HttpResponseRedirect(redirect_url) - return render(request,template,context) +# redirect_url = reverse('events:reset_student_pwd') +# return HttpResponseRedirect(redirect_url) +# return render(request,template,context) + + + +def reset_student_pwd(request): + + # 1. ROLE VALIDATION ------------------------------- + if not request.user.groups.filter(name="School Training Manager").exists(): + return HttpResponseForbidden("You are not allowed to access this page.") + + + template = 'events/templates/reset_student_password.html' + form = StudentPasswordResetForm(request.POST or None) + + if request.method == "POST" and form.is_valid(): + + school = form.cleaned_data['school'] + batches = form.cleaned_data['batches'] + new_password = form.cleaned_data['new_password'] + + # 2. SECURITY FIX — ensure all batches belong to the selected school + for b in batches: + if b.school_id != school.id: + return HttpResponseForbidden("Invalid batch selected.") + + batch_ids = batches.values_list("id", flat=True) + + # 3. Get student IDs efficiently + student_ids = StudentMaster.objects.filter( + batch_id__in=batch_ids + ).values_list('student_id', flat=True) + + # 4. Update Student table in bulk + Student.objects.filter(id__in=student_ids).update( + verified=1, + error=0 + ) + + # 5. Get User IDs linked to these students + user_ids = Student.objects.filter( + id__in=student_ids + ).values_list("user_id", flat=True) + + # 6. Update Django User passwords in bulk + hashed_pwd = make_password(new_password) + User.objects.filter(id__in=user_ids).update( + password=hashed_pwd, + is_active=1 + ) + + # 7. Fetch emails efficiently + emails = User.objects.filter( + id__in=user_ids + ).values_list("email", flat=True) + + # 8. Update Moodle users password + MdlUser.objects.filter(email__in=emails).update( + password=encript_password(new_password) + ) + + # 9. Send email once (not inside loop) + send_bulk_student_reset_mail( + school=school, + batches=batches, + total_students=len(student_ids), + new_password=new_password, + user=request.user + ) + + messages.success( + request, + f"Password updated for {len(student_ids)} students." + ) + + return redirect("events:reset_student_pwd") + + return render(request, template, {"form": form}) + + def get_schools(request): From d6e805042158ab9970f08b25f93bbdba86642f74 Mon Sep 17 00:00:00 2001 From: ayishanishana21 Date: Thu, 20 Nov 2025 12:59:38 +0530 Subject: [PATCH 4/8] Add notify_users command and update cms models --- cms/management/commands/notify_users.py | 133 ++++++++++++++++++++++++ cms/models.py | 14 ++- 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 cms/management/commands/notify_users.py diff --git a/cms/management/commands/notify_users.py b/cms/management/commands/notify_users.py new file mode 100644 index 00000000..7e648e63 --- /dev/null +++ b/cms/management/commands/notify_users.py @@ -0,0 +1,133 @@ +from django.core.management.base import BaseCommand +from django.core.mail import EmailMultiAlternatives +from django.conf import settings +from django.contrib.auth.models import User +from django.db import transaction +from datetime import datetime, timedelta +import smtplib +from cms.models import EmailLog + + +class Command(BaseCommand): + help = "Notify users inactive for more than X years or before a given cutoff date." + + def add_arguments(self, parser): + + parser.add_argument( + "--years", + type=int, + default=5, + help="Check inactivity older than this many years (default = 5). Ignored if --cutoff-date provided.", + ) + + parser.add_argument( + "--limit", + type=int, + default=None, + help="Limit number of users to notify", + ) + + parser.add_argument( + "--cutoff-date", + type=str, + default=None, + help="Custom cutoff date in YYYY-MM-DD format (overrides --years)", + ) + + @transaction.atomic + def handle(self, *args, **options): + + years = options.get("years") + limit = options.get("limit") + cutoff_input = options.get("cutoff_date") + + if cutoff_input: + try: + cutoff_date = datetime.strptime(cutoff_input, "%Y-%m-%d") + except ValueError: + self.stdout.write(self.style.ERROR( + "❌ Invalid cutoff date format! Use YYYY-MM-DD" + )) + return + else: + cutoff_date = datetime.now() - timedelta(days=years * 365) + + cutoff_str = cutoff_date.strftime("%Y-%m-%d") + self.stdout.write(self.style.WARNING( + f"\n📅 Using cutoff date: {cutoff_str} (YYYY-MM-DD)\n" + )) + + users = User.objects.filter( + last_login__lt=cutoff_date, + is_active=True + ).order_by("id") + + if limit: + users = users[:limit] + + total_users = users.count() + self.stdout.write(self.style.NOTICE( + f"🔎 Users inactive since before {cutoff_str}: {total_users}\n" + )) + + subject = "Reminder: Your account has been inactive for a long time" + + sent_count = 0 + failed_count = 0 + for user in users: + + message = f""" +Dear {user.first_name} {user.last_name}, + +Our system indicates that your account has not been used for a long time. + +Your last login was on: {user.last_login.strftime("%Y-%m-%d")} + +This is a reminder to log in again and continue using our services. + +If you need help, simply reply to this email. + +Regards, +Support Team +""" + + email = EmailMultiAlternatives( + subject, + message, + settings.NO_REPLY_EMAIL, + to=[user.email], + ) + + try: + email.send(fail_silently=False) + + sent_count += 1 + + EmailLog.objects.create( + user=user, + email=user.email, + status=True, + reason=None + ) + + self.stdout.write(self.style.SUCCESS(f"[SENT] {user.email}")) + + except (smtplib.SMTPException, Exception) as e: + + failed_count += 1 + + EmailLog.objects.create( + user=user, + email=user.email, + status=False, + reason=str(e) + ) + + self.stdout.write(self.style.ERROR(f"[FAILED] {user.email} → {e}")) + + self.stdout.write("\n---------------------------------------") + self.stdout.write(self.style.SUCCESS(f"Emails Sent: {sent_count}")) + self.stdout.write(self.style.ERROR(f"Failed: {failed_count}")) + self.stdout.write(self.style.WARNING(f"Total Processed: {total_users}")) + self.stdout.write(self.style.NOTICE(f"Cutoff Date Used: {cutoff_str}")) + self.stdout.write("---------------------------------------\n") diff --git a/cms/models.py b/cms/models.py index 517b6b25..557d40f8 100644 --- a/cms/models.py +++ b/cms/models.py @@ -150,4 +150,16 @@ class UserType(models.Model): ilw = jsonfield.JSONField(null=True) status = models.CharField(choices=STATUS_CHOICES,max_length=25,default=1) created = models.DateTimeField(auto_now_add=True) - updated = models.DateTimeField(auto_now=True) \ No newline at end of file + updated = models.DateTimeField(auto_now=True) + + + +class EmailLog(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + email = models.EmailField() + sent_time = models.DateTimeField(auto_now_add=True) + status = models.BooleanField(default=False) + reason = models.TextField(null=True, blank=True) + + def __str__(self): + return f"{self.email} - {'Success' if self.status else 'Failed'}" From b5e422e6bdb0817ac3bf4bf6154f049b5ebab7ce Mon Sep 17 00:00:00 2001 From: ayishanishana21 Date: Fri, 21 Nov 2025 20:04:46 +0530 Subject: [PATCH 5/8] Added ilwmdlcourse in the training form --- training/forms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/training/forms.py b/training/forms.py index 4464a5e7..45206aa6 100644 --- a/training/forms.py +++ b/training/forms.py @@ -15,7 +15,8 @@ class CreateTrainingEventForm(forms.ModelForm): ilw_course = forms.CharField(required=False) event_coordinator_email = forms.CharField(required = False) event_coordinator_contact_no = forms.CharField(required = False) - foss_data = forms.ModelMultipleChoiceField(queryset=FossCategory.objects.filter(id__in=CourseMap.objects.filter(category=0, test=1).values('foss_id'))) + # foss_data = forms.ModelMultipleChoiceField(queryset=FossCategory.objects.filter(id__in=CourseMap.objects.filter(category=0, test=1).values('foss_id'))) + foss_data = forms.ModelMultipleChoiceField(queryset=FossCategory.objects.filter(id__in=ILWFossMdlCourses.objects.exclude(foss__isnull=True).values_list('foss_id', flat=True).distinct()),required=False) city = forms.ModelChoiceField(queryset=City.objects.none(), required=False) host_college = forms.ModelChoiceField(queryset=AcademicCenter.objects.none(), required=False) From 9ac132cd58c2c1e516cc3a4ad4c88631b1274b26 Mon Sep 17 00:00:00 2001 From: ayishanishana21 Date: Wed, 26 Nov 2025 23:55:42 +0530 Subject: [PATCH 6/8] Updated 15 month option in academic payment form --- events/formsv2.py | 4 +++- events/models.py | 5 ++--- events/templates/academic_payment_details_form.html | 7 ++++--- events/viewsv2.py | 3 +-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/events/formsv2.py b/events/formsv2.py index 27f15466..9f798a28 100644 --- a/events/formsv2.py +++ b/events/formsv2.py @@ -7,6 +7,7 @@ from events.models import * from events.helpers import get_academic_years from cms.validators import validate_csv_file +from spoken.config import SUBSCRIPTION_CHOICES class StudentBatchForm(forms.ModelForm): year = forms.ChoiceField(choices = get_academic_years()) @@ -668,4 +669,5 @@ class Meta(object): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['college_type'].widget.attrs.update({'class': 'form-control', 'readonly': 'readonly'}) - self.fields['payment_status'].widget.attrs.update({'class': 'form-control', 'readonly': 'readonly'}) \ No newline at end of file + self.fields['payment_status'].widget.attrs.update({'class': 'form-control', 'readonly': 'readonly'}) + self.fields['subscription'].choices = SUBSCRIPTION_CHOICES \ No newline at end of file diff --git a/events/models.py b/events/models.py index a7e59a6d..6423db28 100755 --- a/events/models.py +++ b/events/models.py @@ -24,6 +24,7 @@ #creation app models from creation.models import FossAvailableForWorkshop, FossAvailableForTest +from spoken.config import SUBSCRIPTION_CHOICES PAYMENT_STATUS_CHOICES =( @@ -32,9 +33,7 @@ COLLEGE_TYPE_CHOICES =( ('', '-----'), ('Engg', 'Engg'), ('ASC', 'ASC'), ('Polytechnic', 'Polytechnic'), ('University', 'University'), ('School', 'School') ) -SUBSCRIPTION_CHOICES = ( - ('', '-----'), ('365', 'One_Year'), ('182', 'Six_Months') - ) + # Create your models here. diff --git a/events/templates/academic_payment_details_form.html b/events/templates/academic_payment_details_form.html index e36108a0..bd18b556 100644 --- a/events/templates/academic_payment_details_form.html +++ b/events/templates/academic_payment_details_form.html @@ -269,9 +269,10 @@ if(type == 365){ $('#id_amount').val(29500) }else if(type == 182){ - $('#id_amount').val(14750) - - } + $('#id_amount').val(14750) + }else if(type == 455){ + $('#id_amount').val(29500) + } }) diff --git a/events/viewsv2.py b/events/viewsv2.py index 167c79be..f05d0c90 100755 --- a/events/viewsv2.py +++ b/events/viewsv2.py @@ -23,7 +23,7 @@ from django.db import IntegrityError from django.utils.decorators import method_decorator from events.decorators import group_required -from events import display +# from events import display from events.forms import StudentBatchForm, TrainingRequestForm, \ TrainingRequestEditForm, CourseMapForm, SingleTrainingForm, \ OrganiserFeedbackForm,STWorkshopFeedbackForm,STWorkshopFeedbackFormPre,STWorkshopFeedbackFormPost,LearnDrupalFeedbackForm, LatexWorkshopFileUploadForm, UserForm, \ @@ -75,7 +75,6 @@ from django.db import connection from donate.utils import send_transaction_email from .certificates import * - from spoken.config import BASIC_LEVEL_INSTITUTIONS class JSONResponseMixin(object): From 4ea88381ad06c5319829eaa83e197d399fa934af Mon Sep 17 00:00:00 2001 From: ayishanishana21 Date: Mon, 1 Dec 2025 16:35:15 +0530 Subject: [PATCH 7/8] added caches page --- cms/cache_registry.py | 17 +++ cms/cacheurls.py | 6 ++ cms/templates/cms/cache_tools.html | 57 ++++++++++ cms/urls.py | 3 +- cms/views.py | 47 ++++++++ spoken/helpers.py | 10 ++ spoken/settings.py | 168 +++++++++++++++++------------ spoken/urls.py | 21 +++- 8 files changed, 256 insertions(+), 73 deletions(-) create mode 100644 cms/cache_registry.py create mode 100644 cms/cacheurls.py create mode 100644 cms/templates/cms/cache_tools.html diff --git a/cms/cache_registry.py b/cms/cache_registry.py new file mode 100644 index 00000000..5d11a3e7 --- /dev/null +++ b/cms/cache_registry.py @@ -0,0 +1,17 @@ +from django.core.cache import cache + +REGISTRY_KEY = "_cache_key_registry" + +def register_cache_key(key): + keys = cache.get(REGISTRY_KEY) or set() + keys.add(key) + cache.set(REGISTRY_KEY, keys, None) + +def unregister_cache_key(key): + keys = cache.get(REGISTRY_KEY) or set() + if key in keys: + keys.remove(key) + cache.set(REGISTRY_KEY, keys, None) + +def list_cache_keys(): + return sorted(cache.get(REGISTRY_KEY) or []) diff --git a/cms/cacheurls.py b/cms/cacheurls.py new file mode 100644 index 00000000..e0d63313 --- /dev/null +++ b/cms/cacheurls.py @@ -0,0 +1,6 @@ +from django.conf.urls import url +from cms import views + +urlpatterns = [ + url(r'^cache-tools/$', views.cache_tools, name='cache-tools'), +] diff --git a/cms/templates/cms/cache_tools.html b/cms/templates/cms/cache_tools.html new file mode 100644 index 00000000..40b03d24 --- /dev/null +++ b/cms/templates/cms/cache_tools.html @@ -0,0 +1,57 @@ +{% extends "base.html" %} + +{% block content %} +
+

Memcache Tools

+ + {% for message in messages %} +
{{ message }}
+ {% endfor %} + + +

Existing Cache Keys (via Memcached slabs)

+
    + {% for k in keys %} +
  • {{ k }}
  • + {% empty %} +
  • No keys found or Memcached restricts visibility.
  • + {% endfor %} +
+ +
+ + +
+ {% csrf_token %} + + + +
+ + {% if value_output %} +
+ Key Value:
+ {{ value_output|safe }} +
+ {% endif %} + +
+ + +
+ {% csrf_token %} + + + +
+ +
+ + +
+ {% csrf_token %} + +
+ +
+{% endblock %} diff --git a/cms/urls.py b/cms/urls.py index 3cea0526..da3c7356 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -7,6 +7,7 @@ from spoken.sitemaps import SpokenStaticViewSitemap from donate.views import * + app_name = 'cms' spoken_sitemaps = { @@ -31,6 +32,6 @@ url(r'^sitemap\.xml/$', sitemap, {'sitemaps' : spoken_sitemaps } , name='spoken_sitemap'), url(r'^(?P.+)/$', dispatcher, name="dispatcher"), - + ] \ No newline at end of file diff --git a/cms/views.py b/cms/views.py index bd0ef45a..c1bbb594 100644 --- a/cms/views.py +++ b/cms/views.py @@ -29,6 +29,17 @@ from donate.models import Payee + +from django.contrib.admin.views.decorators import staff_member_required +from django.core.cache import caches +from django.shortcuts import render, redirect + +from cms.cache_registry import list_cache_keys, unregister_cache_key +from django.utils.safestring import mark_safe + + +cache = caches['default'] + def dispatcher(request, permalink=''): if permalink == '': return HttpResponseRedirect('/') @@ -504,3 +515,39 @@ def verify_email(request): else: messages.error(request, 'Invalid Email ID', extra_tags='error') return render(request, "cms/templates/verify_email.html", context) + + +@staff_member_required +def cache_tools(request): + + keys = list_cache_keys() + value_output = None + + if request.method == "POST": + + if "view_key" in request.POST: + key = request.POST.get("cache_key").strip() + val = cache.get(key) + print("dfghjkdfghjk",val) + + if val is None: + value_output = f"No value stored for key: '{key}'" + else: + value_output = mark_safe(f"
{val}
") + + elif "clear_key" in request.POST: + key = request.POST.get("cache_key").strip() + cache.delete(key) + unregister_cache_key(key) + messages.success(request, f"Key '{key}' deleted.") + return redirect("cache-tools") + + elif "clear_all" in request.POST: + cache.clear() + messages.success(request, "All cache cleared.") + return redirect("cache-tools") + + return render(request, "cms/cache_tools.html", { + "keys": keys, + "value_output": value_output + }) diff --git a/spoken/helpers.py b/spoken/helpers.py index 488ee112..4a2dae39 100644 --- a/spoken/helpers.py +++ b/spoken/helpers.py @@ -10,12 +10,16 @@ from events.models import Testimonials from cms.models import Notification, Event from .config import CACHE_RANDOM_TUTORIALS, CACHE_TR_REC, CACHE_TESTIMONIALS, CACHE_NOTIFICATIONS, CACHE_EVENTS +from cms.cache_registry import register_cache_key + # ---- 1. Random tutorials from TutorialSummaryCache ---- def get_home_random_tutorials(): cache_key = "home_random_tutorials" tutorials = cache.get(cache_key) + print("tuto",tutorials) if tutorials is not None: + print("tuturial exit",list(tutorials)) return tutorials try: ids = list( @@ -31,8 +35,10 @@ def get_home_random_tutorials(): "foss", "first_tutorial", "first_tutorial__tutorial_detail", "first_tutorial__language") ) cache.set(cache_key, tutorials, timeout=CACHE_RANDOM_TUTORIALS) # in sec + # register_cache_key(cache_key) except Exception: tutorials = [] + print("exceptionnnnn",tutorials) return tutorials @@ -51,6 +57,7 @@ def get_home_tr_rec(request=None): else: tr_rec = None cache.set(cache_key, tr_rec, timeout=CACHE_TR_REC) #seconds + register_cache_key(cache_key) except Exception as e: tr_rec = None if request is not None: @@ -66,6 +73,7 @@ def get_home_testimonials(): return testimonials testimonials = Testimonials.objects.all().order_by("?")[:2] cache.set(cache_key, testimonials, timeout=CACHE_TESTIMONIALS) # seconds + register_cache_key(cache_key) return testimonials # ---- 4. Notifications (shorter cache) ---- @@ -77,6 +85,7 @@ def get_home_notifications(): today = dt.datetime.today() notifications = Notification.objects.filter(Q(start_date__lte=today) & Q(expiry_date__gte=today)).order_by("expiry_date") cache.set(cache_key, notifications, timeout=CACHE_NOTIFICATIONS) + register_cache_key(cache_key) return notifications # ---- 5. Upcoming events ---- @@ -88,4 +97,5 @@ def get_home_events(): today = dt.datetime.today() events = Event.objects.filter(event_date__gte=today).order_by("event_date")[:2] cache.set(cache_key, events, timeout=CACHE_EVENTS) + register_cache_key(cache_key) return events diff --git a/spoken/settings.py b/spoken/settings.py index bd227578..977c7aca 100644 --- a/spoken/settings.py +++ b/spoken/settings.py @@ -72,6 +72,7 @@ 'django.contrib.redirects', 'django.contrib.sitemaps', 'django_extensions', + # 'debug_toolbar', 'widget_tweaks', 'captcha', 'nicedit', @@ -129,82 +130,85 @@ # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases -CONN_MAX_AGE = DB_CONN_MAX_AGE_DEFAULT +# CONN_MAX_AGE = DB_CONN_MAX_AGE_DEFAULT +CONN_MAX_AGE = 60 +DB_CONN_MAX_AGE_DEFAULT = 0 # connections close after each request +DB_CONN_MAX_AGE_FREQUENT = 60 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': DB, - 'USER': DB_USER, - 'PASSWORD': DB_PASS, - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', - "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, + 'NAME': 'ST_20Feb2023', + 'USER':'lisha', + 'PASSWORD': '1947', + 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + 'PORT': '3306', + # "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, }, - 'moodle': { - 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': MDB, # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': MDB_USER, - 'PASSWORD': MDB_PASS, - 'HOST': MDB_HOST, # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. - "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, - }, - 'ilwmoodle': { - 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': ILWMDB, # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': ILW_MDB_USER, - 'PASSWORD': ILW_MDB_PASS, - 'HOST': ILW_MDB_HOST, # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': ILW_MDB_PORT, # Set to empty string for default. - }, - 'cdeep': { - 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': CDB, # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': CDB_USER, - 'PASSWORD': CDB_PASS, - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. - }, - 'workshop_info': { - 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': WDB, # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': WDB_USER, - 'PASSWORD': WDB_PASS, - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. - }, - 'forums': { - 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': FDB, # Or path to database file if using sqlite3. - # The following settings are not used with sqlite3: - 'USER': FDB_USER, - 'PASSWORD': FDB_PASS, - 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '', # Set to empty string for default. - }, - 'healthdb': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': HN, - 'USER': HN_USER, - 'PASSWORD': HN_PASS, - 'HOST': HN_HOST, - 'PORT': HN_PORT, - }, - 'stats': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': STATS_DB, - 'USER': STATS_USER, - 'PASSWORD': STATS_PWD, - 'HOST': STATS_HOST, - 'PORT': STATS_PORT, - "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, - } + # 'moodle': { + # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + # 'NAME': MDB, # Or path to database file if using sqlite3. + # # The following settings are not used with sqlite3: + # 'USER': MDB_USER, + # 'PASSWORD': MDB_PASS, + # 'HOST': MDB_HOST, # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + # 'PORT': '', # Set to empty string for default. + # "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, + # }, + # 'ilwmoodle': { + # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + # 'NAME': ILWMDB, # Or path to database file if using sqlite3. + # # The following settings are not used with sqlite3: + # 'USER': ILW_MDB_USER, + # 'PASSWORD': ILW_MDB_PASS, + # 'HOST': ILW_MDB_HOST, # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + # 'PORT': ILW_MDB_PORT, # Set to empty string for default. + # }, + # 'cdeep': { + # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + # 'NAME': CDB, # Or path to database file if using sqlite3. + # # The following settings are not used with sqlite3: + # 'USER': CDB_USER, + # 'PASSWORD': CDB_PASS, + # 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + # 'PORT': '', # Set to empty string for default. + # }, + # 'workshop_info': { + # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + # 'NAME': WDB, # Or path to database file if using sqlite3. + # # The following settings are not used with sqlite3: + # 'USER': WDB_USER, + # 'PASSWORD': WDB_PASS, + # 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + # 'PORT': '', # Set to empty string for default. + # }, + # 'forums': { + # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + # 'NAME': FDB, # Or path to database file if using sqlite3. + # # The following settings are not used with sqlite3: + # 'USER': FDB_USER, + # 'PASSWORD': FDB_PASS, + # 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + # 'PORT': '', # Set to empty string for default. + # }, + # 'healthdb': { + # 'ENGINE': 'django.db.backends.mysql', + # 'NAME': HN, + # 'USER': HN_USER, + # 'PASSWORD': HN_PASS, + # 'HOST': HN_HOST, + # 'PORT': HN_PORT, + # }, + # 'stats': { + # 'ENGINE': 'django.db.backends.mysql', + # 'NAME': STATS_DB, + # 'USER': STATS_USER, + # 'PASSWORD': STATS_PWD, + # 'HOST': STATS_HOST, + # 'PORT': STATS_PORT, + # "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, + # } } @@ -364,7 +368,8 @@ 'django.middleware.common.BrokenLinkEmailsMiddleware', #'masquerade.middleware.MasqueradeMiddleware', 'django.contrib.redirects.middleware.RedirectFallbackMiddleware', - 'impersonate.middleware.ImpersonateMiddleware' + 'impersonate.middleware.ImpersonateMiddleware', + # 'debug_toolbar.middleware.DebugToolbarMiddleware', ] CORS_ORIGIN_ALLOW_ALL = True @@ -422,3 +427,24 @@ HDFC_POLL_INTERVAL=HDFC_POLL_INTERVAL RESPONSE_KEY=RESPONSE_KEY DEVELOPER_EMAIL=DEVELOPER_EMAIL + + +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +EMAIL_HOST = "smtp.gmail.com" +EMAIL_USE_TLS = True +EMAIL_PORT = 587 + +EMAIL_HOST_USER = "aisha@edupyramids.org" +EMAIL_HOST_PASSWORD = "zqmxcjxxuxsxwril" + +NO_REPLY_EMAIL = EMAIL_HOST_USER + +# DEBUG_TOOLBAR_CONFIG = { +# 'SHOW_TOOLBAR_CALLBACK': lambda x: True +# } + +# DEBUG_TOOLBAR_PATCH_SETTINGS = False +# DEBUG_TOOLBAR_CONFIG = { +# 'TOOLBAR_STORE_CLASS': 'debug_toolbar.store.DatabaseStore', +# 'RESULTS_CACHE_SIZE': 100, # Store up to 100 requests +# } diff --git a/spoken/urls.py b/spoken/urls.py index f29dbd6e..c91cb891 100644 --- a/spoken/urls.py +++ b/spoken/urls.py @@ -13,10 +13,16 @@ from donate.views import ilw_payment_callback from donate.payment import check_ilw_payment_status +# import debug_toolbar + +from django.conf import settings + + app_name = 'spoken' admin.autodiscover() urlpatterns = [ + # url(r'^__debug__/', include(debug_toolbar.urls)), url(r'^robots\.txt', robots_txt, name='robots-txt'), #url(r'^sitemap\.xml$', TemplateView.as_view(template_name='sitemap.xml', content_type='text/xml')), url(r'^sitemap\.html$', sitemap, name='sitemap'), @@ -142,10 +148,23 @@ #donation url(r'^donate/', include('donate.urls', namespace='donate')), + #Caches + url(r'^system-tools/', include('cms.cacheurls')), + + # cms url(r'^', include('cms.urls', namespace='cms')), - + + #nep book fiar url(r'wbf-book-fair-2023', bookfair,name="bookfair"), ] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) + +if settings.DEBUG: + import debug_toolbar + urlpatterns += [ + url(r'^__debug__/', include(debug_toolbar.urls)), + ] + + From bb7cfb3555e3b816333da0a8714d766b838174de Mon Sep 17 00:00:00 2001 From: ayishanishana21 Date: Mon, 1 Dec 2025 16:47:20 +0530 Subject: [PATCH 8/8] Remove unintended changes in spoken/settings.py --- spoken/settings.py | 168 +++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 97 deletions(-) diff --git a/spoken/settings.py b/spoken/settings.py index 977c7aca..bd227578 100644 --- a/spoken/settings.py +++ b/spoken/settings.py @@ -72,7 +72,6 @@ 'django.contrib.redirects', 'django.contrib.sitemaps', 'django_extensions', - # 'debug_toolbar', 'widget_tweaks', 'captcha', 'nicedit', @@ -130,85 +129,82 @@ # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases -# CONN_MAX_AGE = DB_CONN_MAX_AGE_DEFAULT -CONN_MAX_AGE = 60 -DB_CONN_MAX_AGE_DEFAULT = 0 # connections close after each request -DB_CONN_MAX_AGE_FREQUENT = 60 +CONN_MAX_AGE = DB_CONN_MAX_AGE_DEFAULT DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'ST_20Feb2023', - 'USER':'lisha', - 'PASSWORD': '1947', - 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - 'PORT': '3306', - # "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, + 'NAME': DB, + 'USER': DB_USER, + 'PASSWORD': DB_PASS, + 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + 'PORT': '', + "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, }, - # 'moodle': { - # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - # 'NAME': MDB, # Or path to database file if using sqlite3. - # # The following settings are not used with sqlite3: - # 'USER': MDB_USER, - # 'PASSWORD': MDB_PASS, - # 'HOST': MDB_HOST, # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - # 'PORT': '', # Set to empty string for default. - # "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, - # }, - # 'ilwmoodle': { - # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - # 'NAME': ILWMDB, # Or path to database file if using sqlite3. - # # The following settings are not used with sqlite3: - # 'USER': ILW_MDB_USER, - # 'PASSWORD': ILW_MDB_PASS, - # 'HOST': ILW_MDB_HOST, # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - # 'PORT': ILW_MDB_PORT, # Set to empty string for default. - # }, - # 'cdeep': { - # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - # 'NAME': CDB, # Or path to database file if using sqlite3. - # # The following settings are not used with sqlite3: - # 'USER': CDB_USER, - # 'PASSWORD': CDB_PASS, - # 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - # 'PORT': '', # Set to empty string for default. - # }, - # 'workshop_info': { - # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - # 'NAME': WDB, # Or path to database file if using sqlite3. - # # The following settings are not used with sqlite3: - # 'USER': WDB_USER, - # 'PASSWORD': WDB_PASS, - # 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - # 'PORT': '', # Set to empty string for default. - # }, - # 'forums': { - # 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - # 'NAME': FDB, # Or path to database file if using sqlite3. - # # The following settings are not used with sqlite3: - # 'USER': FDB_USER, - # 'PASSWORD': FDB_PASS, - # 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. - # 'PORT': '', # Set to empty string for default. - # }, - # 'healthdb': { - # 'ENGINE': 'django.db.backends.mysql', - # 'NAME': HN, - # 'USER': HN_USER, - # 'PASSWORD': HN_PASS, - # 'HOST': HN_HOST, - # 'PORT': HN_PORT, - # }, - # 'stats': { - # 'ENGINE': 'django.db.backends.mysql', - # 'NAME': STATS_DB, - # 'USER': STATS_USER, - # 'PASSWORD': STATS_PWD, - # 'HOST': STATS_HOST, - # 'PORT': STATS_PORT, - # "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, - # } + 'moodle': { + 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': MDB, # Or path to database file if using sqlite3. + # The following settings are not used with sqlite3: + 'USER': MDB_USER, + 'PASSWORD': MDB_PASS, + 'HOST': MDB_HOST, # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + 'PORT': '', # Set to empty string for default. + "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, + }, + 'ilwmoodle': { + 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': ILWMDB, # Or path to database file if using sqlite3. + # The following settings are not used with sqlite3: + 'USER': ILW_MDB_USER, + 'PASSWORD': ILW_MDB_PASS, + 'HOST': ILW_MDB_HOST, # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + 'PORT': ILW_MDB_PORT, # Set to empty string for default. + }, + 'cdeep': { + 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': CDB, # Or path to database file if using sqlite3. + # The following settings are not used with sqlite3: + 'USER': CDB_USER, + 'PASSWORD': CDB_PASS, + 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + 'PORT': '', # Set to empty string for default. + }, + 'workshop_info': { + 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': WDB, # Or path to database file if using sqlite3. + # The following settings are not used with sqlite3: + 'USER': WDB_USER, + 'PASSWORD': WDB_PASS, + 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + 'PORT': '', # Set to empty string for default. + }, + 'forums': { + 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': FDB, # Or path to database file if using sqlite3. + # The following settings are not used with sqlite3: + 'USER': FDB_USER, + 'PASSWORD': FDB_PASS, + 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. + 'PORT': '', # Set to empty string for default. + }, + 'healthdb': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': HN, + 'USER': HN_USER, + 'PASSWORD': HN_PASS, + 'HOST': HN_HOST, + 'PORT': HN_PORT, + }, + 'stats': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': STATS_DB, + 'USER': STATS_USER, + 'PASSWORD': STATS_PWD, + 'HOST': STATS_HOST, + 'PORT': STATS_PORT, + "CONN_MAX_AGE": DB_CONN_MAX_AGE_FREQUENT, + } } @@ -368,8 +364,7 @@ 'django.middleware.common.BrokenLinkEmailsMiddleware', #'masquerade.middleware.MasqueradeMiddleware', 'django.contrib.redirects.middleware.RedirectFallbackMiddleware', - 'impersonate.middleware.ImpersonateMiddleware', - # 'debug_toolbar.middleware.DebugToolbarMiddleware', + 'impersonate.middleware.ImpersonateMiddleware' ] CORS_ORIGIN_ALLOW_ALL = True @@ -427,24 +422,3 @@ HDFC_POLL_INTERVAL=HDFC_POLL_INTERVAL RESPONSE_KEY=RESPONSE_KEY DEVELOPER_EMAIL=DEVELOPER_EMAIL - - -EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" -EMAIL_HOST = "smtp.gmail.com" -EMAIL_USE_TLS = True -EMAIL_PORT = 587 - -EMAIL_HOST_USER = "aisha@edupyramids.org" -EMAIL_HOST_PASSWORD = "zqmxcjxxuxsxwril" - -NO_REPLY_EMAIL = EMAIL_HOST_USER - -# DEBUG_TOOLBAR_CONFIG = { -# 'SHOW_TOOLBAR_CALLBACK': lambda x: True -# } - -# DEBUG_TOOLBAR_PATCH_SETTINGS = False -# DEBUG_TOOLBAR_CONFIG = { -# 'TOOLBAR_STORE_CLASS': 'debug_toolbar.store.DatabaseStore', -# 'RESULTS_CACHE_SIZE': 100, # Store up to 100 requests -# }