├── home ├── __init__.py ├── api │ ├── __init__.py │ ├── urls.py │ ├── serializers.py │ └── views.py ├── migrations │ └── __init__.py ├── tests.py ├── apps.py ├── urls.py ├── forms.py ├── admin.py ├── context_processors.py └── models.py ├── Jagrati ├── __init__.py ├── settings │ ├── __init__.py │ ├── production.py │ ├── development.py │ └── base.py ├── wsgi.py └── urls.py ├── accounts ├── __init__.py ├── api │ ├── __init__.py │ ├── urls.py │ └── serializers.py ├── tests │ ├── __init__.py │ └── test_views.py ├── migrations │ └── __init__.py ├── tests.py ├── apps.py ├── tokens.py ├── urls.py ├── forms.py ├── admin.py └── models.py ├── apps ├── events │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── tests.py │ ├── apps.py │ ├── urls.py │ ├── views.py │ ├── models.py │ └── admin.py ├── misc │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── tests.py │ ├── views.py │ ├── apps.py │ ├── admin.py │ ├── models.py │ └── forms.py ├── feedbacks │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── tests.py │ ├── apps.py │ ├── urls.py │ ├── admin.py │ ├── models.py │ └── views.py ├── students │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── tests.py │ ├── apps.py │ ├── forms.py │ ├── urls.py │ ├── admin.py │ └── models.py └── volunteers │ ├── __init__.py │ ├── api │ ├── __init__.py │ └── serializers.py │ ├── migrations │ └── __init__.py │ ├── tests.py │ ├── apps.py │ ├── forms.py │ ├── urls.py │ ├── admin.py │ └── models.py ├── .dockerignore ├── templates ├── registration │ ├── password_reset_subject.txt │ ├── password_reset_email.html │ ├── password_reset_complete.html │ ├── password_change_done.html │ ├── password_reset_done.html │ ├── password_change_form.html │ ├── password_reset_form.html │ └── password_reset_confirm.html ├── accounts │ ├── email │ │ ├── account_authenticated_email.html │ │ ├── account_activation_email.html │ │ └── account_authentication_email.html │ ├── account_authenticated.html │ ├── profile_completed.html │ ├── signup_success.html │ ├── token_expired.html │ ├── resend_activation_mail.html │ ├── login_proto.html │ └── login_signup.html ├── feedbacks │ ├── feedback_submitted.html │ └── index.html ├── new_home │ └── new_base.html ├── students │ ├── update_from_sheets.html │ ├── leaderboard.html │ ├── index.html │ └── profile.html ├── base.html ├── snippets │ ├── footer.html │ └── header.html ├── 404.html ├── volunteers │ ├── leaderboard.html │ ├── index.html │ ├── volunteers_list.html │ └── update_schedule.html ├── events │ ├── index.html │ ├── captures.html │ └── add_event.html └── layout.html ├── static ├── logo.png ├── home │ ├── logo.jpg │ ├── logo.png │ ├── images │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── 04.jpg │ │ ├── 05.jpg │ │ ├── man.png │ │ ├── menu.png │ │ ├── close.png │ │ └── woman.png │ ├── js │ │ ├── myjs.js │ │ └── glide.js │ └── css │ │ └── calendar.css ├── global │ ├── icon │ │ ├── 404.jpg │ │ ├── camera.svg │ │ └── double-up-arrow.svg │ ├── images │ │ ├── header.jpg │ │ └── calendar.png │ ├── vendor │ │ ├── webfonts │ │ │ ├── fa-brands-400.eot │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-solid-900.eot │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-solid-900.woff │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.eot │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff │ │ │ ├── fa-regular-400.woff2 │ │ │ └── fa-solid-900.woff2 │ │ ├── photoswipe │ │ │ ├── default-skin │ │ │ │ ├── preloader.gif │ │ │ │ ├── default-skin.png │ │ │ │ └── default-skin.svg │ │ │ └── photoswipe.css │ │ └── css │ │ │ ├── glide.core.min.css │ │ │ └── glide.theme.min.css │ ├── css │ │ ├── scroll_to_top.css │ │ ├── custom.css │ │ └── sidebar.css │ └── js │ │ └── scroll_to_top.js ├── accounts │ ├── icon │ │ ├── lock.gif │ │ ├── tick.gif │ │ ├── google.png │ │ ├── mail-sent.gif │ │ ├── eye.svg │ │ └── eye-slash.svg │ └── style.js ├── new_home │ ├── images │ │ └── logo.png │ └── style.js ├── students │ └── css │ │ └── style.css └── volunteers │ └── css │ └── style.css ├── samples ├── sample-db.sqlite3 └── .env.save ├── .github ├── zulipbot-config │ └── templates │ │ ├── abandonWarning.md │ │ └── inactiveWarning.md ├── pull_request_template.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── workflows │ ├── welcome-new-contributors.yml │ └── python_lint.yml └── linters │ └── .flake8.yml ├── manage.py ├── requirements.txt ├── Dockerfile ├── LICENSE ├── .gitignore ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md /home/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Jagrati/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/events/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/misc/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /home/api/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Jagrati/settings/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts/api/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/feedbacks/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/students/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/volunteers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /home/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /venv/ 2 | /env/ -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/misc/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/volunteers/api/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/events/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/feedbacks/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/students/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/volunteers/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/registration/password_reset_subject.txt: -------------------------------------------------------------------------------- 1 | Jagrati Password Reset -------------------------------------------------------------------------------- /home/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/logo.png -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /apps/events/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /apps/misc/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /apps/misc/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /apps/feedbacks/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /apps/students/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /apps/volunteers/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /static/home/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/logo.jpg -------------------------------------------------------------------------------- /static/home/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/logo.png -------------------------------------------------------------------------------- /samples/sample-db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/samples/sample-db.sqlite3 -------------------------------------------------------------------------------- /static/home/images/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/01.jpg -------------------------------------------------------------------------------- /static/home/images/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/02.jpg -------------------------------------------------------------------------------- /static/home/images/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/03.jpg -------------------------------------------------------------------------------- /static/home/images/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/04.jpg -------------------------------------------------------------------------------- /static/home/images/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/05.jpg -------------------------------------------------------------------------------- /static/global/icon/404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/icon/404.jpg -------------------------------------------------------------------------------- /static/home/images/man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/man.png -------------------------------------------------------------------------------- /static/home/images/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/menu.png -------------------------------------------------------------------------------- /home/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class HomeConfig(AppConfig): 5 | name = 'home' 6 | -------------------------------------------------------------------------------- /static/accounts/icon/lock.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/accounts/icon/lock.gif -------------------------------------------------------------------------------- /static/accounts/icon/tick.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/accounts/icon/tick.gif -------------------------------------------------------------------------------- /static/home/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/close.png -------------------------------------------------------------------------------- /static/home/images/woman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/home/images/woman.png -------------------------------------------------------------------------------- /apps/misc/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MiscConfig(AppConfig): 5 | name = 'misc' 6 | -------------------------------------------------------------------------------- /static/accounts/icon/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/accounts/icon/google.png -------------------------------------------------------------------------------- /static/global/images/header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/images/header.jpg -------------------------------------------------------------------------------- /static/new_home/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/new_home/images/logo.png -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /apps/events/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class EventsConfig(AppConfig): 5 | name = 'events' 6 | -------------------------------------------------------------------------------- /static/accounts/icon/mail-sent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/accounts/icon/mail-sent.gif -------------------------------------------------------------------------------- /static/global/images/calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/images/calendar.png -------------------------------------------------------------------------------- /apps/students/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StudentsConfig(AppConfig): 5 | name = 'students' 6 | -------------------------------------------------------------------------------- /apps/feedbacks/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class FeedbacksConfig(AppConfig): 5 | name = 'feedbacks' 6 | -------------------------------------------------------------------------------- /apps/volunteers/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class VolunteersConfig(AppConfig): 5 | name = 'volunteers' 6 | -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /static/global/vendor/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /static/global/vendor/photoswipe/default-skin/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/photoswipe/default-skin/preloader.gif -------------------------------------------------------------------------------- /static/global/vendor/photoswipe/default-skin/default-skin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/garg3133/JagratiWebApp/HEAD/static/global/vendor/photoswipe/default-skin/default-skin.png -------------------------------------------------------------------------------- /home/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('create_profile/', views.create_profile_view, name='api_create_profile'), 6 | path('update_profile/', views.update_profile_view, name='api_update_profile'), 7 | ] -------------------------------------------------------------------------------- /.github/zulipbot-config/templates/abandonWarning.md: -------------------------------------------------------------------------------- 1 | Hello @{assignee}, you have been unassigned from this issue because you have not updated this issue or any referenced pull requests for over {total} days. 2 | 3 | Thanks for your contributions, and hope to see you again soon! -------------------------------------------------------------------------------- /apps/events/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'events' 6 | urlpatterns = [ 7 | path('', views.index, name='index'), 8 | path('add/', views.add_event, name='add_event'), 9 | path('captures/', views.captures, name='captures'), 10 | ] 11 | -------------------------------------------------------------------------------- /apps/misc/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .forms import InitiativeAdminForm 4 | from .models import Initiative 5 | 6 | 7 | @admin.register(Initiative) 8 | class InitiativeAdmin(admin.ModelAdmin): 9 | form = InitiativeAdminForm 10 | 11 | list_display = ('title',) 12 | -------------------------------------------------------------------------------- /apps/feedbacks/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'feedbacks' 6 | urlpatterns = [ 7 | path('', views.index, name='index'), 8 | path('submitted/', views.feedback_submitted, name='feedback_submitted'), 9 | path('contact/', views.contact, name='contact'), 10 | ] 11 | -------------------------------------------------------------------------------- /samples/.env.save: -------------------------------------------------------------------------------- 1 | EMAIL_HOST_USER = 'admin@domain.com' 2 | EMAIL_HOST_PASSWORD = 'your-password' 3 | 4 | SENDER_EMAIL = 'Jagrati ' 5 | ADMINS_EMAIL = ['email-address-of-admin@domain.com'] 6 | 7 | SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'google-oauth2-key' 8 | SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'google-oauth2-secret' 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Related Issue 2 | Fixes: 3 | 4 | # Prosposed Changes 5 | - change 1 6 | - change 2 7 | 8 | # Additional Info 9 | - any additional information or context 10 | 11 | # Screenshots 12 | 13 | Original | Updated 14 | :-------------------------:|:-------------------------: 15 | ** original screenshot ** | ** updated screenshot ** -------------------------------------------------------------------------------- /templates/accounts/email/account_authenticated_email.html: -------------------------------------------------------------------------------- 1 | {% autoescape off %} 2 | Hi {{ profile.get_full_name }},
3 |
4 | Your account has been successfully authenticated by our Admin. You can now log into your Jagrati Account..
5 |
6 | http://{{ domain }}{% url 'accounts:login_signup' %}
7 |
8 |
9 | Regards,
10 | Jagrati Team 11 | {% endautoescape %} -------------------------------------------------------------------------------- /templates/accounts/email/account_activation_email.html: -------------------------------------------------------------------------------- 1 | {% autoescape off %} 2 | Hi,
3 |
4 | Your account has been created successfully. Please click below link to activate your account and complete your profile:
5 |
6 | http://{{ domain }}{% url 'accounts:account_activation' uidb64=uid token=token %}
7 |
8 |
9 | Regards,
10 | Jagrati Team 11 | {% endautoescape %} -------------------------------------------------------------------------------- /apps/misc/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Initiative(models.Model): 5 | title = models.CharField(max_length=50) 6 | description = models.TextField(max_length=1000) 7 | thumb_url = models.URLField(max_length=200, blank=True) 8 | thumbnail = models.ImageField(upload_to='misc/initiatives', blank=True) 9 | 10 | def __str__(self): 11 | return self.title 12 | -------------------------------------------------------------------------------- /apps/feedbacks/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Feedback, Contact 3 | 4 | 5 | @admin.register(Feedback) 6 | class FeedbackAdmin(admin.ModelAdmin): 7 | list_display = ('date', 'name') 8 | ordering = ('-date',) 9 | 10 | 11 | @admin.register(Contact) 12 | class ContactAdmin(admin.ModelAdmin): 13 | list_display = ('date', 'name', 'email') 14 | ordering = ('-date',) 15 | -------------------------------------------------------------------------------- /static/global/css/scroll_to_top.css: -------------------------------------------------------------------------------- 1 | #scroll-to-top-button { 2 | position: fixed; 3 | bottom: 30px; 4 | right: 10px; 5 | z-index: 99; 6 | width: 50px; 7 | height: 50px; 8 | background-color: #ff8c00; 9 | border: none; 10 | cursor: pointer; 11 | outline: none; 12 | padding: 6px; 13 | border-radius: 50%; 14 | opacity: 0.95; 15 | } 16 | 17 | #scroll-to-top-button:hover { 18 | opacity: 1; 19 | } 20 | -------------------------------------------------------------------------------- /templates/feedbacks/feedback_submitted.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Feedbacks {% endblock %} 6 | 7 | {% block content %} 8 |
9 |
10 |
11 |

Thank You for submitting feedback!

12 |
13 |
14 |
15 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/password_reset_email.html: -------------------------------------------------------------------------------- 1 | {% autoescape off %} 2 | To initiate the password reset process for your Account {{ user.email }}, 3 | click the link below: 4 | 5 | {{ protocol }}://{{ domain }}{% url 'accounts:password_reset_confirm' uidb64=uid token=token %} 6 | 7 | If clicking the link above doesn't work, please copy and paste the URL in a new browser 8 | window instead. 9 | 10 | Sincerely, 11 | The Jagrati Team 12 | {% endautoescape %} -------------------------------------------------------------------------------- /Jagrati/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for Jagrati project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Jagrati.settings.development') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /static/global/css/custom.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Raleway:300,400,600,700,800,900); 2 | @import url('https://fonts.googleapis.com/css?family=Montserrat|Poppins&display=swap'); 3 | 4 | html, body { 5 | font-family: 'Raleway', sans-serif; 6 | /* color: #737373; */ 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | font-size: 16px; 10 | } 11 | 12 | label { 13 | font-weight:600; 14 | letter-spacing:1.2px; 15 | } -------------------------------------------------------------------------------- /accounts/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | path('register/', views.registration_view, name='api_register'), 6 | path('login/', views.LoginView.as_view(), name='api_login'), 7 | path('complete_profile/', views.complete_profile_view, name='api_complete_profile'), 8 | path('logout/', views.LogoutView.as_view(), name='api_logout'), 9 | path('check_login_status/', views.check_login_status, name='api_check_login_status'), 10 | ] -------------------------------------------------------------------------------- /static/new_home/style.js: -------------------------------------------------------------------------------- 1 | function rotate_menu(x) 2 | { 3 | x.classList.toggle("change"); 4 | } 5 | 6 | function nav_button() 7 | { 8 | var x = document.getElementById("nav"); 9 | 10 | if (x.className === "navbar") 11 | x.className += " responsive"; 12 | else 13 | x.className = "navbar"; 14 | } 15 | 16 | $(window).scroll(function() { 17 | if ($(window).scrollTop() > 20) { 18 | $('#sticky').addClass('floatingNav'); 19 | } else { 20 | $('#sticky').removeClass('floatingNav'); 21 | } 22 | }); 23 | 24 | -------------------------------------------------------------------------------- /apps/volunteers/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from home.models import Schedule 4 | from .models import VolunteerSchedule 5 | 6 | 7 | class VolunteerScheduleAdminForm(forms.ModelForm): 8 | class Meta: 9 | model = VolunteerSchedule 10 | fields = ['volun', 'day', 'schedule'] 11 | 12 | def clean(self): 13 | cleaned_data = self.cleaned_data 14 | schedule = cleaned_data.get('schedule') 15 | cleaned_data['day'] = Schedule.objects.get(id=schedule.id).day 16 | return cleaned_data 17 | -------------------------------------------------------------------------------- /templates/new_home/new_base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% load static %} 6 | 7 | 8 | 9 | 10 | {% block title %} {% endblock %} 11 | 12 | {% block style %} 13 | {% endblock %} 14 | 15 | 16 | 17 | 18 | {% block content %} 19 | {% endblock %} 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /templates/students/update_from_sheets.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati {% endblock %} 6 | 7 | {% block content %} 8 |
9 |
10 | {% csrf_token %} 11 | 12 | 13 |
14 | 15 |
16 |
17 | 18 | {% endblock %} -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% load static %} 6 | 7 | 8 | 9 | 10 | 11 | {% block title %} {% endblock %} 12 | 13 | {% block style %} 14 | {% endblock %} 15 | 16 | 17 | 18 | 19 | {% block content %} 20 | {% endblock %} 21 | 22 | 23 | -------------------------------------------------------------------------------- /home/api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from accounts.models import Profile 4 | 5 | class UpdateProfileSerializer(serializers.ModelSerializer): 6 | 7 | profile_image = serializers.ImageField(max_length=350, required=False) 8 | 9 | class Meta: 10 | model = Profile 11 | fields = ['id', 'roll_no', 'first_name', 'last_name', 'gender', 12 | 'batch', 'programme', 'dob', 'contact_no', 'alt_email', 13 | 'street_address1', 'street_address2', 'city', 'state', 14 | 'pincode', 'profile_image'] -------------------------------------------------------------------------------- /apps/misc/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import Initiative 3 | 4 | 5 | class InitiativeAdminForm(forms.ModelForm): 6 | class Meta: 7 | model = Initiative 8 | fields = ['title', 'description', 'thumb_url', 'thumbnail'] 9 | 10 | def clean(self): 11 | cleaned_data = self.cleaned_data 12 | thumb_url = cleaned_data.get('thumb_url') 13 | thumbnail = cleaned_data.get('thumbnail') 14 | if not thumbnail and not thumb_url: 15 | raise forms.ValidationError( 16 | "Both thumbnail and thumb_url cannot be empty.") 17 | return cleaned_data 18 | -------------------------------------------------------------------------------- /static/global/js/scroll_to_top.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | var scrollTopButton = document.getElementById("scroll-to-top-button"); 3 | 4 | window.onscroll = function () { 5 | scrollFunction(); 6 | }; 7 | 8 | function scrollFunction() { 9 | if ( 10 | document.body.scrollTop > 20 || 11 | document.documentElement.scrollTop > 20 12 | ) { 13 | scrollTopButton.style.display = "block"; 14 | } else { 15 | scrollTopButton.style.display = "none"; 16 | } 17 | } 18 | 19 | $("#scroll-to-top-button").click(function () { 20 | $("html ,body").animate({ scrollTop: 0 }, 800); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /templates/accounts/account_authenticated.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | SignUp Successful {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 |
11 | Done 12 |

Account Authenticated

13 |

You have successfully Authenticated the user account.

14 |
15 |
16 | 17 | {% endblock %} -------------------------------------------------------------------------------- /apps/students/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from home.models import Schedule 4 | from .models import StudentSchedule,Student 5 | 6 | 7 | class StudentScheduleAdminForm(forms.ModelForm): 8 | class Meta: 9 | model = StudentSchedule 10 | fields = ['student', 'day', 'schedule'] 11 | 12 | def clean(self): 13 | cleaned_data = self.cleaned_data 14 | schedule = cleaned_data.get('schedule') 15 | cleaned_data['day'] = Schedule.objects.get(id=schedule.id).day 16 | return cleaned_data 17 | 18 | class StudentModelForm(forms.ModelForm): 19 | class Meta: 20 | model = Student 21 | fields = '__all__' 22 | -------------------------------------------------------------------------------- /home/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = 'home' 5 | urlpatterns = [ 6 | path('', views.index, name='index'), 7 | path('new/', views.new_index, name='new_index'), 8 | path('dashboard/', views.dashboard, name='dashboard'), 9 | path('dashboard/update_cwhw/', views.update_cwhw, name='update_cwhw'), 10 | path('ajax/dashboard/', views.ajax_dashboard, name='ajax_dashboard'), 11 | path('dashboard/class_schedule/', views.class_schedule, name='class_schedule'), 12 | path('calendar/', views.calendar, name='calendar'), 13 | path('ajax/fetch_calendar', views.ajax_fetch_calendar, name='ajax_fetch_calendar'), 14 | ] 15 | -------------------------------------------------------------------------------- /static/global/icon/camera.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[bug]: " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /templates/accounts/email/account_authentication_email.html: -------------------------------------------------------------------------------- 1 | {% autoescape off %} 2 | A new User has signed up. The details are as follows:
3 |
4 | Email: {{ profile.user.email }}
5 | Roll No: {{ volun.roll_no }}
6 | Name: {{ profile.get_full_name }}
7 | Gender: {{ profile.get_gender_display }}
8 | Batch: {{ volun.batch }}
9 | Programme: {{ volun.get_programme_display }}
10 | Alternate Email: {{ profile.alt_email }}
11 |
12 | To verify the account, click on the link below...
13 |
14 | http://{{ domain }}{% url 'accounts:account_authentication' uidb64=uid token=token %}
15 |
16 |
17 | Regards,
18 | Jagrati Team 19 | {% endautoescape %} 20 | -------------------------------------------------------------------------------- /templates/accounts/profile_completed.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block title %} Jagrati | SignUp Successful {% endblock %} 4 | 5 | {% block content %} 6 | 7 |
8 |
9 | 10 |

Profile in Review

11 |

We have sent your Profile to our Admin for verification. You will recieve an Email Notification once your Profile gets verified by Admin.

12 |
13 |
14 | 15 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/password_reset_complete.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Password Reset {% endblock %} 6 | 7 | {% block content %} 8 |
9 |
10 | tick 11 |

Password Reset Successful

12 |

You may go ahead and sign in 13 | now.

14 |
15 |
16 | {% endblock %} -------------------------------------------------------------------------------- /apps/volunteers/api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from apps.volunteers.models import Volunteer 4 | 5 | class CreateVolunteerSerializer(serializers.ModelSerializer): 6 | class Meta: 7 | model = Volunteer 8 | fields = ['roll_no', 'batch', 'programme', 'dob'] 9 | 10 | def validate_roll_no(self, value): 11 | volun = Volunteer.objects.filter(roll_no=roll_no) 12 | if volun.exists(): 13 | raise serializers.ValidationError('Volunteer with entered roll no. already exists.') 14 | return value 15 | 16 | # WE CAN USE NESTED REPRESENTATION FOR PROFILE AND UPDATE_PROFILE 17 | # AS THEY NEED TO BE CREATED IN THIS APP -------------------------------------------------------------------------------- /templates/accounts/signup_success.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | SignUp Successful {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
10 |
11 | Email Sent 12 |

Account Activation

13 |

We have sent you an activation link on your email, please click on it to Proceed.

14 |
15 |
16 | 17 | {% endblock %} -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | def main(): 7 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Jagrati.settings.development') 8 | try: 9 | from django.core.management import execute_from_command_line 10 | except ImportError as exc: 11 | raise ImportError( 12 | "Couldn't import Django. Are you sure it's installed and " 13 | "available on your PYTHONPATH environment variable? Did you " 14 | "forget to activate a virtual environment?" 15 | ) from exc 16 | execute_from_command_line(sys.argv) 17 | 18 | 19 | if __name__ == '__main__': 20 | main() 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[feature]: " 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /home/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import Section 3 | 4 | class SectionAdminForm(forms.ModelForm): 5 | class Meta: 6 | model = Section 7 | fields = ['section_id', 'name', 'is_parent_section', 'parent_section'] 8 | 9 | def clean(self): 10 | cleaned_data = self.cleaned_data 11 | parent_section = cleaned_data.get('parent_section') 12 | is_parent_section = cleaned_data.get('is_parent_section') 13 | if parent_section and is_parent_section: 14 | raise forms.ValidationError( 15 | "A section cannot be a parent section and a child section at the same time. Only two level of parent-child relationship is allowed.") 16 | return cleaned_data -------------------------------------------------------------------------------- /templates/accounts/token_expired.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block title %} Jagrati | Token Expired {% endblock %} 4 | 5 | {% block content %} 6 | 7 |
8 |
9 | 10 |

Token Expired

11 |

12 | {{msg}} 13 | {% if act_token %} 14 | Try signing in with your credentials. 15 | {% endif %} 16 |

17 |
18 |
19 | 20 | {% endblock %} -------------------------------------------------------------------------------- /.github/zulipbot-config/templates/inactiveWarning.md: -------------------------------------------------------------------------------- 1 | Hello @{assignee}, you claimed this issue to work on it, but this issue and any referenced pull requests haven't been updated for {remind} days. Are you still working on this issue? 2 | 3 | If so, please update this issue by leaving a comment on this issue to let me know that you're still working on it. Otherwise, I'll automatically remove you from this issue in {abandon} days. 4 | 5 | If you've decided to work on something else, simply unassign yourself from this issue by going to the `Assignees` section and clicking on `unassign me`, so that someone else can claim it and continue from where you left off. 6 | 7 | Thank you for your valuable contributions to JagratiWebApp! 8 | 9 | -------------------------------------------------------------------------------- /.github/workflows/welcome-new-contributors.yml: -------------------------------------------------------------------------------- 1 | name: 'Welcome new contributors' 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | pull_request_target: 7 | types: [opened] 8 | 9 | jobs: 10 | greet-the-contributor: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: garg3133/welcome-new-contributors@v1.1 14 | with: 15 | token: ${{ secrets.BOT_ACCESS_TOKEN }} 16 | is-oauth-token: true 17 | issue-message: 'Hi! Thanks for opening your first issue at JagratiWebApp :rocket: We really appreciate it. :raised_hands: Someone from our team will get back here soon.' 18 | pr-message: 'Congratulations for making your first Pull Request at JagratiWebApp!! :tada: Someone from our team will review it soon.' 19 | -------------------------------------------------------------------------------- /static/global/vendor/css/glide.core.min.css: -------------------------------------------------------------------------------- 1 | .glide{position:relative;width:100%;box-sizing:border-box}.glide *{box-sizing:inherit}.glide__track{overflow:hidden}.glide__slides{position:relative;width:100%;list-style:none;backface-visibility:hidden;transform-style:preserve-3d;touch-action:pan-Y;overflow:hidden;padding:0;white-space:nowrap;display:flex;flex-wrap:nowrap;will-change:transform}.glide__slides--dragging{user-select:none}.glide__slide{width:100%;height:100%;flex-shrink:0;white-space:normal;user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}.glide__slide a{user-select:none;-webkit-user-drag:none;-moz-user-select:none;-ms-user-select:none}.glide__arrows{-webkit-touch-callout:none;user-select:none}.glide__bullets{-webkit-touch-callout:none;user-select:none}.glide--rtl{direction:rtl} 2 | -------------------------------------------------------------------------------- /apps/feedbacks/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | # Create your models here. 5 | class Feedback(models.Model): 6 | name = models.CharField(max_length=50) 7 | roll_no = models.IntegerField(null=True, blank=True) 8 | email = models.EmailField(max_length=255, null=True, blank=True) 9 | feedback = models.TextField(max_length=5000) 10 | date = models.DateTimeField(auto_now_add=True) 11 | 12 | def __str__(self): 13 | return self.name 14 | 15 | 16 | class Contact(models.Model): 17 | date = models.DateTimeField(auto_now_add=True) 18 | name = models.CharField(max_length=100) 19 | phone = models.CharField(max_length=15) 20 | email = models.EmailField(max_length=50) 21 | message = models.TextField(max_length=400) 22 | 23 | def __str__(self): 24 | return self.email 25 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2023.7.22 2 | cffi==1.14.4 3 | chardet==4.0.0 4 | cryptography==41.0.6 5 | defusedxml==0.7.0rc2 6 | Django==2.2.28 7 | django-appconf==1.0.4 8 | django-cleanup==5.0.0 9 | django-cors-headers==3.7.0 10 | django-extensions==3.1.3 11 | django-imagekit==4.0.2 12 | djangorestframework==3.11.2 13 | et-xmlfile==1.0.1 14 | flake8==3.9.1 15 | idna==2.10 16 | jdcal==1.4.1 17 | mccabe==0.6.1 18 | oauthlib==3.1.0 19 | openpyxl==3.0.3 20 | pilkit==2.0 21 | Pillow==10.0.1 22 | pycodestyle==2.7.0 23 | pycparser==2.20 24 | pyflakes==2.3.1 25 | PyJWT==2.4.0 26 | python-decouple==3.3 27 | python3-openid==3.2.0 28 | pytz==2019.3 29 | requests==2.31.0 30 | requests-oauthlib==1.3.0 31 | six==1.15.0 32 | social-auth-app-django==4.0.0 33 | social-auth-core==4.0.3 34 | sqlparse==0.4.4 35 | urllib3==1.26.18 36 | -------------------------------------------------------------------------------- /accounts/tokens.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.tokens import PasswordResetTokenGenerator 2 | from django.utils import six 3 | 4 | class TokenGenerator(PasswordResetTokenGenerator): 5 | def _make_hash_value(self, user, timestamp): 6 | return ( 7 | six.text_type(user.pk) + six.text_type(timestamp) 8 | + six.text_type((user.is_active is True)) 9 | + six.text_type((user.auth is True)) 10 | 11 | # Wasn't working correctly in cpanel because in activation func 12 | # user.is_active and all other booleans somehow becomes null (or None) 13 | # and thus the token don't match with is_active False at one place and 14 | # None at other 15 | 16 | ) 17 | # return str(user.pk) + str(timestamp) + str(user.is_active) 18 | 19 | account_activation_token = TokenGenerator() -------------------------------------------------------------------------------- /static/accounts/icon/eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /templates/registration/password_change_done.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Change Password {% endblock %} 6 | 7 | {% block style %} 8 | 16 | {% endblock %} 17 | 18 | {% block content %} 19 |
20 |
21 | Done 22 |

Password Changed

23 |

Your password has been successfully updated.

24 | Back to dashboard 25 |
26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile written for continuous development 2 | # Running on django development server 3 | # Making it easy for contributers across all environment to setup a Django platform in seconds 4 | # 5 | # 6 | # 7 | # v1.0.0 8 | 9 | FROM python:3.8 10 | # This is the image base 11 | 12 | 13 | RUN apt-get update \ 14 | && apt-get install -y --no-install-recommends \ 15 | && rm -rf /var/lib/apt/lists/* 16 | 17 | # Keeping a work directory 18 | WORKDIR /usr/src/app 19 | 20 | # Copying and installing requirememts.txt 21 | COPY requirements.txt ./ 22 | RUN pip3 install -r requirements.txt 23 | 24 | # Moving the files into our working directory 25 | COPY . . 26 | 27 | # Default port 8000 is opened from docker to server the project 28 | EXPOSE 8000 29 | 30 | # Django setups with DB and admin user 31 | RUN python3 manage.py makemigrations 32 | RUN python3 manage.py migrate 33 | RUN python3 manage.py createsuperuser 34 | 35 | # Entrypoint, While running this command will be executed 36 | CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] 37 | -------------------------------------------------------------------------------- /Jagrati/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.conf.urls.static import static 3 | from django.contrib import admin 4 | from django.urls import path, include 5 | 6 | admin.site.site_header = "Jagrati Admin" 7 | admin.site.site_title = "Jagrati Admin Portal" 8 | admin.site.index_title = "Welcome to Jagrati Administration" 9 | 10 | urlpatterns = [ 11 | path('admin/', admin.site.urls), 12 | path('', include('home.urls')), 13 | path('accounts/', include('accounts.urls')), 14 | path('oauth/', include('social_django.urls', namespace='social')), 15 | path('students/', include('apps.students.urls')), 16 | path('volunteers/', include('apps.volunteers.urls')), 17 | path('feedbacks/', include('apps.feedbacks.urls')), 18 | path('events/', include('apps.events.urls')), 19 | 20 | # Rest API URLs 21 | path('api/', include('home.api.urls')), 22 | path('api/accounts/', include('accounts.api.urls')), 23 | ] 24 | 25 | if settings.DEBUG: 26 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 27 | -------------------------------------------------------------------------------- /templates/snippets/footer.html: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 27 | -------------------------------------------------------------------------------- /templates/accounts/resend_activation_mail.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Resend activation mail {% endblock %} 6 | 7 | {% block content %} 8 |
9 |
10 |

Resend activation mail

11 |
12 | {% csrf_token %} 13 | 16 | 17 | {{error_message}} 18 | 19 |
20 |
21 |
22 | {% endblock %} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Priyansh Garg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /apps/volunteers/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'volunteers' 6 | urlpatterns = [ 7 | path('', views.index, name='index'), 8 | path('profile//', views.profile, name='profile'), 9 | path('attendance/', views.attendance, name='attendance'), 10 | path('leaderboard/', views.leaderboard, name='leaderboard'), 11 | # path('attendance/view/', views.view_attendance, name='view_attendance'), 12 | path('update_schedule/', views.update_schedule, name='update_schedule'), 13 | path('ajax/update_schedule/', views.ajax_update_schedule, name='ajax_update_schedule'), 14 | 15 | # Needs to be changed 16 | path('profile/update/', views.update_profile, name='update_profile'), # Not needed, update in profile/ only 17 | path('list/', views.volunteers_list, name='volunteers_list'), 18 | path('ajax/list/', views.ajax_volunteers_list, name='ajax_volunteers_list'), 19 | 20 | # AJAX calls 21 | path('ajax/mark_attendance/', views.ajax_mark_attendance, name='ajax_mark_attendance'), 22 | path('ajax/add_extra_vol/', views.ajax_add_extra_vol, name='ajax_add_extra_vol'), 23 | ] -------------------------------------------------------------------------------- /templates/registration/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Password Reset {% endblock %} 6 | 7 | {% block style %} 8 | 16 | {% endblock %} 17 | 18 | {% block content %} 19 |
20 |
21 | Email Sent 23 |

Reset link sent

24 |

We've emailed you the instructions to reset your password.

25 |

If the email address entered by you is registered with us, you should receive them 26 | shortly. If you don't, please check your spam folder.

27 | Return to Home Page 28 |
29 |
30 | {% endblock %} -------------------------------------------------------------------------------- /apps/students/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'students' 6 | urlpatterns = [ 7 | path('', views.index, name='index'), 8 | path('add/', views.add_student, name='add_student'), 9 | path('profile//', views.profile, name='profile'), 10 | path('attendance/', views.attendance, name='attendance'), 11 | path('leaderboard/', views.leaderboard, name='leaderboard'), 12 | # path('attendance/view/', views.view_attendance, name='view_attendance'), 13 | path('profile/update//', views.update_profile, name='update_profile'), # Not needed, update in profile/ only 14 | path('profile/verify_profile///', views.verify_profile, name='verify_profile'), 15 | 16 | path('update_from_sheets/', views.update_from_sheets, name='update_from_sheets'), 17 | path('generate_sheet/', views.generate_sheet, name='generate_sheet'), 18 | 19 | # AJAX calls 20 | path('ajax/fetch_students/', views.ajax_fetch_students, name='ajax_fetch_students'), 21 | path('ajax/mark_attendance/', views.ajax_mark_attendance, name='ajax_mark_attendance'), 22 | path('ajax/mark_homework/', views.ajax_mark_homework, name='ajax_mark_homework'), 23 | 24 | ] -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | 404 Page Not Found {% endblock %} 6 | 7 | {% block style %} 8 | 30 | {% endblock %} 31 | 32 | {% block content %} 33 |
34 |
35 | 404 36 |

OOPS !!!

37 |

Seems like our kids misplaced the page

38 | Return to Home Page 39 |
40 |
41 | {% endblock %} -------------------------------------------------------------------------------- /static/global/vendor/css/glide.theme.min.css: -------------------------------------------------------------------------------- 1 | .glide__arrow{position:absolute;display:block;top:50%;z-index:2;color:white;text-transform:uppercase;padding:9px 12px;background-color:transparent;border:2px solid rgba(255,255,255,0.5);border-radius:4px;box-shadow:0 0.25em 0.5em 0 rgba(0,0,0,0.1);text-shadow:0 0.25em 0.5em rgba(0,0,0,0.1);opacity:1;cursor:pointer;transition:opacity 150ms ease, border 300ms ease-in-out;transform:translateY(-50%);line-height:1}.glide__arrow:focus{outline:none}.glide__arrow:hover{border-color:white}.glide__arrow--left{left:2em}.glide__arrow--right{right:2em}.glide__arrow--disabled{opacity:0.33}.glide__bullets{position:absolute;z-index:2;bottom:2em;left:50%;display:inline-flex;list-style:none;transform:translateX(-50%)}.glide__bullet{background-color:rgba(255,255,255,0.5);width:9px;height:9px;padding:0;border-radius:50%;border:2px solid transparent;transition:all 300ms ease-in-out;cursor:pointer;line-height:0;box-shadow:0 0.25em 0.5em 0 rgba(0,0,0,0.1);margin:0 0.25em}.glide__bullet:focus{outline:none}.glide__bullet:hover,.glide__bullet:focus{border:2px solid white;background-color:rgba(255,255,255,0.5)}.glide__bullet--active{background-color:white}.glide--swipeable{cursor:grab;cursor:-moz-grab;cursor:-webkit-grab}.glide--dragging{cursor:grabbing;cursor:-moz-grabbing;cursor:-webkit-grabbing} 2 | -------------------------------------------------------------------------------- /home/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .forms import SectionAdminForm 4 | from .models import Calendar, ClassworkHomework, Schedule, Section 5 | 6 | @admin.register(Calendar) 7 | class CalendarAdmin(admin.ModelAdmin): 8 | list_display = ('date', 'class_scheduled', 'remark') 9 | search_fields = ('date',) 10 | list_filter = ('class_scheduled',) 11 | ordering = ('-date',) 12 | 13 | @admin.register(ClassworkHomework) 14 | class ClassworkHomeworkAdmin(admin.ModelAdmin): 15 | list_display = ('cal_date', 'section', 'subject_taught') 16 | search_fields = ('cal_date',) 17 | list_filter = ('subject_taught', 'section__name',) 18 | ordering = ('-cal_date__date', 'section__section_id') 19 | 20 | @admin.register(Schedule) 21 | class ScheduleAdmin(admin.ModelAdmin): 22 | list_display = ('day', 'section', 'subject') 23 | list_filter = ('day', 'subject', 'section__name') 24 | ordering = ('day', 'section__section_id') 25 | 26 | @admin.register(Section) 27 | class SectionAdmin(admin.ModelAdmin): 28 | form = SectionAdminForm 29 | 30 | list_display = ('section_id', 'name', 'parent_section', 'is_parent_section') 31 | search_fields = ('name', 'parent_section') 32 | list_filter = ('parent_section', 'is_parent_section') 33 | ordering = ('section_id',) 34 | -------------------------------------------------------------------------------- /Jagrati/settings/production.py: -------------------------------------------------------------------------------- 1 | # CONTAINS SETTINGS FOR PRODUCTION 2 | 3 | from .base import * 4 | import ast 5 | 6 | SECRET_KEY = config('DJANGO_SECRET_KEY_JAGRATI') 7 | 8 | DEBUG = config("DEBUG", cast=bool) 9 | 10 | ALLOWED_HOSTS = ast.literal_eval(config("ALLOWED_HOSTS")) 11 | 12 | # Database 13 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases 14 | 15 | DATABASES = { 16 | 'default': { 17 | 'ENGINE': 'django.db.backends.sqlite3', 18 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 19 | } 20 | } 21 | 22 | # EMAIL SETTINGS 23 | 24 | EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' 25 | 26 | EMAIL_USE_TLS = True 27 | EMAIL_HOST = 'smtp.gmail.com' 28 | EMAIL_HOST_USER = config("EMAIL_HOST_USER") 29 | EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD") 30 | EMAIL_PORT = 587 31 | 32 | DEFAULT_FROM_EMAIL = config("SENDER_EMAIL") 33 | ADMINS_EMAIL = ast.literal_eval(config("ADMINS_EMAIL")) 34 | 35 | 36 | # Static files (CSS, JavaScript, Images) 37 | # https://docs.djangoproject.com/en/2.2/howto/static-files/ 38 | 39 | STATIC_ROOT = os.path.join(BASE_DIR, '..', 'staticfiles/') 40 | STATIC_URL = '/static/' 41 | 42 | MEDIA_ROOT = os.path.join(BASE_DIR, '..', 'media/') 43 | MEDIA_URL = '/media/' 44 | 45 | TEMP_ROOT = os.path.join(BASE_DIR, '..', 'temp/') 46 | 47 | STATICFILES_DIRS = [BASE_DIR+"/static", ] 48 | -------------------------------------------------------------------------------- /static/accounts/style.js: -------------------------------------------------------------------------------- 1 | 2 | const signUpButton = document.getElementById('signUp'); 3 | const signInButton = document.getElementById('signIn'); 4 | const container = document.getElementById('container'); 5 | 6 | 7 | signUpButton.addEventListener('click', () => { 8 | container.classList.add("right-panel-active"); 9 | document.querySelectorAll('.form-error')[1].innerHTML=""; 10 | }); 11 | 12 | signInButton.addEventListener('click', () => { 13 | container.classList.remove("right-panel-active"); 14 | document.querySelectorAll('.form-error')[0].innerHTML=""; 15 | }); 16 | 17 | const togglePassword = document.querySelector('#togglePassword'); 18 | const password = document.querySelector('#password'); 19 | 20 | togglePassword.addEventListener('click', function (e) { 21 | 22 | // toggle the type attribute 23 | const type = password.getAttribute('type'); 24 | 25 | if(type == "password"){ 26 | password.setAttribute('type', "text"); 27 | // toggle the eye slash icon 28 | togglePassword.src = "/static/accounts/icon/eye.svg" 29 | 30 | //Toggle the tooltip 31 | togglePassword.title = "Hide Password" 32 | } 33 | else{ 34 | password.setAttribute('type', "password"); 35 | // toggle the eye slash icon 36 | togglePassword.src = "/static/accounts/icon/eye-slash.svg" 37 | 38 | //Toggle the tooltip 39 | togglePassword.title = "Show Password" 40 | } 41 | 42 | }); -------------------------------------------------------------------------------- /templates/accounts/login_proto.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %} Login | SignUp {% endblock %} 4 | 5 | {% block content %} 6 | 7 | {% if user.is_authenticated %} 8 |

User is Authenticated.

9 | Logout 10 | {% else %} 11 | 12 |

Login

13 |
14 | {% csrf_token %} 15 |

{{ login_error }}

16 | 17 | 18 | 19 |
20 | 21 |

SignUp

22 |
23 | {% csrf_token %} 24 |

{{ signup_error }}

25 |
26 | Volunteer 27 | Faculty
28 |
29 |
30 | 31 |
32 | 33 | {% endif %} 34 | 35 | {% endblock %} -------------------------------------------------------------------------------- /static/students/css/style.css: -------------------------------------------------------------------------------- 1 | .student__header { 2 | top: 70px; 3 | } 4 | 5 | .student__header .header-img { 6 | width: 100%; 7 | height: 280px; 8 | } 9 | 10 | #student__cards a { 11 | text-decoration: none; 12 | } 13 | 14 | .student__card img { 15 | width: 100%; 16 | border-radius: 12px; 17 | border: 1px solid rgb(239, 237, 235); 18 | height: 200px; 19 | object-fit: cover; 20 | background-color: rgb(239, 237, 235); 21 | } 22 | 23 | .student__card { 24 | background-color: snow; 25 | padding: 8px; 26 | border-radius: 12px; 27 | border: 1px solid rgb(239, 237, 235); 28 | transition: all 200ms ease-in-out; 29 | cursor: pointer; 30 | } 31 | 32 | #student__cards .tag { 33 | padding: 4px 8px; 34 | border: 1px solid rgb(241, 128, 29); 35 | 36 | border-radius: 50px; 37 | font-size: 12px; 38 | font-weight: 600; 39 | color: rgb(241, 128, 29); 40 | } 41 | 42 | #student__cards .name { 43 | font-size: 16px; 44 | font-weight: 600; 45 | margin-top: 16px; 46 | margin-bottom: 8px; 47 | } 48 | 49 | #student__cards p { 50 | font-size: 14px; 51 | color: #7f8c9b; 52 | line-height: 150%; 53 | letter-spacing: 1px; 54 | margin: 0px; 55 | padding: 2px 0px; 56 | } 57 | 58 | .card__details { 59 | padding: 8px 8px 8px 8px; 60 | } 61 | 62 | @media screen and (max-width: 576px) { 63 | #student__cards > .row { 64 | max-width: 255px; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /static/accounts/icon/eye-slash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /static/home/js/myjs.js: -------------------------------------------------------------------------------- 1 | //Nav button controls 2 | const navbar_toggler = document.querySelector('.navbar-toggler i'); 3 | const left_nav = document.querySelector('.navbar .left-nav .navbar-nav'); 4 | 5 | function toggleNav() { 6 | navbar_toggler.classList.toggle('fa-bars'); 7 | navbar_toggler.classList.toggle('fa-times'); 8 | left_nav.classList.toggle('nav-collapsed'); 9 | } 10 | 11 | navbar_toggler.addEventListener('click', function() { 12 | toggleNav(); 13 | }); 14 | 15 | 16 | window.onclick = function(e){ 17 | // Navbar closes if clicks anywhere else 18 | if (!e.target.closest('.navbar')) { 19 | if (navbar_toggler.classList.contains('fa-times')) toggleNav(); 20 | } 21 | 22 | // Donate us modal close 23 | if(e.target == don_modal){ 24 | don_modal.style.display="none"; 25 | } 26 | } 27 | 28 | // Donate Us Modal Close 29 | const don_modal = document.getElementById("don-modal"); 30 | function donate_us(){ 31 | don_modal.style.display="block"; 32 | } 33 | const modal_cl = document.getElementById("don-close"); 34 | modal_cl.onclick = function(){ 35 | don_modal.style.display="none"; 36 | } 37 | 38 | // SHOWCASE TEXT 39 | const show_p_txt = "Give way to changing the lives of needy children through Education"; 40 | let i=0; 41 | show_p(); 42 | function show_p(){ 43 | if(i < show_p_txt.length){ 44 | document.getElementById("show-p").innerHTML += show_p_txt.charAt(i); 45 | i++; 46 | setTimeout(show_p, 50); //speed is in milliseconds 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /accounts/api/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from accounts.models import User, Profile 4 | 5 | 6 | class RegistrationSerializer(serializers.ModelSerializer): 7 | password2 = serializers.CharField(style={'input_type': 'password'}, write_only=True) 8 | 9 | class Meta: 10 | model = User 11 | fields = ['email', 'password', 'password2'] 12 | extra_kwargs = { 13 | 'password': {'write_only': True}, 14 | } 15 | 16 | def save(self): 17 | user = User( 18 | email=self.validated_data['email'], 19 | is_active=False, 20 | ) 21 | # Validate Password 22 | password = self.validated_data['password'] 23 | password2 = self.validated_data['password2'] 24 | if password != password2: 25 | data = { 26 | 'response': 'Error', 27 | 'error_message': 'Passwords must match.', 28 | } 29 | # This data is sent directly to the caller 30 | raise serializers.ValidationError(data) 31 | 32 | user.set_password(password) 33 | user.save() 34 | return user 35 | 36 | class CreateProfileSerializer(serializers.ModelSerializer): 37 | class Meta: 38 | model = Profile 39 | fields = ['first_name', 'last_name', 'gender', 'contact_no', 40 | 'alt_email', 'street_address1', 'street_address2', 41 | 'city', 'state', 'pincode', 'profile_image'] 42 | -------------------------------------------------------------------------------- /static/global/icon/double-up-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /static/global/vendor/photoswipe/default-skin/default-skin.svg: -------------------------------------------------------------------------------- 1 | default-skin 2 -------------------------------------------------------------------------------- /Jagrati/settings/development.py: -------------------------------------------------------------------------------- 1 | # CONTAINS SETTINGS FOR DEVELOPMENT 2 | 3 | from .base import * 4 | import ast 5 | 6 | # Quick-start development settings - unsuitable for production 7 | # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ 8 | 9 | # Warning: This SECRET KEY is for development purpose only. 10 | # ALWAYS USE A DIFFERENT KEY FOR PRODUCTION. 11 | SECRET_KEY = '(8ty!=07t%td)i5%r8x4dh^tvb3sv+4e3zk1cq=(g)tcnn@nq8' 12 | 13 | DEBUG = True 14 | 15 | ALLOWED_HOSTS = ['*'] 16 | 17 | # Database 18 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases 19 | 20 | DATABASES = { 21 | 'default': { 22 | 'ENGINE': 'django.db.backends.sqlite3', 23 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 24 | } 25 | } 26 | 27 | 28 | # EMAIL SETTINGS 29 | 30 | EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' 31 | # EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' 32 | 33 | EMAIL_USE_TLS = True 34 | EMAIL_HOST = 'smtp.gmail.com' 35 | EMAIL_HOST_USER = config("EMAIL_HOST_USER") 36 | EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD") 37 | EMAIL_PORT = 587 38 | 39 | DEFAULT_FROM_EMAIL = config("SENDER_EMAIL") 40 | ADMINS_EMAIL = ast.literal_eval(config("ADMINS_EMAIL")) 41 | 42 | 43 | # Static files (CSS, JavaScript, Images) 44 | # https://docs.djangoproject.com/en/2.2/howto/static-files/ 45 | 46 | STATIC_URL = '/static/' 47 | 48 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 49 | MEDIA_URL = '/media/' 50 | 51 | STATICFILES_DIRS = [BASE_DIR+"/static", ] 52 | 53 | TEMP_ROOT = os.path.join(BASE_DIR, 'temp') 54 | -------------------------------------------------------------------------------- /templates/volunteers/leaderboard.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Volunteer Leaderboard {% endblock %} 6 | 7 | {% block content %} 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% for vol in volunteers %} 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | {% endfor %} 42 | 43 |
#Roll No.NameTotal DaysExtra Days
{{forloop.counter}}{{ vol.volun__roll_no }} 31 | 32 | {{ vol.volun__profile__first_name }} 33 | 34 | {{ vol.volun__profile__last_name }} 35 | 36 | {{ vol.total_attendance }}{{ vol.extra }}
44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /static/volunteers/css/style.css: -------------------------------------------------------------------------------- 1 | .vol__header { 2 | top: 70px; 3 | } 4 | 5 | .vol__header .header-img { 6 | width: 100%; 7 | height: 280px; 8 | } 9 | 10 | #Vol__Cards a { 11 | text-decoration: none; 12 | } 13 | 14 | .vol__card img { 15 | width: 100%; 16 | border-radius: 12px; 17 | border: 1px solid rgb(241, 128, 29); 18 | height: 200px; 19 | object-fit: cover; 20 | background-color: rgb(241, 128, 29); 21 | } 22 | 23 | .vol__card { 24 | background-color: snow; 25 | padding: 8px; 26 | border-radius: 12px; 27 | border: 1px solid rgb(241, 128, 29); 28 | transition: all 200ms ease-in-out; 29 | cursor: pointer; 30 | /* width: 240px; 31 | height: 360px; */ 32 | } 33 | 34 | .vol__card:focus, 35 | .vol__card:hover { 36 | transition: all 0.35s cubic-bezier(0.14, 0.51, 0, 1); 37 | box-shadow: 10px 10px 0px 0px rgb(239 112 0 / 10%), 38 | 20px 16px 50px -20px rgb(240 112 0); 39 | } 40 | 41 | #Vol__Cards .tag { 42 | padding: 4px 8px; 43 | border: 1px solid rgb(241, 128, 29); 44 | 45 | border-radius: 50px; 46 | font-size: 12px; 47 | font-weight: 600; 48 | color: rgb(241, 128, 29); 49 | } 50 | 51 | #Vol__Cards .name { 52 | font-size: 16px; 53 | font-weight: 600; 54 | margin-top: 16px; 55 | margin-bottom: 8px; 56 | } 57 | 58 | #Vol__Cards p { 59 | font-size: 14px; 60 | color: #7f8c9b; 61 | line-height: 150%; 62 | letter-spacing: 1px; 63 | margin: 0px; 64 | padding: 2px 0px; 65 | } 66 | 67 | .card__details { 68 | padding: 16px 8px 8px 8px; 69 | } 70 | 71 | @media screen and (max-width: 576px) { 72 | #Vol__Cards > .row { 73 | max-width: 255px; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /templates/volunteers/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Volunteers {% endblock %} 6 | 7 | {% block style %} 8 | 9 | {% endblock %} 10 | 11 | {% block content %} 12 | 13 |
14 |
15 | Header Image 16 |
17 |
18 | 19 | 20 |
21 | {% if volunteers %} 22 |
23 | {% for vol in volunteers %} 24 |
25 |
26 | Profile Image 27 |
28 | {% if vol.desig %} 29 | {{ vol.desig }} 30 | {% endif %} 31 |
{{ vol.profile.get_full_name }}
32 |

Roll No: {{ vol.roll_no }}

33 |

Batch: {{ vol.batch }}

34 |
35 | 36 |
37 |
38 | {% endfor %} 39 |
40 | {% else %} 41 |

42 | There are no active volunteer. 43 |

44 | {% endif %} 45 |
46 | {% endblock %} 47 | 48 | {% block scripts %} 49 | 50 | {% endblock %} -------------------------------------------------------------------------------- /templates/students/leaderboard.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Volunteer Leaderboard {% endblock %} 6 | 7 | {% block content %} 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% for stud in students %} 26 | 27 | 28 | 29 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | {% endfor %} 43 | 44 |
#NameClassVillageTotal DaysHW Done
{{forloop.counter}} 30 | 31 | {{ stud.student__first_name }} 32 | 33 | {{ stud.student__last_name }} 34 | 35 | {{ stud.student__school_class }}{{ stud.student__village }}{{ stud.total_attendance }}{{ stud.total_hw_done }}
45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /.github/workflows/python_lint.yml: -------------------------------------------------------------------------------- 1 | ########################### 2 | ########################### 3 | ## PyLint GitHub Actions ## 4 | ########################### 5 | ########################### 6 | name: Lint the Code Base 7 | 8 | # 9 | # Documentation: 10 | # https://help.github.com/en/articles/workflow-syntax-for-github-actions 11 | # 12 | 13 | ############################# 14 | # Start the job on all push # 15 | ############################# 16 | on: 17 | pull_request: 18 | branches: [master] 19 | push: 20 | branches: [master] 21 | 22 | ############### 23 | # Set the Job # 24 | ############### 25 | jobs: 26 | build: 27 | # Name the Job 28 | name: Flake8 Code 29 | # Set the agent to run on 30 | runs-on: ubuntu-latest 31 | 32 | ################## 33 | # Load all steps # 34 | ################## 35 | steps: 36 | 37 | ########################## 38 | # Checkout the code base # 39 | ########################## 40 | - name: Checkout Code 41 | uses: actions/checkout@v2 42 | with: 43 | # Full git history is needed to get a proper list of changed files within `super-linter` 44 | fetch-depth: 0 45 | 46 | ################################ 47 | # Run Linter against code base # 48 | ################################ 49 | - name: Flake8 50 | uses: github/super-linter@v3 51 | env: 52 | VALIDATE_ALL_CODEBASE: false 53 | VALIDATE_PYTHON: true 54 | VALIDATE_PYTHON_FLAKE8: true 55 | DEFAULT_BRANCH: master 56 | LINTER_RULES_PATH: /.github/linters 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | PYTHON_FLAKE8_CONFIG_FILE: .flake8.yml 59 | -------------------------------------------------------------------------------- /templates/students/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Students {% endblock %} 6 | 7 | {% block style %} 8 | 9 | {% endblock %} 10 | 11 | {% block content %} 12 |
13 |
14 | Header Image 15 |
16 |
17 | 18 | 19 |
20 |
21 |

22 | Students 23 |

24 |
25 |
26 | 27 |
28 | {% if students %} 29 |
30 | {% for student in students %} 31 |
32 |
33 | Profile Image 34 |
35 |
{{ student.get_full_name }}
36 |

Class: {{ student.school_class }}

37 |

Village: {{ student.get_village_display }}

38 |
39 | 40 |
41 |
42 | {% endfor %} 43 |
44 | {% else %} 45 |

46 | There are no active students. 47 |

48 | {% endif %} 49 |
50 | {% endblock %} -------------------------------------------------------------------------------- /apps/events/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib import messages 2 | from django.contrib.auth.decorators import login_required, user_passes_test 3 | from django.http import HttpResponse 4 | from django.shortcuts import render, redirect 5 | from django.urls import reverse_lazy 6 | 7 | from home.views import has_authenticated_profile 8 | from .models import Event, Gallery 9 | 10 | 11 | def index(request): 12 | events = Event.objects.all() 13 | context = {'events': events, } 14 | return render(request, "events/index.html", context) 15 | 16 | 17 | def captures(request): 18 | gallery = Gallery.objects.all().order_by('-event__schedule') 19 | gallery_dict = {} 20 | 21 | for image in gallery: 22 | if image.event.title not in gallery_dict.keys(): 23 | gallery_dict[image.event.title] = [] 24 | gallery_dict[image.event.title].append(image) 25 | 26 | context = {'gallery_dict': gallery_dict} 27 | return render(request, 'events/captures.html', context) 28 | 29 | 30 | @login_required 31 | @user_passes_test( 32 | has_authenticated_profile, 33 | login_url=reverse_lazy('accounts:complete_profile') 34 | ) 35 | # @permission_required('events.add_event', raise_exception=True) 36 | def add_event(request): 37 | if request.method == 'POST': 38 | title = request.POST['title'] 39 | description = request.POST['description'] 40 | schedule = request.POST['schedule'] 41 | venue = request.POST['venue'] 42 | thumbnail = request.FILES.get('thumbnail') 43 | 44 | event = Event( 45 | title=title, schedule=schedule, venue=venue, 46 | description=description, thumbnail=thumbnail, 47 | ) 48 | event.save() 49 | 50 | messages.success(request, "Event added successfully!") 51 | return redirect('events:add_event') 52 | 53 | return render(request, 'events/add_event.html') 54 | -------------------------------------------------------------------------------- /static/home/js/glide.js: -------------------------------------------------------------------------------- 1 | var glide = new Glide('.glide',{ 2 | type: 'slider', 3 | focusAt: 'center', 4 | perView: 2, 5 | autoplay: 2000, 6 | gap: 30, 7 | breakpoints: { 8 | 760:{ 9 | perView: 1, 10 | 11 | } 12 | } 13 | }) 14 | 15 | var ele = document.querySelectorAll(".glide__slides li") 16 | var ele1 = document.querySelectorAll(".glide__slide--clone") 17 | // ele1[1].classList.add("llll") 18 | // ele1[2].classList.add("rrrr") 19 | console.log(ele1) 20 | 21 | glide.on(['mount.after', 'run'], function () { 22 | var a = glide.index 23 | // var l= a==0?8:a-1 24 | // var r= a==8?0:a+1 25 | // console.log(ele[l]); 26 | // console.log(ele[r]); 27 | for(let i=0; i<9; i++){ 28 | ele[i].classList.remove("rrrr"); 29 | ele[i].classList.remove("llll"); 30 | } 31 | if(a!=0) ele[a-1].classList.add("llll"); 32 | // ele[l].classList.remove("rrrr"); 33 | // ele[r].classList.remove("llll"); 34 | if(a!=8) ele[a+1].classList.add("rrrr"); 35 | // ele[a].classList.remove("rrrr"); 36 | // ele[a].classList.remove("llll"); 37 | 38 | }) 39 | 40 | glide.mount() 41 | 42 | // 43 | for(let i=0; i<9; i++){ 44 | document.querySelectorAll(".card")[i].addEventListener('touchstart', function(e) { 45 | e.preventDefault(); 46 | document.querySelectorAll(".card")[i].classList.add("card_hover"); 47 | document.querySelectorAll(".card1")[i].classList.add("card1_hover"); 48 | document.querySelectorAll(".card_h2")[i].classList.add("h_hover"); 49 | }, false); 50 | document.querySelectorAll(".card")[i].addEventListener('touchend', function() { 51 | document.querySelectorAll(".card")[i].classList.remove("card_hover"); 52 | document.querySelectorAll(".card1")[i].classList.remove("card1_hover"); 53 | document.querySelectorAll(".card_h2")[i].classList.remove("h_hover"); 54 | }, false); 55 | } 56 | // console.log(document.querySelector("#initiatives h2")); -------------------------------------------------------------------------------- /templates/events/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Events {% endblock %} 6 | 7 | {% block style %} 8 | 42 | {% endblock %} 43 | 44 | {% block content %} 45 |
46 |

EVENTS 47 | 48 |

49 | {% if events %} 50 |
51 | {% for event in events %} 52 |
53 |
54 | thumbnail 55 |
56 |

Title: {{event.title}}

57 |

Venue: {{event.venue}}

58 |

Description: {{event.description}}

59 |
60 |
61 |
62 | {% endfor %} 63 |
64 | {% else %} 65 |

No events to show yet.

66 | {% endif %} 67 |
68 | {% endblock %} -------------------------------------------------------------------------------- /apps/feedbacks/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | from django.views.decorators.csrf import csrf_exempt 3 | from django.contrib import messages 4 | from .models import Feedback, Contact 5 | 6 | 7 | def index(request): 8 | if request.method == 'POST': 9 | anonymous_array = request.POST.getlist('anonymousCheck') 10 | name = request.POST['name'] 11 | roll_no = request.POST['rollNo'] 12 | email = request.POST['email'] 13 | feedback = request.POST['feedback'] 14 | if len(anonymous_array) != 0: 15 | feedback = Feedback(name='Anonymous', feedback=feedback) 16 | feedback.save() 17 | else: 18 | feedback = Feedback(name=name, roll_no=roll_no, email=email, feedback=feedback) 19 | feedback.save() 20 | return redirect('feedbacks:feedback_submitted') 21 | 22 | context = { 23 | 'logout_redirect_site': request.path, 24 | 'login_redirect_site': request.path, 25 | } 26 | return render(request, 'feedbacks/index.html', context) 27 | 28 | 29 | def feedback_submitted(request): 30 | return render(request, 'feedbacks/feedback_submitted.html') 31 | 32 | 33 | @csrf_exempt 34 | def contact(request): 35 | if request.method == 'POST': 36 | try: 37 | name = request.POST['full_name'] 38 | phone = request.POST['phone'] 39 | email = request.POST['email_id'] 40 | msg = request.POST['msg'] 41 | contact_data = Contact(name=name, phone=phone, email=email, message=msg) 42 | contact_data.save() 43 | messages.success(request, 'We got your message, Someone from our team will shortly contact you.') 44 | return redirect('home:new_index') 45 | except Exception: 46 | messages.error(request, 'Error, On Submitting the contact form.') 47 | return redirect('home:new_index') 48 | return redirect('home:new_index') 49 | -------------------------------------------------------------------------------- /templates/registration/password_change_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block title %} Jagrati | Change Password {% endblock %} 4 | 5 | {% block style %} 6 | 40 | 41 | {% endblock %} 42 | 43 | {% block content %} 44 | 63 | {% endblock %} -------------------------------------------------------------------------------- /apps/events/models.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.db import models 3 | 4 | from apps.volunteers.models import Volunteer 5 | from apps.students.models import Student 6 | 7 | 8 | def event_thumbmail_path(instance, filename): 9 | return f'events/{instance.id}/thumbnail/{filename}' 10 | 11 | 12 | class Event(models.Model): 13 | title = models.CharField(max_length=100) 14 | description = models.TextField(max_length=2500) 15 | schedule = models.DateTimeField() 16 | venue = models.CharField(max_length=50) 17 | thumbnail = models.ImageField( 18 | upload_to=event_thumbmail_path, null=True, blank=True) 19 | 20 | def __str__(self): 21 | return self.title 22 | 23 | @property 24 | def get_thumbnail_url(self): 25 | if self.thumbnail and hasattr(self.thumbnail, 'url'): 26 | return self.thumbnail.url 27 | else: 28 | return settings.STATIC_URL + 'home/images/02.jpg' 29 | 30 | 31 | class Team(models.Model): 32 | team_id = models.CharField(max_length=50, unique=True) 33 | name = models.CharField(max_length=50) 34 | 35 | def __str__(self): 36 | return self.name 37 | 38 | 39 | class Management(models.Model): 40 | volunteer = models.ForeignKey(Volunteer, on_delete=models.CASCADE) 41 | event = models.ForeignKey(Event, on_delete=models.CASCADE) 42 | team = models.ForeignKey(Team, on_delete=models.CASCADE) 43 | 44 | def __str__(self): 45 | return f'{self.id}' 46 | 47 | 48 | class Participant(models.Model): 49 | student = models.ForeignKey(Student, on_delete=models.CASCADE) 50 | event = models.ForeignKey(Event, on_delete=models.CASCADE) 51 | 52 | def __str__(self): 53 | return f'{self.id}' 54 | 55 | 56 | def event_gallery_path(instance, filename): 57 | return f'events/{instance.id}/{filename}' 58 | 59 | 60 | class Gallery(models.Model): 61 | event = models.ForeignKey(Event, on_delete=models.CASCADE) 62 | photo = models.ImageField(upload_to=event_gallery_path) 63 | # Whether to display the image on Captures Page or not 64 | capture = models.BooleanField(default=False) 65 | 66 | def __str__(self): 67 | return f's{self.id}' 68 | -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, reverse_lazy 2 | from . import views 3 | 4 | from django.contrib.auth import views as auth_views 5 | 6 | app_name = 'accounts' 7 | urlpatterns = [ 8 | path('login/', views.login_signup, name='login_signup'), 9 | path('complete_profile/', views.complete_profile, name='complete_profile'), 10 | path('logout/', views.logout_view, name='logout'), 11 | path('resend_activation_mail/', views.resend_activation_mail, 12 | name='resend_activation_mail'), 13 | path('activate///', 14 | views.account_activation, name='account_activation'), 15 | path('authenticate///', 16 | views.account_authentication, name='account_authentication'), 17 | 18 | path('signup/success/', views.signup_success, name='signup_success'), 19 | path('profile_completed/', views.profile_completed, name='profile_completed'), 20 | path('authenticated/', views.account_authenticated, 21 | name='account_authenticated'), 22 | 23 | # Django Auth URLs 24 | path('password_change/', 25 | auth_views.PasswordChangeView.as_view( 26 | success_url=reverse_lazy('accounts:password_change_done')), 27 | name='password_change'), 28 | path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(), 29 | name='password_change_done'), 30 | path('password_reset/', 31 | auth_views.PasswordResetView.as_view( 32 | success_url=reverse_lazy('accounts:password_reset_done')), 33 | name='password_reset'), 34 | path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), 35 | name='password_reset_done'), 36 | path('reset///', 37 | auth_views.PasswordResetConfirmView.as_view( 38 | success_url=reverse_lazy('accounts:password_reset_complete')), 39 | name='password_reset_confirm'), 40 | # path('reset///', views.CustomPasswordResetConfirmView.as_view(), name='password_reset_confirm'), 41 | path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), 42 | name='password_reset_complete'), 43 | 44 | # AJAX call URLs 45 | path('ajax_volunteer_rollcheck/', views.ajax_volunteer_rollcheck, 46 | name='ajax_volunteer_rollcheck'), 47 | ] 48 | -------------------------------------------------------------------------------- /templates/registration/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% load static %} 3 | {% block title %} Jagrati | Password Reset {% endblock %} 4 | 5 | {% block style %} 6 | 44 | {% endblock %} 45 | 46 | {% block content %} 47 |
48 |
49 |
50 | image 51 |
52 |
53 |
54 | 55 |

Reset password

56 |
57 | {% csrf_token %} 58 |
59 | 61 |
62 |
63 | 64 |
65 |
66 |
67 |
68 |
69 |
70 | {% endblock %} -------------------------------------------------------------------------------- /home/context_processors.py: -------------------------------------------------------------------------------- 1 | # from datetime import datetime, date 2 | # import json 3 | # from django.core.serializers.json import DjangoJSONEncoder 4 | # from django.forms.models import model_to_dict 5 | 6 | from accounts.models import Profile 7 | from apps.volunteers.models import Volunteer, VolunteerSchedule 8 | 9 | 10 | def database_context(request): 11 | profile = volun = volun_sch = None 12 | if request.user.is_authenticated: 13 | user = request.user 14 | profile = Profile.objects.filter(user=user).first() 15 | if profile is not None and user.desig == 'v': 16 | volun = Volunteer.objects.get(profile=profile) 17 | if volun is not None: 18 | volun_sch = VolunteerSchedule.objects.filter(volun=volun).first() 19 | 20 | # Student's dictionary for AJAX 21 | # students = Student.objects.all() 22 | # stu_dict = {} 23 | 24 | # for stu in students: 25 | # stu_dict[stu.id] = model_to_dict(stu) 26 | 27 | # stu_dict_json = json.dumps(stu_dict) 28 | 29 | # Volunteer's dictionary for AJAX 30 | # volunteers = Volunteer.objects.all() 31 | # vol_dict = {} 32 | 33 | # for vol in volunteers: 34 | # vol_dict[vol.id] = model_to_dict(vol) 35 | 36 | # vol_dict_json = json.dumps(vol_dict, cls=DjangoJSONEncoder) # For encoding date 37 | 38 | # Schedule dictionary for AJAX 39 | # schedules = Schedule.objects.all() 40 | # sch_dict = {} 41 | 42 | # for sch in schedules: 43 | # sch_dict[sch.id] = model_to_dict(sch) 44 | 45 | # sch_dict_json = json.dumps(sch_dict) 46 | 47 | # return { 48 | # 'volunteer': volunteer, 49 | # # 'volunteers': volunteers, 50 | # # 'vol_dict_json' : vol_dict_json, 51 | # 'vol_schedule': vol_schedule, 52 | # # 'vol_schedules': VolunteerSchedule.objects.all(), 53 | # # 'schedules' : Schedule.objects.order_by('section__section_id'), 54 | # # 'sch_dict_json' : sch_dict_json, 55 | # # 'today_vol_att' : VolunteerAttendance.objects.filter(date=date.today()), 56 | # # 'today_stu_att' : StudentAttendance.objects.filter(date=date.today()), 57 | # # 'students' : students, 58 | # # 'stu_dict_json' : stu_dict_json, 59 | # } 60 | 61 | return { 62 | 'profile': profile, 63 | 'volun': volun, 64 | 'volun_sch': volun_sch, 65 | } 66 | -------------------------------------------------------------------------------- /home/models.py: -------------------------------------------------------------------------------- 1 | import calendar 2 | from django.db import models 3 | 4 | 5 | class Calendar(models.Model): 6 | date = models.DateField(primary_key=True) 7 | remark = models.TextField(max_length=255, blank=True) 8 | class_scheduled = models.BooleanField(default=True) 9 | 10 | class Meta: 11 | verbose_name_plural = 'Calendar' 12 | 13 | def __str__(self): 14 | return str(self.date) 15 | 16 | 17 | class Section(models.Model): 18 | # For grouping and sorting 19 | section_id = models.CharField(max_length=5, unique=True) 20 | name = models.CharField(max_length=30, unique=True) 21 | is_parent_section = models.BooleanField(default=False) 22 | parent_section = models.ForeignKey( 23 | 'self', null=True, blank=True, on_delete=models.SET_NULL, limit_choices_to={'is_parent_section': True}) 24 | 25 | def __str__(self): 26 | return self.name 27 | 28 | 29 | class Schedule(models.Model): 30 | # They won't ever change and will give us dropdown in Admin site 31 | DAY = [((i+1)%7, calendar.day_name[i]) for i in range(0, 7)] 32 | 33 | SUBJECT = ( 34 | ('eng', "English"), 35 | ('hin', "Hindi"), 36 | ('mat', "Mathematics"), 37 | ('sci', "Science"), 38 | ('ssc', "Social Science"), 39 | ('mab', "Mental Ability"), 40 | ) 41 | 42 | day = models.IntegerField(choices=DAY) 43 | section = models.ForeignKey(Section, on_delete=models.CASCADE) 44 | subject = models.CharField(max_length=3, choices=SUBJECT) 45 | 46 | class Meta: 47 | unique_together = (('day', 'section'),) 48 | 49 | def __str__(self): 50 | return f'{self.get_day_display()} - {self.section.name} - {self.get_subject_display()}' 51 | 52 | 53 | class ClassworkHomework(models.Model): 54 | cal_date = models.ForeignKey(Calendar, on_delete=models.PROTECT) 55 | section = models.ForeignKey(Section, on_delete=models.CASCADE) 56 | # Content to be taught 57 | to_be_taught = models.TextField(max_length=1023, blank=True) 58 | subject_taught = models.CharField(max_length=3, choices=Schedule.SUBJECT) 59 | cw = models.TextField(max_length=1023, blank=True) 60 | hw = models.TextField(max_length=1023, blank=True) 61 | comment = models.TextField(max_length=1023, blank=True) 62 | 63 | class Meta: 64 | unique_together = (('cal_date', 'section'),) 65 | verbose_name = 'ClassWork/HomeWork' 66 | verbose_name_plural = 'ClassWork/HomeWork' 67 | 68 | def __str__(self): 69 | return f'{self.cal_date} - {self.section.name}' 70 | -------------------------------------------------------------------------------- /apps/events/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Event, Team, Management, Participant, Gallery 4 | 5 | 6 | @admin.register(Event) 7 | class EventAdmin(admin.ModelAdmin): 8 | list_display = ('title', 'schedule', 'venue') 9 | search_fields = ('title', 'venue') 10 | ordering = ('-schedule',) 11 | 12 | 13 | @admin.register(Team) 14 | class TeamAdmin(admin.ModelAdmin): 15 | list_display = ('team_id', 'name') 16 | search_fields = ('name',) 17 | ordering = ('team_id',) 18 | 19 | 20 | @admin.register(Management) 21 | class ManagementAdmin(admin.ModelAdmin): 22 | list_display = ('get_event_title', 'get_team_name', 'get_volunteer_name') 23 | search_fields = ('event__title', 'team__name', 'volunteer__profile__first_name', 24 | 'volunteer__profile__last_name') 25 | list_filter = ('team__name',) 26 | ordering = ('-event__schedule', 'team__name') 27 | 28 | def get_event_title(self, obj): 29 | return obj.event.title 30 | get_event_title.short_description = 'Event Title' 31 | get_event_title.admin_order_field = 'event__title' 32 | 33 | def get_team_name(self, obj): 34 | return obj.event.title 35 | get_team_name.short_description = 'Team Name' 36 | get_team_name.admin_order_field = 'team__name' 37 | 38 | def get_volunteer_name(self, obj): 39 | return obj.volunteer.profile.get_full_name 40 | get_volunteer_name.short_description = 'Volunteer Name' 41 | get_volunteer_name.admin_order_field = 'volunteer__profile__first_name' 42 | 43 | 44 | @admin.register(Participant) 45 | class ParticipantAdmin(admin.ModelAdmin): 46 | list_display = ('get_event_title', 'get_student_name') 47 | search_fields = ('event__title', 'student__first_name', 48 | 'student__last_name') 49 | ordering = ('-event__schedule',) 50 | 51 | def get_event_title(self, obj): 52 | return obj.event.title 53 | get_event_title.short_description = 'Event Title' 54 | get_event_title.admin_order_field = 'event__title' 55 | 56 | def get_student_name(self, obj): 57 | return obj.student.get_full_name 58 | get_student_name.short_description = 'Student Name' 59 | get_student_name.admin_order_field = 'student__first_name' 60 | 61 | 62 | @admin.register(Gallery) 63 | class GalleryAdmin(admin.ModelAdmin): 64 | list_display = ('get_event_title', 'photo', 'capture') 65 | search_fields = ('event__title',) 66 | list_filter = ('capture',) 67 | ordering = ('-event__schedule',) 68 | 69 | def get_event_title(self, obj): 70 | return obj.event.title 71 | get_event_title.short_description = 'Event Title' 72 | get_event_title.admin_order_field = 'event__title' 73 | -------------------------------------------------------------------------------- /apps/students/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .forms import StudentScheduleAdminForm 4 | from .models import ( 5 | Student, StudentAttendance, StudentSchedule, 6 | ) 7 | 8 | 9 | @admin.register(Student) 10 | class StudentAdmin(admin.ModelAdmin): 11 | list_display = ('get_name', 'school_class', 'village') 12 | search_fields = ('first_name', 'last_name') 13 | list_filter = ('school_class', 'village') 14 | ordering = ('school_class', 'first_name') 15 | 16 | def get_name(self, obj): 17 | return obj.get_full_name 18 | get_name.short_description = 'Name' 19 | get_name.admin_order_field = 'first_name' 20 | 21 | 22 | @admin.register(StudentSchedule) 23 | class StudentScheduleAdmin(admin.ModelAdmin): 24 | form = StudentScheduleAdminForm 25 | 26 | list_display = ('get_class', 'get_name', 'day', 'get_section') 27 | search_fields = ('student__first_name', 'student__last_name') 28 | list_filter = ('day', 'student__school_class', 'schedule__section__name') 29 | ordering = ('student__school_class', 'student__first_name', 'day') 30 | 31 | def get_class(self, obj): 32 | return obj.student.school_class 33 | get_class.short_description = 'Class' 34 | get_class.admin_order_field = 'student__school_class' 35 | 36 | def get_name(self, obj): 37 | return obj.student.get_full_name 38 | get_name.short_description = 'Name' 39 | get_name.admin_order_field = 'student__first_name' 40 | 41 | def get_section(self, obj): 42 | return obj.schedule.section.name 43 | get_section.short_description = 'Section' 44 | get_section.admin_order_field = 'schedule__section__section_id' 45 | 46 | 47 | @admin.register(StudentAttendance) 48 | class StudentAttendanceAdmin(admin.ModelAdmin): 49 | list_display = ('cal_date', 'get_name', 'get_class', 50 | 'get_village', 'present', 'hw_done') 51 | search_fields = ('cal_date', 'student__first_name', 'student__last_name') 52 | list_filter = ('present', 'student__school_class', 53 | 'student__village', 'hw_done') 54 | ordering = ('-cal_date', 'student__school_class', 'student__first_name') 55 | 56 | def get_name(self, obj): 57 | return obj.student.get_full_name 58 | get_name.short_description = 'Name' 59 | get_name.admin_order_field = 'student__first_name' 60 | 61 | def get_class(self, obj): 62 | return obj.student.school_class 63 | get_class.short_description = 'Class' 64 | get_class.admin_order_field = 'student__school_class' 65 | 66 | def get_village(self, obj): 67 | return obj.student.get_village_display() 68 | get_village.short_description = 'Village' 69 | get_village.admin_order_field = 'student__village' 70 | -------------------------------------------------------------------------------- /templates/registration/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block title %} Jagrati | Password Reset {% endblock %} 4 | 5 | {% block style %} 6 | 42 | {% endblock %} 43 | 44 | 45 | {% block content %} 46 | {% if validlink %} 47 | 69 | {% else %} 70 |
71 |
72 | 73 |

Token Expired

74 |

75 | The password reset link was invalid, possibly because it has already been used. 76 | Try signing in with your new credentials or request a new 77 | password reset. 78 |

79 |
80 |
81 | {% endif %} 82 | {% endblock %} -------------------------------------------------------------------------------- /templates/events/captures.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati Captures ❤ {% endblock %} 6 | 7 | {% block style %} 8 | 11 | 14 | 15 | 16 | 17 | 22 | {% endblock %} 23 | 24 | {% block content %} 25 |
26 |
27 |
28 |

CAPTURES 29 | 30 |

31 |
32 | 33 | {% for event_title, images in gallery_dict.items %} 34 |
35 |

{{ event_title }}

36 |
37 | {% for img in images %} 38 |
39 | 40 | gallery_image 41 | 42 |
43 | {% endfor %} 44 |
45 |
46 | {% endfor %} 47 |
48 |
49 | 50 | 53 | 54 | {% endblock %} 55 | 56 | 57 | {% block scripts %} 58 | 61 | 64 | 65 | 68 | 69 | {% endblock %} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Django # 2 | *.log 3 | *.pot 4 | *.pyc 5 | __pycache__ 6 | db.sqlite3 7 | media 8 | **/migrations/* 9 | !**/migrations/__init__.py 10 | 11 | # IDEs # 12 | .vscode 13 | .idea 14 | 15 | # Backup files # 16 | *.bak 17 | 18 | # If you are using PyCharm # 19 | .idea/**/workspace.xml 20 | .idea/**/tasks.xml 21 | .idea/dictionaries 22 | .idea/**/dataSources/ 23 | .idea/**/dataSources.ids 24 | .idea/**/dataSources.xml 25 | .idea/**/dataSources.local.xml 26 | .idea/**/sqlDataSources.xml 27 | .idea/**/dynamic.xml 28 | .idea/**/uiDesigner.xml 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | *.iws /out/ 32 | 33 | # Python # 34 | __pycache__/ 35 | *.py[cod] 36 | *$py.class 37 | 38 | # C extensions 39 | *.so 40 | 41 | # Distribution / packaging 42 | .Python 43 | build/ 44 | develop-eggs/ 45 | dist/ 46 | downloads/ 47 | eggs/ 48 | .eggs/ 49 | lib/ 50 | lib64/ 51 | parts/ 52 | sdist/ 53 | var/ 54 | wheels/ 55 | *.egg-info/ 56 | .installed.cfg 57 | *.egg 58 | MANIFEST 59 | 60 | # PyInstaller 61 | # Usually these files are written by a python script from a template 62 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 63 | *.manifest 64 | *.spec 65 | 66 | # Installer logs 67 | pip-log.txt 68 | pip-delete-this-directory.txt 69 | 70 | # Unit test / coverage reports 71 | htmlcov/ 72 | .tox/ 73 | .coverage 74 | .coverage.* 75 | .cache 76 | nosetests.xml 77 | coverage.xml 78 | *.cover 79 | .hypothesis/ 80 | .pytest_cache/ 81 | 82 | # Translations 83 | *.mo 84 | *.pot 85 | 86 | # Django stuff: 87 | *.log 88 | local_settings.py 89 | db.sqlite3 90 | 91 | # Flask stuff: 92 | instance/ 93 | .webassets-cache 94 | 95 | # Scrapy stuff: 96 | .scrapy 97 | 98 | # Sphinx documentation 99 | docs/_build/ 100 | 101 | # PyBuilder 102 | target/ 103 | 104 | # Jupyter Notebook 105 | .ipynb_checkpoints 106 | 107 | # pyenv 108 | .python-version 109 | 110 | # celery 111 | celerybeat-schedule.* 112 | 113 | # SageMath parsed files 114 | *.sage.py 115 | 116 | # Environments 117 | .env 118 | .venv 119 | env/ 120 | venv/ 121 | ENV/ 122 | env.bak/ 123 | venv.bak/ 124 | 125 | # Spyder project settings 126 | .spyderproject 127 | .spyproject 128 | 129 | # Rope project settings 130 | .ropeproject 131 | 132 | # mkdocs documentation 133 | /site 134 | 135 | # mypy 136 | .mypy_cache/ 137 | 138 | # Sublime Text # 139 | *.tmlanguage.cache 140 | *.tmPreferences.cache 141 | *.stTheme.cache 142 | *.sublime-workspace 143 | *.sublime-project 144 | 145 | # sftp configuration file 146 | sftp-config.json 147 | 148 | # Package control specific files Package 149 | Control.last-run 150 | Control.ca-list 151 | Control.ca-bundle 152 | Control.system-ca-bundle 153 | GitHub.sublime-settings 154 | 155 | # Visual Studio Code # 156 | .vscode/* 157 | !.vscode/settings.json 158 | !.vscode/tasks.json 159 | !.vscode/launch.json 160 | !.vscode/extensions.json 161 | .history 162 | 163 | # Virtual Environment # 164 | pyvenv.cfg 165 | -------------------------------------------------------------------------------- /templates/snippets/header.html: -------------------------------------------------------------------------------- 1 | 2 | {% comment %} 3 |
4 |

5 | Jagrati 6 |

7 | 13 | {% if user.is_authenticated and user.is_active%} 14 | Dashboard 15 | 16 | {% if logout_redirect_site %} 17 | Sign Out 18 | {% else %} 19 | Sign Out 20 | {% endif %} 21 | 22 | {% else %} 23 | Sign In 24 | {% endif %} 25 |
26 | {% endcomment %} 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /accounts/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from .models import User 4 | 5 | 6 | class UserAdminCreationForm(forms.ModelForm): 7 | """A form for creating new users. Includes all the required 8 | fields, plus a repeated password.""" 9 | password1 = forms.CharField(label='Password', widget=forms.PasswordInput) 10 | password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) 11 | 12 | class Meta: 13 | model = User 14 | fields = ('email', 'desig') 15 | 16 | def clean_password2(self): 17 | # Check that the two password entries match 18 | password1 = self.cleaned_data.get("password1") 19 | password2 = self.cleaned_data.get("password2") 20 | if password1 and password2 and password1 != password2: 21 | raise forms.ValidationError("Passwords don't match") 22 | return password2 23 | 24 | def save(self, commit=True): 25 | # Save the provided password in hashed format 26 | user = super(UserAdminCreationForm, self).save(commit=False) 27 | user.set_password(self.cleaned_data["password1"]) 28 | if commit: 29 | user.save() 30 | return user 31 | 32 | 33 | # No need of any validations or checks in UserChange like in UserCreation. 34 | 35 | # from django.contrib.auth.forms import ReadOnlyPasswordHashField 36 | 37 | # class UserAdminChangeForm(forms.ModelForm): 38 | # """A form for updating users. Includes all the fields on 39 | # the user, but replaces the password field with admin's 40 | # password hash display field. 41 | # """ 42 | # password = ReadOnlyPasswordHashField() 43 | 44 | # class Meta: 45 | # model = User 46 | # fields = ('email', 'password', 'desig', 'is_active', 'is_staff', 'is_superuser') 47 | 48 | # def clean_password(self): 49 | # # Regardless of what the user provides, return the initial value. 50 | # # This is done here, rather than on the field, because the 51 | # # field does not have access to the initial value 52 | # return self.initial["password"] 53 | 54 | 55 | 56 | 57 | # MAIN FORM ENDS HERE 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | # class LoginForm(forms.Form): 66 | # email = forms.EmailField() 67 | # password = forms.CharField(widget=forms.PasswordInput) 68 | 69 | 70 | # class SignUpForm(forms.ModelForm): 71 | # password = forms.CharField(widget=forms.PasswordInput) 72 | # password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput) 73 | 74 | # class Meta: 75 | # model = User 76 | # fields = ('email', 'desig') 77 | 78 | # def clean_email(self): 79 | # email = self.cleaned_data.get('email') 80 | # qs = User.objects.filter(email=email) 81 | # if qs.exists(): 82 | # raise forms.ValidationError("email is taken") 83 | # return email 84 | 85 | # def clean_password2(self): 86 | # # Check that the two password entries match 87 | # password1 = self.cleaned_data.get("password1") 88 | # password2 = self.cleaned_data.get("password2") 89 | # if password1 and password2 and password1 != password2: 90 | # raise forms.ValidationError("Passwords don't match") 91 | # return password2 -------------------------------------------------------------------------------- /templates/volunteers/volunteers_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'sidebar.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Volunteers List {% endblock %} 6 | 7 | {% block content-sidebar %} 8 | 9 |
10 | ⟳ Refresh Page 11 |

Volunteers Schedule

12 |
13 |
14 | 20 |
21 |
22 | 23 |
24 |
25 |

Registered Volunteers

26 |
27 |
28 |
29 |
30 |
31 | {% endblock %} 32 | 33 | {% block scripts-sidebar %} 34 | 35 | 86 | {% endblock %} -------------------------------------------------------------------------------- /home/api/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.contrib.sites.shortcuts import get_current_site 3 | from django.core.mail import send_mail 4 | from django.http import HttpResponse, JsonResponse 5 | from django.template.loader import render_to_string 6 | from django.utils.encoding import force_bytes 7 | from django.utils.html import strip_tags 8 | from django.utils.http import urlsafe_base64_encode 9 | 10 | from rest_framework import status 11 | from rest_framework.authentication import TokenAuthentication 12 | from rest_framework.decorators import api_view, authentication_classes, permission_classes 13 | from rest_framework.permissions import IsAuthenticated 14 | from rest_framework.response import Response 15 | from rest_framework.views import APIView 16 | 17 | from accounts.tokens import account_activation_token 18 | from home.api.serializers import UpdateProfileSerializer 19 | from accounts.models import Profile 20 | 21 | 22 | # VIEWS FUNCTIONS 23 | 24 | @api_view(['POST']) 25 | @permission_classes([IsAuthenticated]) 26 | @authentication_classes([TokenAuthentication]) 27 | def create_profile_view(request): 28 | profile = Profile.objects.filter(user=request.user) 29 | if profile.exists(): 30 | data = { 31 | 'response': 'Error', 32 | 'error_message': 'Profile already exists.' 33 | } 34 | return Response(data, status=400) 35 | else: 36 | profile = Profile(user=request.user) 37 | 38 | serializer = UpdateProfileSerializer(profile, data=request.data) 39 | # print(repr(serializer)) 40 | data = {} 41 | if serializer.is_valid(): 42 | serializer.save() 43 | data['response'] = "Profile Created Successfully!" 44 | 45 | # Notify Admin for New User Sign Up 46 | volun = Profile.objects.get(user=request.user) 47 | current_site = get_current_site(request) 48 | 49 | from_email = settings.DEFAULT_FROM_EMAIL 50 | to = settings.ADMINS_EMAIL 51 | subject = '[noreply] New User Signed Up' 52 | html_message = render_to_string('accounts/email/account_authentication_email.html', { 53 | 'volun': volun, 54 | 'domain': current_site.domain, 55 | 'uid':urlsafe_base64_encode(force_bytes(volun.email.pk)), 56 | 'token':account_activation_token.make_token(volun.email), 57 | }) 58 | plain_message = strip_tags(html_message) 59 | send_mail( 60 | subject, plain_message, from_email, to, 61 | fail_silently=False, html_message=html_message, 62 | ) 63 | return Response(data, status=201) 64 | return Response(serializer.errors, status=400) 65 | 66 | 67 | 68 | @api_view(['GET', 'PUT']) 69 | @permission_classes([IsAuthenticated]) 70 | @authentication_classes([TokenAuthentication]) 71 | def update_profile_view(request): 72 | 73 | try: 74 | volun = Profile.objects.get(user=request.user) 75 | except Profile.DoesNotExist: 76 | return Response(status=404) 77 | 78 | if request.method == 'GET': 79 | serializer = UpdateProfileSerializer(volun) 80 | return Response(serializer.data) 81 | 82 | elif request.method == 'PUT': 83 | serializer = UpdateProfileSerializer(volun, data=request.data) 84 | data = {} 85 | if serializer.is_valid(): 86 | serializer.save() 87 | data['response'] = "Profile Updated Successfully!" 88 | data['data'] = serializer.data 89 | return Response(data) 90 | return Response(serializer.errors, status=400) 91 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

Contributor Covenant Code of Conduct

2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that 59 | is deemed necessary and appropriate to the circumstances. The project team is 60 | obligated to maintain confidentiality with regard to the reporter of an incident. 61 | Further details of specific enforcement policies may be posted separately. 62 | 63 | Project maintainers who do not follow or enforce the Code of Conduct in good 64 | faith may face temporary or permanent repercussions as determined by other 65 | members of the project's leadership. 66 | 67 | ## Attribution 68 | 69 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 70 | available at [here](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html) 71 | 72 | [homepage]: https://www.contributor-covenant.org 73 | 74 | For answers to common questions about this code of conduct, see 75 | [here](https://www.contributor-covenant.org/faq) 76 | -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% load static %} 6 | 7 | 8 | 9 | 10 | 11 | {% block title %} Jagrati | Dashboard {% endblock %} 12 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% block style %} 30 | {% endblock %} 31 | 32 | 33 | 34 | 35 |
36 | {% include 'snippets/header.html' %} 37 | 38 | {% block content %} 39 | {% endblock %} 40 |
41 | 42 | 43 |
44 |
45 | {% for message in messages %} 46 | 54 | {% endfor %} 55 |
56 |
57 | 58 | {% include 'snippets/footer.html' %} 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 80 | 81 | {% block scripts %} 82 | {% endblock %} 83 | 84 | 85 | -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | # from django.contrib import admin 2 | # from django.contrib.auth import get_user_model #coz model in auth is now our custom model 3 | # # we can also do from .models import ...?\ 4 | # from .forms import UserAdminChangeForm, UserAdminCreationForm 5 | 6 | # # Register your models here. 7 | # User = get_user_model() 8 | 9 | # class UserAdmin(admin.ModelAdmin): 10 | # form = UserAdminChangeForm 11 | # add_form = UserAdminCreationForm 12 | 13 | # admin.site.register(User, UserAdmin) 14 | 15 | from django.contrib import admin 16 | from django.contrib.auth.models import Group 17 | from django.contrib.auth.admin import UserAdmin as BaseUserAdmin 18 | 19 | from apps.volunteers.admin import VolunteerInline 20 | from .forms import UserAdminCreationForm 21 | from .models import User, Profile, AuthorisedDevice 22 | 23 | 24 | @admin.register(User) 25 | class UserAdmin(BaseUserAdmin): 26 | # The forms to add and change user instances 27 | 28 | # form = UserAdminChangeForm 29 | # Will override default password checks (like password too common) 30 | # and validations with those specified in this form. 31 | # Also 'desig' field won't work without this. 32 | add_form = UserAdminCreationForm 33 | 34 | # The fields to be used in displaying the User model. 35 | # These override the definitions on the base UserAdmin 36 | # that reference specific fields on auth.User. 37 | list_display = ('email', 'desig', 'auth') 38 | search_fields = ('email',) 39 | readonly_fields = ('date_joined', 'last_login') 40 | 41 | filter_horizontal = ('user_permissions', 'groups') 42 | list_filter = ('desig', 'auth', 'is_active', 'is_staff') 43 | fieldsets = ( 44 | (None, {'fields': ('email', 'password')}), 45 | ('Personal info', {'fields': ('desig',)}), 46 | ('Permissions', {'fields': ('is_active', 'auth', 'is_staff', 'is_superuser')}), 47 | ('Permissions and Groups', {'fields': ('user_permissions', 'groups')}), 48 | ('Others', {'fields': ('date_joined', 'last_login')}), 49 | ) 50 | # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin 51 | # overrides get_fieldsets to use this attribute when creating a user. 52 | add_fieldsets = ( 53 | (None, { 54 | 'classes': ('wide',), 55 | 'fields': ('email', 'password1', 'password2', 'desig')} 56 | ), 57 | ) 58 | 59 | ordering = ('email',) 60 | 61 | @admin.register(Profile) 62 | class ProfileAdmin(admin.ModelAdmin): 63 | list_display = ('get_full_name', 'get_email', 'get_desig', 'get_auth') 64 | search_fields = ('first_name', 'last_name', 'user__email') 65 | list_filter = ('user__desig', 'user__auth') 66 | ordering = ('-user__date_joined',) 67 | 68 | inlines = [VolunteerInline] 69 | 70 | def get_email(self, obj): 71 | return obj.user.email 72 | get_email.short_description = 'Email' 73 | 74 | def get_desig(self, obj): 75 | return obj.user.get_desig_display() 76 | get_desig.short_description = 'Designation' 77 | 78 | def get_auth(self, obj): 79 | return obj.user.auth 80 | get_auth.short_description = 'Auth' 81 | get_auth.admin_order_field = 'user__auth' 82 | get_auth.boolean = True 83 | 84 | @admin.register(AuthorisedDevice) 85 | class AuthorisedDeviceAdmin(admin.ModelAdmin): 86 | list_display = ('get_email', 'device_id', 'active') 87 | search_fields = ('user__email', 'device_id') 88 | list_filter = ('active',) 89 | ordering = ('user__email', 'device_id') 90 | 91 | def get_email(self, obj): 92 | return obj.user.email 93 | get_email.short_description = 'Email' 94 | get_email.admin_order_field = 'user__email' 95 | -------------------------------------------------------------------------------- /.github/linters/.flake8.yml: -------------------------------------------------------------------------------- 1 | # .flake8 2 | # 3 | # DESCRIPTION 4 | # Configuration file for the python linter flake8. 5 | # 6 | # This configuration is based on the generic 7 | # configuration published on GitHub. 8 | # 9 | # AUTHOR 10 | # krnd 11 | # 12 | # VERSION 13 | # 1.0 14 | # 15 | # SEE ALSO 16 | # http://flake8.pycqa.org/en/latest/user/options.html 17 | # http://flake8.pycqa.org/en/latest/user/error-codes.html 18 | # https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes 19 | # https://gist.github.com/krnd 20 | # 21 | 22 | 23 | [flake8] 24 | 25 | ################### PROGRAM ################################ 26 | 27 | # Specify the number of subprocesses that Flake8 will use to run checks in parallel. 28 | jobs = auto 29 | 30 | 31 | ################### OUTPUT ################################# 32 | 33 | ########## VERBOSITY ########## 34 | 35 | # Increase the verbosity of Flake8’s output. 36 | verbose = 0 37 | # Decrease the verbosity of Flake8’s output. 38 | quiet = 0 39 | 40 | 41 | ########## FORMATTING ########## 42 | 43 | # Select the formatter used to display errors to the user. 44 | format = default 45 | 46 | # Print the total number of errors. 47 | count = True 48 | # Print the source code generating the error/warning in question. 49 | show-source = True 50 | # Count the number of occurrences of each error/warning code and print a report. 51 | statistics = True 52 | 53 | 54 | ########## TARGETS ########## 55 | 56 | # Redirect all output to the specified file. 57 | output-file = .flake8.log 58 | # Also print output to stdout if output-file has been configured. 59 | tee = True 60 | 61 | 62 | ################### FILE PATTERNS ########################## 63 | 64 | # Provide a comma-separated list of glob patterns to exclude from checks. 65 | exclude = 66 | # git folder 67 | .git, 68 | # python cache 69 | __pycache__, 70 | # Provide a comma-separate list of glob patterns to include for checks. 71 | filename = 72 | *.py 73 | 74 | 75 | ################### LINTING ################################ 76 | 77 | ########## ENVIRONMENT ########## 78 | 79 | # Provide a custom list of builtin functions, objects, names, etc. 80 | builtins = 81 | 82 | 83 | ########## OPTIONS ########## 84 | 85 | # Report all errors, even if it is on the same line as a `# NOQA` comment. 86 | disable-noqa = False 87 | 88 | # Set the maximum length that any line (with some exceptions) may be. 89 | max-line-length = 119 90 | # Set the maximum allowed McCabe complexity value for a block of code. 91 | max-complexity = 10 92 | # Toggle whether pycodestyle should enforce matching the indentation of the opening bracket’s line. 93 | # incluences E131 and E133 94 | hang-closing = False 95 | 96 | 97 | ########## RULES ########## 98 | 99 | # ERROR CODES 100 | # 101 | # E/W - PEP8 errors/warnings (pycodestyle) 102 | # F - linting errors (pyflakes) 103 | # C - McCabe complexity error (mccabe) 104 | # 105 | # W503 - line break before binary operator 106 | 107 | # Specify a list of codes to ignore. 108 | ignore = 109 | W503 110 | # Specify the list of error codes you wish Flake8 to report. 111 | select = 112 | E, 113 | W, 114 | F, 115 | C 116 | # Enable off-by-default extensions. 117 | enable-extensions = 118 | 119 | 120 | ########## DOCSTRING ########## 121 | 122 | # Enable PyFlakes syntax checking of doctests in docstrings. 123 | doctests = True 124 | 125 | # Specify which files are checked by PyFlakes for doctest syntax. 126 | include-in-doctest = 127 | # Specify which files are not to be checked by PyFlakes for doctest syntax. 128 | exclude-in-doctest = 129 | -------------------------------------------------------------------------------- /apps/volunteers/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .forms import VolunteerScheduleAdminForm 4 | from .models import ( 5 | Designation, Volunteer, VolunteerSchedule, 6 | VolunteerAttendance, UpdateScheduleRequest, 7 | ) 8 | 9 | 10 | class VolunteerInline(admin.StackedInline): 11 | model = Volunteer 12 | 13 | 14 | @admin.register(Designation) 15 | class DesignationAdmin(admin.ModelAdmin): 16 | list_display = ('desig_id', 'name', 'parent_desig') 17 | search_fields = ('name', 'parent_desig__name') 18 | list_filter = ('parent_desig',) 19 | ordering = ('desig_id',) 20 | 21 | 22 | @admin.register(Volunteer) 23 | class VolunteerAdmin(admin.ModelAdmin): 24 | list_display = ('roll_no', 'get_name', 'desig', 'get_auth') 25 | search_fields = ('roll_no', 'profile__first_name', 'profile__last_name') 26 | list_filter = ('desig', 'profile__user__auth') 27 | ordering = ('-profile__user__date_joined',) 28 | 29 | def get_name(self, obj): 30 | return f'{obj.profile.get_full_name}' 31 | get_name.short_description = 'Name' 32 | get_name.admin_order_field = 'profile__first_name' 33 | 34 | def get_auth(self, obj): 35 | return obj.profile.user.auth 36 | get_auth.short_description = 'Auth' 37 | get_auth.admin_order_field = 'profile__user__auth' 38 | get_auth.boolean = True 39 | 40 | 41 | @admin.register(VolunteerSchedule) 42 | class VolunteerScheduleAdmin(admin.ModelAdmin): 43 | form = VolunteerScheduleAdminForm 44 | 45 | list_display = ('get_roll', 'get_name', 'day', 'get_section') 46 | search_fields = ('volun__roll_no', 47 | 'volun__profile__first_name', 'volun__profile__last_name') 48 | list_filter = ('day',) 49 | ordering = ('volun__roll_no',) 50 | 51 | def get_roll(self, obj): 52 | return obj.volun.roll_no 53 | get_roll.short_description = 'Roll No.' 54 | get_roll.admin_order_field = 'volun__roll_no' 55 | 56 | def get_name(self, obj): 57 | return obj.volun.profile.get_full_name 58 | get_name.short_description = 'Name' 59 | get_name.admin_order_field = 'volun__profile__first_name' 60 | 61 | def get_section(self, obj): 62 | return obj.schedule.section.name 63 | get_section.short_description = 'Section' 64 | get_section.admin_order_field = 'schedule__section__section_id' 65 | 66 | 67 | @admin.register(VolunteerAttendance) 68 | class VolunteerAttendanceAdmin(admin.ModelAdmin): 69 | list_display = ('cal_date', 'get_roll', 'get_name', 'present', 'extra') 70 | search_fields = ('volun__roll_no', 71 | 'volun__profile__first_name', 'volun__profile__last_name') 72 | list_filter = ('volun__batch', 'present', 'extra') 73 | ordering = ('-cal_date', '-volun__batch', 'volun__roll_no') 74 | 75 | def get_roll(self, obj): 76 | return obj.volun.roll_no 77 | get_roll.short_description = 'Roll No.' 78 | get_roll.admin_order_field = 'volun__roll_no' 79 | 80 | def get_name(self, obj): 81 | return obj.volun.profile.get_full_name 82 | get_name.short_description = 'Name' 83 | get_name.admin_order_field = 'volun__profile__first_name' 84 | 85 | 86 | @admin.register(UpdateScheduleRequest) 87 | class UpdateScheduleRequestAdmin(admin.ModelAdmin): 88 | list_display = ('volun', 'get_name', 'date', 'approved', 89 | 'declined', 'by_admin', 'cancelled') 90 | search_fields = ('volun__roll_no', 91 | 'volun__profile__first_name', 'volun__profile__last_name') 92 | list_filter = ('approved', 'declined', 'by_admin', 'cancelled') 93 | ordering = ('-date',) 94 | 95 | def get_name(self, obj): 96 | return obj.volun.profile.get_full_name 97 | get_name.short_description = 'Name' 98 | get_name.admin_order_field = 'volun__profile__first_name' 99 | -------------------------------------------------------------------------------- /static/home/css/calendar.css: -------------------------------------------------------------------------------- 1 | .calAndMsgContainer{ 2 | display: grid; 3 | grid-template-columns: 1fr 1fr; 4 | grid-gap: 10px; 5 | margin-top: 10px; 6 | height: 100%; 7 | padding-top: 4rem; 8 | } 9 | 10 | .calendar { 11 | width: 350px; 12 | margin: auto auto; 13 | border: 2px solid #ff8c00; 14 | border-radius: 5px; 15 | display: flex; 16 | flex-direction: column; 17 | align-self: top; 18 | } 19 | 20 | .calendar__body { 21 | width: 100%; 22 | padding: 5px; 23 | display: grid; 24 | grid-template-columns: repeat(7, 1fr); 25 | grid-gap: 1px; 26 | } 27 | 28 | .scheduleInfo { 29 | display: flex; 30 | flex-direction: column; 31 | justify-content: center; 32 | text-align: center; 33 | width: 100%; 34 | } 35 | 36 | .scheduleInfoMobile, #classInfo { 37 | display: none; 38 | width: 100%; 39 | } 40 | 41 | .mainMessageForDay, .mainMessageForDayMobile { 42 | border: 2px solid #ff8c00; 43 | border-radius: 10px; 44 | text-align: center; 45 | padding: 1rem; 46 | margin-bottom: 1rem; 47 | } 48 | 49 | .calendar__month { 50 | font-size: 20px; 51 | font-weight: 800; 52 | padding: 10px 0; 53 | width: 100%; 54 | display: flex; 55 | justify-content: space-between; 56 | } 57 | 58 | .cal-month__previous, 59 | .cal-month__next { 60 | cursor: pointer; 61 | width: 30px; 62 | height: 30px; 63 | text-align: center; 64 | user-select: none; 65 | margin: 0 5px; 66 | } 67 | 68 | .cal-month__previous:hover, 69 | .cal-month__next:hover { 70 | background-color: #ff8c00; 71 | border-radius: 50%; 72 | color: #111; 73 | } 74 | 75 | .cal-head__day, 76 | .cal-body__day { 77 | display: inline-block; 78 | width: 100%; 79 | height: 100%; 80 | text-align: center; 81 | } 82 | 83 | .cal-head__day { 84 | padding: 5px 0; 85 | font-weight: 800; 86 | } 87 | 88 | .cal-body__week, 89 | .calendar__head { 90 | display: block; 91 | height: 100%; 92 | width: 100%; 93 | display: flex; 94 | justify-content: space-between; 95 | } 96 | 97 | .calendar__head { 98 | line-height: 50px; 99 | border-bottom: 2px solid #ff8c00; 100 | } 101 | 102 | .cal-body__day { 103 | color: #111; 104 | line-height: 50px; 105 | text-align: center; 106 | cursor: pointer; 107 | } 108 | 109 | .no_calendar { 110 | color: #ccc; 111 | } 112 | 113 | .holiday { 114 | color: #ff8c00; 115 | font-weight: 800; 116 | } 117 | 118 | .no_class_scheduled { 119 | color: red; 120 | font-weight: 800; 121 | } 122 | 123 | .class_scheduled { 124 | color: green; 125 | font-weight: 800; 126 | } 127 | 128 | .cal-body__day--today { 129 | font-weight: 800; 130 | background-color: #ccc; 131 | /* color: #111; */ 132 | border-radius: 50%; 133 | } 134 | 135 | .cal-body__day--selected { 136 | background-color: #ff8c00; 137 | font-weight: 800; 138 | border-radius: 50%; 139 | color: #111; 140 | } 141 | 142 | .scheduleTable, .scheduleTableMobile { 143 | max-width: 25vw; 144 | margin: auto; 145 | } 146 | 147 | .extraInfo { 148 | margin-top: 1rem; 149 | font-style: italic; 150 | text-decoration: underline; 151 | } 152 | 153 | @media (max-width: 768px) { 154 | .calAndMsgContainer { 155 | display: flex; 156 | flex-direction: column; 157 | justify-content: center; 158 | } 159 | 160 | .scheduleInfoDesktop { 161 | display: none; 162 | } 163 | 164 | .scheduleInfoMobile { 165 | display: flex; 166 | } 167 | 168 | .scheduleTableMobile { 169 | max-width: 100%; 170 | } 171 | 172 | .extraInfoMobile { 173 | margin-top: 1rem; 174 | font-style: italic; 175 | text-decoration: underline; 176 | } 177 | } 178 | 179 | @media (max-width: 400px) { 180 | .calendar { 181 | width: 100%; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /static/global/css/sidebar.css: -------------------------------------------------------------------------------- 1 | /* For Arrow in sidebar->dropdown mobile view */ 2 | .arrow { 3 | border: solid black; 4 | border-width: 0 3px 3px 0; 5 | display: inline-block; 6 | padding: 3px; 7 | } 8 | 9 | .up { 10 | transform: rotate(-135deg); 11 | -webkit-transform: rotate(-135deg); 12 | /* transition-delay: 800ms; */ 13 | } 14 | 15 | .down { 16 | transform: rotate(45deg); 17 | -webkit-transform: rotate(45deg); 18 | /* transition-delay: 800ms; */ 19 | } 20 | 21 | .sidebar { 22 | position: fixed; 23 | top: 71.4px; 24 | bottom: 54px; 25 | left: 0; 26 | /* z-index: 100; */ 27 | /* Behind the navbar */ 28 | /* padding: 28px 0 0; */ 29 | /* Height of navbar */ 30 | box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.1); 31 | overflow-y: auto; 32 | } 33 | 34 | /* .sidebar-sticky { */ 35 | /* position: relative; */ 36 | /* top: 0; */ 37 | /* height: calc(100vh - 48px); */ 38 | /* padding-top: .5rem; */ 39 | /* overflow-x: hidden; */ 40 | /* overflow-y: auto; */ 41 | /* Scrollable contents if viewport is shorter than content. */ 42 | /* } */ 43 | 44 | /* @supports ((position: -webkit-sticky) or (position: sticky)) { 45 | .sidebar-sticky { 46 | position: -webkit-sticky; 47 | position: sticky; 48 | } 49 | } */ 50 | 51 | /* .sidebar .nav-link { 52 | font-weight: 500; 53 | color: #333; 54 | } */ 55 | 56 | /* .sidebar .nav-link.active { 57 | color: #007bff; 58 | } */ 59 | 60 | .sidebar-heading { 61 | font-size: 0.75rem; 62 | text-transform: uppercase; 63 | } 64 | 65 | .sidebar-img { 66 | width: 100px; 67 | height: 100px; 68 | } 69 | .sidebar-list li { 70 | margin: 5px 0; 71 | } 72 | 73 | @media screen and (min-width: 768px) { 74 | .main { 75 | min-height: calc(100vh - 54px); 76 | } 77 | 78 | #alert-toast-div > div { 79 | bottom: 64px !important; 80 | } 81 | 82 | footer { 83 | position: fixed; 84 | bottom: 0; 85 | width: 100%; 86 | } 87 | } 88 | 89 | @media screen and (max-width: 767px) { 90 | .sidebar { 91 | position: static; 92 | } 93 | } 94 | 95 | /* SIDEBAR LINKS MENU */ 96 | 97 | #sidebar-menu { 98 | width: 100%; 99 | /* max-width: 360px; */ 100 | background: #fff; 101 | -webkit-border-radius: 4px; 102 | -moz-border-radius: 4px; 103 | border-radius: 4px; 104 | } 105 | 106 | #sidebar-menu .sidebar-menu-title { 107 | display: block; 108 | padding: 15px; 109 | color: #4d4d4d; 110 | font-weight: 700; 111 | border-bottom: 1px solid #e2e2e2; 112 | position: relative; 113 | -webkit-transition: all 0.4s ease; 114 | -o-transition: all 0.4s ease; 115 | transition: all 0.4s ease; 116 | } 117 | 118 | #sidebar-menu li { 119 | margin: 0; 120 | } 121 | 122 | #sidebar-menu li i { 123 | position: absolute; 124 | top: 50%; 125 | transform: translateY(-50%); 126 | right: 12px; 127 | color: #595959; 128 | -webkit-transition: all 0.4s ease; 129 | -o-transition: all 0.4s ease; 130 | transition: all 0.4s ease; 131 | } 132 | 133 | #sidebar-menu .sidebar-menu-title[aria-expanded="true"] { 134 | /* color: #d66d0b; */ 135 | color: #ff8c00; 136 | } 137 | 138 | #sidebar-menu .sidebar-menu-title[aria-expanded="true"] i { 139 | /* color: #d66d0b; */ 140 | color: #ff8c00; 141 | -webkit-transform: translateY(-50%) rotate(180deg); 142 | -ms-transform: translateY(-50%) rotate(180deg); 143 | -o-transform: translateY(-50%) rotate(180deg); 144 | transform: translateY(-50%) rotate(180deg); 145 | } 146 | 147 | /** 148 | * Submenu 149 | -----------------------------*/ 150 | 151 | .sidebar-submenu { 152 | list-style-type: none; 153 | background: #ededed; 154 | font-size: 14px; 155 | margin: 0; 156 | padding: 0; 157 | } 158 | 159 | .sidebar-submenu li { 160 | border-bottom: 1px solid #e2e2e2; 161 | } 162 | 163 | .sidebar-submenu a { 164 | display: block; 165 | text-decoration: none; 166 | color: #000000; 167 | padding: 12px; 168 | -webkit-transition: all 0.25s ease; 169 | -o-transition: all 0.25s ease; 170 | transition: all 0.25s ease; 171 | } 172 | 173 | .sidebar-submenu a:hover { 174 | /* background: #d66d0b; */ 175 | background-color: #ff8c00; 176 | color: #fff; 177 | } 178 | -------------------------------------------------------------------------------- /templates/feedbacks/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Feedbacks {% endblock %} 6 | 7 | {% block style %} 8 | {% endblock %} 9 | 10 | {% block content %} 11 |
12 |
13 |
14 |

Feedback Form

15 |

We would love to hear your thoughts, concerns or anything we can improve!

16 |
17 |
18 |
19 |
20 |
21 | {% csrf_token %} 22 |
23 |
24 |
25 | 26 | 27 |
28 |
29 |
30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 | 38 |
39 |
40 |
41 |
42 | 43 |
44 |
45 |
46 |
47 | 48 |
49 |
50 |
51 |
52 |
53 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | {% endblock %} 61 | 62 | {% block scripts %} 63 | 64 | 94 | 95 | {% endblock %} -------------------------------------------------------------------------------- /templates/events/add_event.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | 3 | {% block title %} Jagrati | Add Event {% endblock %} 4 | 5 | {% block style %} 6 | 13 | {% endblock %} 14 | 15 | {% block content %} 16 |
17 |
18 |

Add new event

19 |
20 |
21 |
22 |
23 | {% csrf_token %} 24 |
25 | 26 | 27 |
Event name is required.
28 |
29 |
30 |
31 | 32 | 34 |
Please enter a valid date and time.
35 |
36 |
37 | 38 | 39 |
Please enter a venue of your event.
40 |
41 |
42 |
43 | 44 | 45 |
Please enter some description for your event.
46 |
47 |
48 | 49 | 51 |
52 |
53 |
54 |
55 | 56 |
57 |
58 |
59 |
60 |
61 |
62 | {% endblock %} 63 | 64 | {% block scripts %} 65 | 85 | 86 | 87 | 98 | {% endblock %} -------------------------------------------------------------------------------- /apps/students/models.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.db import models 3 | from django.urls import reverse 4 | 5 | from imagekit.models import ProcessedImageField 6 | from imagekit.processors import ResizeToFill 7 | 8 | from home.models import Calendar, Schedule 9 | 10 | 11 | class Student(models.Model): 12 | GENDER = ( 13 | ('M', 'Male'), 14 | ('F', 'Female'), 15 | ('O', 'Other') 16 | ) 17 | VILLAGE = ( 18 | ('G', 'Gadheri'), 19 | ('M', 'Mehgawan'), 20 | ('C', 'Chanditola'), 21 | ('A', 'Amanala'), 22 | ('S', 'Suarkol'), 23 | ) 24 | first_name = models.CharField(max_length=50) 25 | last_name = models.CharField(max_length=50) 26 | gender = models.CharField(max_length=1, choices=GENDER, default='M') 27 | profile_image = ProcessedImageField( 28 | upload_to='students/profile_pics', processors=[ResizeToFill(300, 300)], 29 | format='JPEG', options={'quality': 60}, blank=True) 30 | school_class = models.IntegerField() 31 | village = models.CharField(max_length=3, choices=VILLAGE) 32 | contact_no = models.CharField(max_length=13, blank=True) 33 | guardian_name = models.CharField(max_length=30) 34 | 35 | restricted = models.BooleanField(default=False) 36 | verified = models.BooleanField(verbose_name='Profile details verified', default=False) 37 | remarks = models.TextField(max_length=5000, blank=True) 38 | 39 | def __str__(self): 40 | return f'{self.get_full_name} ({self.school_class})' 41 | 42 | @property 43 | def get_full_name(self): 44 | return f'{self.first_name} {self.last_name}' 45 | 46 | @property 47 | def has_complete_profile(self): 48 | if (self.first_name != '.' and self.last_name != '.' and '.' not in self.guardian_name 49 | and self.contact_no and self.profile_image): 50 | return True 51 | return False 52 | 53 | @property 54 | def get_verified_name(self): 55 | sign = '' 56 | if not self.has_complete_profile: 57 | sign = '❗ ' 58 | elif not self.verified: 59 | sign = '✘ ' 60 | else: 61 | sign = '✔ ' 62 | return f'{sign}{self.first_name} {self.last_name}' 63 | 64 | @property 65 | def get_profile_image_url(self): 66 | if self.profile_image and hasattr(self.profile_image, 'url'): 67 | return self.profile_image.url 68 | elif self.gender == 'F': 69 | return settings.STATIC_URL + 'home/images/woman.png' 70 | else: 71 | return settings.STATIC_URL + 'home/images/man.png' 72 | 73 | @property 74 | def get_profile_url(self): 75 | """Returns the url to student profile.""" 76 | return reverse('students:profile', args=[str(self.id)]) 77 | 78 | 79 | class StudentSchedule(models.Model): 80 | student = models.ForeignKey( 81 | Student, on_delete=models.CASCADE, related_name='student_schedules') 82 | day = models.IntegerField(choices=Schedule.DAY, blank=True) 83 | schedule = models.ForeignKey( 84 | Schedule, on_delete=models.CASCADE, related_name='student_schedules') 85 | 86 | class Meta: 87 | unique_together = (('student', 'day'),) 88 | verbose_name = 'Student Schedule' 89 | verbose_name_plural = 'Students Schedule' 90 | 91 | def __str__(self): 92 | return f'{self.student} - {self.schedule}' 93 | 94 | 95 | class StudentAttendance(models.Model): 96 | student = models.ForeignKey( 97 | Student, on_delete=models.CASCADE, related_name='student_attendance') 98 | cal_date = models.ForeignKey( 99 | Calendar, on_delete=models.CASCADE, related_name='student_attendance') 100 | present = models.BooleanField(default=False) 101 | hw_done = models.BooleanField(default=False, verbose_name="HomeWork Done") 102 | 103 | class Meta: 104 | unique_together = (('student', 'cal_date'),) 105 | verbose_name = 'Student Attendance' 106 | verbose_name_plural = 'Students Attendance' 107 | 108 | def __str__(self): 109 | return f'{self.student} - {self.cal_date}' 110 | 111 | def save(self, *args, **kwargs): 112 | """For cpanel.""" 113 | self.present = (self.present is True) 114 | self.hw_done = (self.hw_done is True) 115 | super(StudentAttendance, self).save(*args, **kwargs) 116 | -------------------------------------------------------------------------------- /Jagrati/settings/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for Jagrati project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.2.6. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.2/ref/settings/ 11 | """ 12 | 13 | import os 14 | from decouple import config 15 | 16 | 17 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 18 | BASE_DIR = os.path.dirname(os.path.dirname( 19 | os.path.dirname(os.path.abspath(__file__)))) 20 | 21 | # Application definition 22 | 23 | INSTALLED_APPS = [ 24 | 'django.contrib.admin', 25 | 'django.contrib.auth', 26 | 'django.contrib.contenttypes', 27 | 'django.contrib.sessions', 28 | 'django.contrib.messages', 29 | 'django.contrib.staticfiles', 30 | 31 | 'corsheaders', 32 | 'imagekit', 33 | 'django_cleanup.apps.CleanupConfig', 34 | 'rest_framework', 35 | 'rest_framework.authtoken', 36 | 'social_django', 37 | 'django_extensions', 38 | 39 | 'home', 40 | 'accounts', 41 | 'apps.students', 42 | 'apps.volunteers', 43 | 'apps.feedbacks', 44 | 'apps.events', 45 | 'apps.misc', 46 | 47 | ] 48 | 49 | REST_FRAMEWORK = { 50 | 'DEFAULT_AUTHENTICATION_CLASSES': [ 51 | 'rest_framework.authentication.TokenAuthentication', 52 | ], 53 | 'DEFAULT_PERMISSION_CLASSES': [ 54 | 'rest_framework.permissions.IsAuthenticated', 55 | ], 56 | } 57 | 58 | MIDDLEWARE = [ 59 | 'django.middleware.security.SecurityMiddleware', 60 | 'django.contrib.sessions.middleware.SessionMiddleware', 61 | 'corsheaders.middleware.CorsMiddleware', 62 | 'django.middleware.common.CommonMiddleware', 63 | 'django.middleware.csrf.CsrfViewMiddleware', 64 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 65 | 'django.contrib.messages.middleware.MessageMiddleware', 66 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 67 | 68 | 'social_django.middleware.SocialAuthExceptionMiddleware', 69 | ] 70 | 71 | ROOT_URLCONF = 'Jagrati.urls' 72 | 73 | TEMPLATES = [ 74 | { 75 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 76 | 'DIRS': ['/', os.path.join(BASE_DIR, 'templates')], 77 | 'APP_DIRS': True, 78 | 'OPTIONS': { 79 | 'context_processors': [ 80 | 'django.template.context_processors.debug', 81 | 'django.template.context_processors.request', 82 | 'django.contrib.auth.context_processors.auth', 83 | 'django.contrib.messages.context_processors.messages', 84 | 85 | # for accessing models from templates... Or Use Inclusion Tags 86 | 'home.context_processors.database_context', 87 | 88 | 'social_django.context_processors.backends', 89 | 'social_django.context_processors.login_redirect', 90 | ], 91 | }, 92 | }, 93 | ] 94 | 95 | WSGI_APPLICATION = 'Jagrati.wsgi.application' 96 | 97 | AUTHENTICATION_BACKENDS = [ 98 | 'django.contrib.auth.backends.ModelBackend', 99 | 'social_core.backends.google.GoogleOAuth2' 100 | ] 101 | 102 | # Password validation 103 | # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators 104 | 105 | AUTH_PASSWORD_VALIDATORS = [ 106 | { 107 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 108 | }, 109 | { 110 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 111 | }, 112 | { 113 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 114 | }, 115 | { 116 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 117 | }, 118 | ] 119 | 120 | 121 | # Internationalization 122 | # https://docs.djangoproject.com/en/2.2/topics/i18n/ 123 | 124 | LANGUAGE_CODE = 'en-us' 125 | 126 | TIME_ZONE = 'Asia/Kolkata' 127 | 128 | USE_I18N = True 129 | 130 | USE_L10N = False # Is false in AlumniConnect 131 | 132 | USE_TZ = True 133 | 134 | DATE_FORMAT = 'Y-m-d' 135 | 136 | LOGIN_REDIRECT_URL = '/' 137 | 138 | AUTH_USER_MODEL = 'accounts.User' 139 | 140 | # DJANGO_EXTENSIONS settings 141 | SHELL_PLUS_PRINT_SQL = True 142 | 143 | # GOOGLE_OAUTH settings 144 | SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = config("SOCIAL_AUTH_GOOGLE_OAUTH2_KEY") 145 | SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = config("SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET") 146 | 147 | CORS_ORIGIN_ALLOW_ALL = True 148 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## 🤝***First time contributing? We will help you out.*** 👍 2 | 3 | ![GitHub custom open for collaboration](https://img.shields.io/badge/Open%20For-Collaboration-brightgreen?style=for-the-badge) 4 | 5 | Refer to the following articles on the basics of Git and Github and can also contact the Project Mentors, in case you are stuck: 6 | 7 | 8 | - [Getting started with Git and GitHub](https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github) 9 | - [Forking a Repo](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) 10 | - [Cloning a Repo](https://help.github.com/en/desktop/contributing-to-projects/creating-a-pull-request) 11 | - [How to create a Pull Request](https://opensource.com/article/19/7/create-pull-request-github) 12 | 13 | ***If you don't have git on your machine, [install it](https://help.github.com/articles/set-up-git/).*** 14 | 15 | ## 💥 How to Contribute 16 | 17 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) 18 | [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.png?v=103)](https://github.com/ellerbrock/open-source-badges/) 19 | 20 | - Take a look at the Existing [Issues](https://github.com/garg3133/JagratiWebApp/issues) or create your own Issues! 21 | - Wait for the Issue to be assigned to you after which you can start working on it. 22 | - Fork the Repo and create a Branch for any Issue that you are working upon. 23 | - Read the [Code of Conduct](https://github.com/garg3133/JagratiWebApp/blob/master/CODE_OF_CONDUCT.md) 24 | - Create a Pull Request which will be promptly reviewed and suggestions would be added to improve it. 25 | - Add Screenshots to help us know what this Script is all about. 26 | 27 | ## ⭐HOW TO MAKE A PULL REQUEST: 28 | 29 | **1.** Fork [this](https://github.com/garg3133/JagratiWebApp) repository. 30 | Click on the symbol at the top right corner. 31 | 32 | **2.** Clone the forked repository. Open terminal and type: 33 | 34 | ```bash 35 | git clone https://github.com//JagratiWebApp.git 36 | ``` 37 | 38 | **3.** Navigate to the project directory. 39 | 40 | ```bash 41 | cd JagratiWebApp 42 | ``` 43 | 44 | **4.** Make a feature branch 45 | ```bash 46 | git checkout -b 47 | 48 | ``` 49 | **5.** Make changes in source code/ project. 50 | 51 | **6.** Stage your changes and commit 52 | 53 | ```bash 54 | #Add changes to Index 55 | git add . 56 | 57 | #Commit to the local repo 58 | git commit -m "" 59 | ``` 60 | 61 | **7.** Push your local commits to the remote repo. 62 | 63 | ```bash 64 | git push origin 65 | ``` 66 | 67 | **8.** Create a [PR](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) ! 68 | 69 | **9.** **Congratulations!** Sit and relax, you've made your contribution to [JagratiWebApp](https://github.com/garg3133/JagratiWebApp) project. 70 | 71 | 72 | ***:trophy: After this, project leaders and mentors will review the changes and will merge your PR if they are found good, otherwise we will suggest the required changes.*** 73 | 74 | ## Style Guides for Git Commit Messages:memo: 75 | 76 | #### Here's a list of some good to have points, that can add more value to your contribution logs. 77 | 78 | - Use the present tense (example: "Add feature" and not "Added feature") 79 | - Use the imperative mood (example: "Move item to...", instead of "Moves item to...") 80 | - Limit the first line (also called subject line) to 50 characters or less 81 | - Capitalize the subject line 82 | - Separate subject from body with a blank line 83 | - Do not end the subject line with a period 84 | - Wrap the body at 72 characters 85 | - Use the body to explain what, why, vs, and how 86 | - Reference issues and pull requests liberally after the first line 87 | 88 | For more detailed reference to the above points, refer here: https://chris.beams.io/posts/git-commit. 89 | 90 | ## 💥 Issues: 91 | For major changes, you are welcomed to open an issue about what you would like to contribute. Enhancements will be appreciated. 92 | 93 | #### All the Best!🥇 94 | 95 |

96 | 97 | built by developers 98 | [![built with love](https://forthebadge.com/images/badges/built-with-love.svg)](https://github.com/garg3133/JagratiWebApp) 99 | 100 |

101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /templates/accounts/login_signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Login {% endblock %} 6 | 7 | {% block style %} 8 | 9 | 10 | 29 | {% endblock %} 30 | 31 | {% block content %} 32 | 33 | 102 | 103 | 104 | 107 | {% endblock %} -------------------------------------------------------------------------------- /static/global/vendor/photoswipe/photoswipe.css: -------------------------------------------------------------------------------- 1 | /*! PhotoSwipe main CSS by Dmitry Semenov | photoswipe.com | MIT license */ 2 | /* 3 | Styles for basic PhotoSwipe functionality (sliding area, open/close transitions) 4 | */ 5 | /* pswp = photoswipe */ 6 | .pswp { 7 | display: none; 8 | position: absolute; 9 | width: 100%; 10 | height: 100%; 11 | left: 0; 12 | top: 0; 13 | overflow: hidden; 14 | -ms-touch-action: none; 15 | touch-action: none; 16 | z-index: 1500; 17 | -webkit-text-size-adjust: 100%; 18 | /* create separate layer, to avoid paint on window.onscroll in webkit/blink */ 19 | -webkit-backface-visibility: hidden; 20 | outline: none; } 21 | .pswp * { 22 | -webkit-box-sizing: border-box; 23 | box-sizing: border-box; } 24 | .pswp img { 25 | max-width: none; } 26 | 27 | /* style is added when JS option showHideOpacity is set to true */ 28 | .pswp--animate_opacity { 29 | /* 0.001, because opacity:0 doesn't trigger Paint action, which causes lag at start of transition */ 30 | opacity: 0.001; 31 | will-change: opacity; 32 | /* for open/close transition */ 33 | -webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); 34 | transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); } 35 | 36 | .pswp--open { 37 | display: block; } 38 | 39 | .pswp--zoom-allowed .pswp__img { 40 | /* autoprefixer: off */ 41 | cursor: -webkit-zoom-in; 42 | cursor: -moz-zoom-in; 43 | cursor: zoom-in; } 44 | 45 | .pswp--zoomed-in .pswp__img { 46 | /* autoprefixer: off */ 47 | cursor: -webkit-grab; 48 | cursor: -moz-grab; 49 | cursor: grab; } 50 | 51 | .pswp--dragging .pswp__img { 52 | /* autoprefixer: off */ 53 | cursor: -webkit-grabbing; 54 | cursor: -moz-grabbing; 55 | cursor: grabbing; } 56 | 57 | /* 58 | Background is added as a separate element. 59 | As animating opacity is much faster than animating rgba() background-color. 60 | */ 61 | .pswp__bg { 62 | position: absolute; 63 | left: 0; 64 | top: 0; 65 | width: 100%; 66 | height: 100%; 67 | background: #000; 68 | opacity: 0; 69 | -webkit-transform: translateZ(0); 70 | transform: translateZ(0); 71 | -webkit-backface-visibility: hidden; 72 | will-change: opacity; } 73 | 74 | .pswp__scroll-wrap { 75 | position: absolute; 76 | left: 0; 77 | top: 0; 78 | width: 100%; 79 | height: 100%; 80 | overflow: hidden; } 81 | 82 | .pswp__container, 83 | .pswp__zoom-wrap { 84 | -ms-touch-action: none; 85 | touch-action: none; 86 | position: absolute; 87 | left: 0; 88 | right: 0; 89 | top: 0; 90 | bottom: 0; } 91 | 92 | /* Prevent selection and tap highlights */ 93 | .pswp__container, 94 | .pswp__img { 95 | -webkit-user-select: none; 96 | -moz-user-select: none; 97 | -ms-user-select: none; 98 | user-select: none; 99 | -webkit-tap-highlight-color: transparent; 100 | -webkit-touch-callout: none; } 101 | 102 | .pswp__zoom-wrap { 103 | position: absolute; 104 | width: 100%; 105 | -webkit-transform-origin: left top; 106 | -ms-transform-origin: left top; 107 | transform-origin: left top; 108 | /* for open/close transition */ 109 | -webkit-transition: -webkit-transform 333ms cubic-bezier(0.4, 0, 0.22, 1); 110 | transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1); } 111 | 112 | .pswp__bg { 113 | will-change: opacity; 114 | /* for open/close transition */ 115 | -webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); 116 | transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); } 117 | 118 | .pswp--animated-in .pswp__bg, 119 | .pswp--animated-in .pswp__zoom-wrap { 120 | -webkit-transition: none; 121 | transition: none; } 122 | 123 | .pswp__container, 124 | .pswp__zoom-wrap { 125 | -webkit-backface-visibility: hidden; } 126 | 127 | .pswp__item { 128 | position: absolute; 129 | left: 0; 130 | right: 0; 131 | top: 0; 132 | bottom: 0; 133 | overflow: hidden; } 134 | 135 | .pswp__img { 136 | position: absolute; 137 | width: auto; 138 | height: auto; 139 | top: 0; 140 | left: 0; } 141 | 142 | /* 143 | stretched thumbnail or div placeholder element (see below) 144 | style is added to avoid flickering in webkit/blink when layers overlap 145 | */ 146 | .pswp__img--placeholder { 147 | -webkit-backface-visibility: hidden; } 148 | 149 | /* 150 | div element that matches size of large image 151 | large image loads on top of it 152 | */ 153 | .pswp__img--placeholder--blank { 154 | background: #222; } 155 | 156 | .pswp--ie .pswp__img { 157 | width: 100% !important; 158 | height: auto !important; 159 | left: 0; 160 | top: 0; } 161 | 162 | /* 163 | Error message appears when image is not loaded 164 | (JS option errorMsg controls markup) 165 | */ 166 | .pswp__error-msg { 167 | position: absolute; 168 | left: 0; 169 | top: 50%; 170 | width: 100%; 171 | text-align: center; 172 | font-size: 14px; 173 | line-height: 16px; 174 | margin-top: -8px; 175 | color: #CCC; } 176 | 177 | .pswp__error-msg a { 178 | color: #CCC; 179 | text-decoration: underline; } 180 | -------------------------------------------------------------------------------- /templates/volunteers/update_schedule.html: -------------------------------------------------------------------------------- 1 | {% extends 'sidebar.html' %} 2 | 3 | {% load static %} 4 | 5 | {% block title %} Jagrati | Update Schedule {% endblock %} 6 | 7 | {% block content-sidebar %} 8 | 9 | 10 | 11 |
12 | ⟳ Refresh Page 13 |

Update Schedule

14 |
15 | {% csrf_token %} 16 |
17 |
18 | 19 | 25 |
26 |
27 | 28 | 29 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 |
38 |

Previous Requests

39 |
40 |

41 | {% if update_req.count %} 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | {% for req in update_req %} 52 | 53 | 60 | 61 | 62 | 63 | 76 | 77 | {% endfor %} 78 | 79 |
FromToStatus
54 | {% if req.previous_schedule is None %} 55 | NA 56 | {% else %} 57 | {{ req.previous_schedule }} 58 | {% endif %} 59 | {{ req.new_schedule }} 64 | {% if req.approved is True %} 65 | Approved 66 | {% elif req.declined is True %} 67 | Declined 68 | {% elif req.by_admin is True %} 69 | By Admin 70 | {% elif req.cancelled is True %} 71 | Cancelled 72 | {% else %} 73 | Pending 74 | {% endif %} 75 |
80 | {% else %} 81 |

No requests made yet!
82 | {% endif %} 83 |

84 |
85 |
86 |
87 |
88 | {% csrf_token %} 89 |
90 |
91 | 93 |
94 |
95 |
96 |
97 | 98 | {% endblock %} 99 | 100 | {% block scripts-sidebar %} 101 | 102 | 103 | 127 | 128 | {% endblock %} -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin 3 | 4 | from django.conf import settings 5 | from django.db.models.signals import post_save 6 | from django.dispatch import receiver 7 | from rest_framework.authtoken.models import Token 8 | from imagekit.models import ProcessedImageField 9 | from imagekit.processors import ResizeToFill 10 | from django.utils.crypto import get_random_string 11 | 12 | 13 | class UserManager(BaseUserManager): 14 | def create_user(self, email, password=None): # Add all required fields 15 | if not email: 16 | raise ValueError("User must have an email address") 17 | if not password: 18 | password = get_random_string(length=10) 19 | user = self.model( 20 | email=self.normalize_email(email), 21 | ) 22 | user.set_password(password) 23 | user.save(using=self._db) 24 | return user 25 | 26 | def create_staffuser(self, email, password=None): 27 | user = self.create_user( 28 | email, 29 | password=password, 30 | ) 31 | user.is_staff = True 32 | user.save(using=self._db) 33 | return user 34 | 35 | def create_superuser(self, email, password=None): 36 | user = self.create_user( 37 | email, 38 | password=password, 39 | ) 40 | user.is_staff = True 41 | user.is_superuser = True 42 | user.save(using=self._db) 43 | return user 44 | 45 | 46 | class User(AbstractBaseUser, PermissionsMixin): 47 | DESIG = ( 48 | ('v', 'Volunteer'), 49 | ('f', 'Faculty') 50 | ) 51 | 52 | email = models.EmailField( 53 | verbose_name="Email Address", max_length=255, unique=True) 54 | is_staff = models.BooleanField(default=False) 55 | is_active = models.BooleanField(default=True) 56 | auth = models.BooleanField(default=False) 57 | desig = models.CharField(max_length=1, choices=DESIG, default='v') 58 | date_joined = models.DateTimeField( 59 | verbose_name='Date Joined', auto_now_add=True) 60 | last_login = models.DateTimeField(verbose_name='Last Login', auto_now=True) 61 | 62 | USERNAME_FIELD = 'email' 63 | REQUIRED_FIELDS = [] # Required for 'createsuperuser' 64 | 65 | objects = UserManager() 66 | 67 | def __str__(self): 68 | return self.email 69 | 70 | def save(self, *args, **kwargs): 71 | """For cpanel.""" 72 | self.is_active = (self.is_active is True) 73 | self.is_staff = (self.is_staff is True) 74 | self.is_superuser = (self.is_superuser is True) 75 | self.auth = (self.auth is True) 76 | 77 | super(User, self).save(*args, **kwargs) 78 | 79 | 80 | @receiver(post_save, sender=settings.AUTH_USER_MODEL) 81 | def create_auth_token(sender, instance=None, created=False, **kwargs): 82 | """Generate a Token everytime a new User registers.""" 83 | if created: 84 | Token.objects.create(user=instance) 85 | 86 | 87 | class Profile(models.Model): 88 | GENDER = ( 89 | ('M', 'Male'), 90 | ('F', 'Female'), 91 | ('O', 'Other') 92 | ) 93 | 94 | user = models.OneToOneField(User, on_delete=models.CASCADE) 95 | first_name = models.CharField(verbose_name="First Name", max_length=50) 96 | last_name = models.CharField(verbose_name="Last name", max_length=50) 97 | profile_image = ProcessedImageField( 98 | upload_to='profile_pics', processors=[ResizeToFill(300, 300)], 99 | format='JPEG', options={'quality': 60}, blank=True) 100 | gender = models.CharField(max_length=1, choices=GENDER) 101 | alt_email = models.EmailField( 102 | verbose_name="Alternate Email", max_length=255, blank=True) 103 | contact_no = models.CharField(verbose_name="Contact Number", max_length=13) 104 | street_address1 = models.CharField( 105 | verbose_name="Address Line 1", max_length=255) 106 | street_address2 = models.CharField( 107 | verbose_name="Address Line 2", max_length=255, blank=True) 108 | city = models.CharField(max_length=50) 109 | state = models.CharField(max_length=50) 110 | pincode = models.CharField(max_length=6) 111 | 112 | def __str__(self): 113 | return f'{self.get_full_name} - {self.user.email}' 114 | 115 | @property 116 | def get_full_name(self): 117 | return f'{self.first_name} {self.last_name}' 118 | 119 | @property 120 | def get_complete_address(self): 121 | if self.street_address2: 122 | return f'{self.street_address1}, {self.street_address2}, {self.city} - {self.pincode}, {self.state}' 123 | return f'{self.street_address1}, {self.city} - {self.pincode}, {self.state}' 124 | 125 | @property 126 | def get_profile_image_url(self): 127 | if self.profile_image and hasattr(self.profile_image, 'url'): 128 | return self.profile_image.url 129 | elif self.gender == 'F': 130 | return settings.STATIC_URL + 'home/images/woman.png' 131 | else: 132 | return settings.STATIC_URL + 'home/images/man.png' 133 | 134 | 135 | class AuthorisedDevice(models.Model): 136 | user = models.ForeignKey(User, on_delete=models.CASCADE) 137 | device_id = models.CharField(max_length=255) 138 | active = models.BooleanField(default=True) 139 | 140 | class Meta: 141 | unique_together = (('user', 'device_id'),) 142 | 143 | def __str__(self): 144 | return f'{self.user.email} - {self.device_id}' 145 | -------------------------------------------------------------------------------- /apps/volunteers/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.db.models.signals import post_delete 3 | from django.dispatch import receiver 4 | from django.urls import reverse 5 | 6 | from accounts.models import Profile 7 | from home.models import Calendar, Schedule 8 | 9 | 10 | class Designation(models.Model): 11 | desig_id = models.CharField( 12 | max_length=10, verbose_name='Designation ID', unique=True) 13 | name = models.CharField(max_length=100) 14 | parent_desig = models.ForeignKey( 15 | 'self', on_delete=models.SET_NULL, null=True, blank=True) 16 | 17 | def __str__(self): 18 | return self.name 19 | 20 | 21 | class Volunteer(models.Model): 22 | PROGRAMME = ( 23 | ('bt', 'B.Tech'), 24 | ('mt', 'M.Tech'), 25 | ('phd', 'PhD'), 26 | ('bd', 'B.Des'), 27 | ('md', 'M.Des'), 28 | ) 29 | 30 | # user = models.OneToOneField(User, on_delete=models.CASCADE) 31 | profile = models.OneToOneField(Profile, on_delete=models.CASCADE) 32 | roll_no = models.CharField( 33 | verbose_name="Roll Number", max_length=8, unique=True) 34 | batch = models.IntegerField() 35 | programme = models.CharField(max_length=3, choices=PROGRAMME) 36 | dob = models.DateField(verbose_name="Date of Birth") 37 | desig = models.ForeignKey(Designation, on_delete=models.SET_NULL, 38 | null=True, blank=True) # null --> Normal Volunteer 39 | # resp = models.ForeignKey() 40 | active = models.BooleanField(default=True) 41 | 42 | def __str__(self): 43 | return f'{self.profile.get_full_name} ({self.roll_no})' 44 | 45 | def save(self, *args, **kwargs): 46 | """For cpanel.""" 47 | self.active = (self.active is True) 48 | super(Volunteer, self).save(*args, **kwargs) 49 | 50 | @property 51 | def profile_url(self): 52 | """Returns the url to volunteer profile.""" 53 | return reverse('volunteers:profile', args=[str(self.id)]) 54 | 55 | @receiver(post_delete, sender=Volunteer) 56 | def delete_related_profile(sender, instance, **kwargs): 57 | """Delete the related Profile.""" 58 | instance.profile.delete() 59 | 60 | 61 | class VolunteerSchedule(models.Model): 62 | volun = models.ForeignKey( 63 | Volunteer, on_delete=models.CASCADE, related_name='volun_schedules') 64 | day = models.IntegerField(choices=Schedule.DAY, blank=True) 65 | schedule = models.ForeignKey( 66 | Schedule, on_delete=models.CASCADE, related_name='volun_schedules') 67 | 68 | class Meta: 69 | unique_together = (('volun', 'day'),) 70 | verbose_name = 'Volunteer Schedule' 71 | verbose_name_plural = 'Volunteers Schedule' 72 | 73 | def __str__(self): 74 | return f'{self.volun} - {self.schedule}' 75 | 76 | 77 | class VolunteerAttendance(models.Model): 78 | volun = models.ForeignKey( 79 | Volunteer, on_delete=models.CASCADE, related_name='volun_attendance') 80 | cal_date = models.ForeignKey( 81 | Calendar, on_delete=models.CASCADE, related_name='volun_attendance') 82 | present = models.BooleanField(default=False) 83 | extra = models.BooleanField(default=False) 84 | 85 | class Meta: 86 | unique_together = (('volun', 'cal_date'),) 87 | verbose_name = 'Volunteer Attendance' 88 | verbose_name_plural = 'Volunteers Attendance' 89 | 90 | def __str__(self): 91 | return f'{self.volun} - {self.cal_date}' 92 | 93 | def save(self, *args, **kwargs): 94 | """For cpanel.""" 95 | self.present = (self.present is True) 96 | self.extra = (self.extra is True) 97 | super(VolunteerAttendance, self).save(*args, **kwargs) 98 | 99 | 100 | class UpdateScheduleRequest(models.Model): 101 | volun = models.ForeignKey( 102 | Volunteer, on_delete=models.CASCADE, related_name='update_sch_requests') 103 | previous_schedule = models.ForeignKey( 104 | Schedule, on_delete=models.SET_NULL, related_name='update_sch_requests_from', null=True, blank=True) 105 | new_schedule = models.ForeignKey( 106 | Schedule, on_delete=models.CASCADE, related_name='update_sch_requests_to') 107 | date = models.DateTimeField(verbose_name='Date', auto_now_add=True) 108 | 109 | # Only one of the below booleans will be true. Request pending if all false! 110 | approved = models.BooleanField(default=False) 111 | declined = models.BooleanField(default=False) 112 | # If shedule is updated by admin without request by volunteer 113 | by_admin = models.BooleanField(default=False) 114 | cancelled = models.BooleanField(default=False) 115 | 116 | def __str__(self): 117 | return self.volun.__str__() 118 | 119 | def save(self, *args, **kwargs): 120 | # Create VolunteerSchedule instance 121 | if self.approved is True or self.by_admin is True: # Schedule is updated in only these two cases 122 | prev_sch = VolunteerSchedule.objects.filter(volun=self.volun) 123 | if prev_sch.exists(): 124 | prev_sch = prev_sch[0] 125 | prev_sch.schedule = self.updated_schedule 126 | prev_sch.save() 127 | else: 128 | vol_sch = VolunteerSchedule( 129 | volun=self.volun, schedule=self.updated_schedule) 130 | vol_sch.save() 131 | # For CPanel 132 | self.approved = (self.approved is True) 133 | self.declined = (self.declined is True) 134 | self.by_admin = (self.by_admin is True) 135 | self.cancelled = (self.cancelled is True) 136 | super(UpdateScheduleRequest, self).save(*args, **kwargs) 137 | -------------------------------------------------------------------------------- /accounts/tests/test_views.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from django.urls import reverse 3 | 4 | from accounts.models import Profile, User 5 | from apps.volunteers.models import Volunteer 6 | 7 | 8 | class LoginSignupViewTest(TestCase): 9 | @classmethod 10 | def setUpTestData(cls): 11 | # Create a user 12 | test_user1 = User.objects.create_user( 13 | email='testuser1@gmail.com', password='1X 9 | @media screen and (max-width: 600px) { 10 | .container { 11 | width: 85vw; 12 | } 13 | } 14 | 15 | {% endblock %} 16 | 17 | {% block content %} 18 | 19 |
20 |
21 |

22 | Student Profile 23 |

24 |
25 | 26 |
27 |
28 |
29 |
30 | profile_image 32 |
33 |
34 |
35 |
36 | Name: 37 |
38 |
39 | {{ profile.get_full_name }} 40 |
41 |
42 |
43 |
44 | Class: 45 |
46 |
47 | {{ profile.school_class }} 48 |
49 |
50 |
51 |
52 | Village: 53 |
54 |
55 | {{ profile.get_village_display }} 56 |
57 |
58 |
59 |
60 | Gender: 61 |
62 |
63 | {{ profile.get_gender_display }} 64 |
65 |
66 |
67 |
68 | Guardian name: 69 |
70 |
71 | {{ profile.guardian_name}} 72 |
73 |
74 |
75 |
76 | Contact No. : 77 |
78 |
79 | {{ profile.contact_no }} 80 |
81 |
82 | 83 |
84 |
85 |
86 | {% if not profile.has_complete_profile %} 87 |

❗ Incomplete Profile

88 | {% elif not profile.verified %} 89 |

✘ Unverified Profile

90 | {% else %} 91 |

✔ Verified Profile

92 | {% endif %} 93 |
94 |
95 | {% if profile.has_complete_profile and not profile.verified %} 96 | Mark as verified 97 | {% elif profile.verified %} 98 | Mark as unverified 99 | {% endif %} 100 | 101 | Edit Profile 102 | 103 |
104 |
105 |
106 | {% comment %} 107 |
108 |

109 | Student Schedule 110 |

111 |
112 |
113 |
114 |
115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | {% for sch in stu_schedule %} 125 | 126 | 127 | 128 | 129 | 130 | {% endfor %} 131 | 132 |
DaySectionSubject
{{ sch.get_day_display }}{{ sch.schedule.section.name }}{{ sch.schedule.get_subject_display }}
133 |
134 |
135 |
136 | {% endcomment %} 137 |
138 | {% endblock %} --------------------------------------------------------------------------------