From 8f803cad2bc2dad03ff73617b90bb10adb5952f3 Mon Sep 17 00:00:00 2001 From: Nishant Nayak Date: Wed, 19 Jun 2024 19:59:04 +0530 Subject: [PATCH] Merge 'main' into 'achievements_page' Signed-off-by: Nishant Nayak --- ...er_executivemember_date_joined_and_more.py | 32 + corpus/accounts/models.py | 5 +- corpus/accounts/urls.py | 22 + corpus/accounts/views.py | 2 +- corpus/corpus/decorators.py | 23 + corpus/corpus/settings.py | 133 ++- corpus/corpus/urls.py | 20 + corpus/farewell/__init__.py | 0 corpus/farewell/add_data.py | 174 ++++ corpus/farewell/admin.py | 7 + corpus/farewell/apps.py | 6 + corpus/farewell/forms.py | 16 + corpus/farewell/migrations/0001_initial.py | 31 + corpus/farewell/migrations/__init__.py | 0 corpus/farewell/models.py | 12 + corpus/farewell/send_mail.py | 24 + corpus/farewell/tests.py | 1 + corpus/farewell/urls.py | 8 + corpus/farewell/views.py | 53 ++ corpus/pages/views.py | 4 + corpus/requirements.txt | 5 + corpus/templates/accounts/login.html | 4 + .../components/general_dropdown.html | 2 +- corpus/templates/components/navbar_large.html | 2 +- corpus/templates/electrika/home.html | 2 +- corpus/templates/emails/farewell/base.html | 64 ++ corpus/templates/emails/farewell/invite.html | 35 + corpus/templates/farewell/farewell.html | 784 ++++++++++++++++++ .../registration/password_reset_complete.html | 21 + .../registration/password_reset_confirm.html | 60 ++ .../registration/password_reset_done.html | 21 + .../registration/password_reset_email.html | 31 + .../registration/password_reset_form.html | 41 + .../registration/password_reset_subject.txt | 1 + corpus/templates/static/css/RedOctoberNF.otf | Bin 0 -> 32272 bytes corpus/templates/static/css/farewell.css | 354 ++++++++ corpus/templates/static/css/gesat.otf | Bin 0 -> 30456 bytes corpus/templates/static/img/summer-sands.jpeg | Bin 0 -> 508624 bytes .../static/js/farewell/particles-dark.json | 110 +++ .../virtual_expo/admin/dashboard.html | 82 ++ .../templates/virtual_expo/admin/manage.html | 198 +++++ corpus/templates/virtual_expo/base.html | 5 + corpus/templates/virtual_expo/header.html | 12 + corpus/templates/virtual_expo/home.html | 41 + .../virtual_expo/members/add_members.html | 76 ++ .../members/approver_dashboard.html | 53 ++ .../virtual_expo/members/dashboard.html | 96 +++ .../virtual_expo/members/edit_report.html | 104 +++ .../virtual_expo/members/new_report.html | 103 +++ corpus/templates/virtual_expo/report.html | 49 ++ .../virtual_expo/reports_by_year.html | 59 ++ corpus/virtual_expo/__init__.py | 0 corpus/virtual_expo/admin.py | 9 + corpus/virtual_expo/admin_urls.py | 7 + corpus/virtual_expo/admin_views.py | 61 ++ corpus/virtual_expo/apps.py | 6 + corpus/virtual_expo/forms.py | 62 ++ corpus/virtual_expo/member_urls.py | 22 + corpus/virtual_expo/member_views.py | 161 ++++ .../virtual_expo/migrations/0001_initial.py | 105 +++ corpus/virtual_expo/migrations/__init__.py | 0 corpus/virtual_expo/models.py | 56 ++ corpus/virtual_expo/tests.py | 1 + corpus/virtual_expo/urls.py | 16 + corpus/virtual_expo/views.py | 68 ++ docker-compose.yml | 1 + env.example | 3 + prod-docker-compose.yml | 1 + 68 files changed, 3558 insertions(+), 9 deletions(-) create mode 100644 corpus/accounts/migrations/0005_alter_executivemember_date_joined_and_more.py create mode 100644 corpus/farewell/__init__.py create mode 100644 corpus/farewell/add_data.py create mode 100644 corpus/farewell/admin.py create mode 100644 corpus/farewell/apps.py create mode 100644 corpus/farewell/forms.py create mode 100644 corpus/farewell/migrations/0001_initial.py create mode 100644 corpus/farewell/migrations/__init__.py create mode 100644 corpus/farewell/models.py create mode 100644 corpus/farewell/send_mail.py create mode 100644 corpus/farewell/tests.py create mode 100644 corpus/farewell/urls.py create mode 100644 corpus/farewell/views.py create mode 100644 corpus/templates/emails/farewell/base.html create mode 100644 corpus/templates/emails/farewell/invite.html create mode 100644 corpus/templates/farewell/farewell.html create mode 100644 corpus/templates/registration/password_reset_complete.html create mode 100644 corpus/templates/registration/password_reset_confirm.html create mode 100644 corpus/templates/registration/password_reset_done.html create mode 100644 corpus/templates/registration/password_reset_email.html create mode 100644 corpus/templates/registration/password_reset_form.html create mode 100644 corpus/templates/registration/password_reset_subject.txt create mode 100644 corpus/templates/static/css/RedOctoberNF.otf create mode 100644 corpus/templates/static/css/farewell.css create mode 100644 corpus/templates/static/css/gesat.otf create mode 100644 corpus/templates/static/img/summer-sands.jpeg create mode 100644 corpus/templates/static/js/farewell/particles-dark.json create mode 100644 corpus/templates/virtual_expo/admin/dashboard.html create mode 100644 corpus/templates/virtual_expo/admin/manage.html create mode 100644 corpus/templates/virtual_expo/base.html create mode 100644 corpus/templates/virtual_expo/header.html create mode 100644 corpus/templates/virtual_expo/home.html create mode 100644 corpus/templates/virtual_expo/members/add_members.html create mode 100644 corpus/templates/virtual_expo/members/approver_dashboard.html create mode 100644 corpus/templates/virtual_expo/members/dashboard.html create mode 100644 corpus/templates/virtual_expo/members/edit_report.html create mode 100644 corpus/templates/virtual_expo/members/new_report.html create mode 100644 corpus/templates/virtual_expo/report.html create mode 100644 corpus/templates/virtual_expo/reports_by_year.html create mode 100644 corpus/virtual_expo/__init__.py create mode 100644 corpus/virtual_expo/admin.py create mode 100644 corpus/virtual_expo/admin_urls.py create mode 100644 corpus/virtual_expo/admin_views.py create mode 100644 corpus/virtual_expo/apps.py create mode 100644 corpus/virtual_expo/forms.py create mode 100644 corpus/virtual_expo/member_urls.py create mode 100644 corpus/virtual_expo/member_views.py create mode 100644 corpus/virtual_expo/migrations/0001_initial.py create mode 100644 corpus/virtual_expo/migrations/__init__.py create mode 100644 corpus/virtual_expo/models.py create mode 100644 corpus/virtual_expo/tests.py create mode 100644 corpus/virtual_expo/urls.py create mode 100644 corpus/virtual_expo/views.py diff --git a/corpus/accounts/migrations/0005_alter_executivemember_date_joined_and_more.py b/corpus/accounts/migrations/0005_alter_executivemember_date_joined_and_more.py new file mode 100644 index 00000000..a73e20fd --- /dev/null +++ b/corpus/accounts/migrations/0005_alter_executivemember_date_joined_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.7 on 2024-03-21 05:30 +import datetime + +from django.db import migrations +from django.db import models + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0004_alter_executivemember_date_joined"), + ] + + operations = [ + migrations.AlterField( + model_name="executivemember", + name="date_joined", + field=models.DateTimeField( + default=datetime.datetime( + 2024, 3, 21, 5, 30, 54, 960770, tzinfo=datetime.timezone.utc + ), + verbose_name="Date Joined", + ), + ), + migrations.AlterField( + model_name="executivemember", + name="github", + field=models.CharField( + blank=True, max_length=39, null=True, verbose_name="GitHub Username" + ), + ), + ] diff --git a/corpus/accounts/models.py b/corpus/accounts/models.py index b537ecd6..c6abcade 100644 --- a/corpus/accounts/models.py +++ b/corpus/accounts/models.py @@ -2,6 +2,7 @@ from django.contrib.auth.base_user import BaseUserManager from django.contrib.auth.models import AbstractUser from django.db import models +from django.utils import timezone from django.utils.translation import gettext_lazy as _ from .validators import validate_ieee_email @@ -138,7 +139,9 @@ class ExecutiveMember(models.Model): max_length=39, blank=True, null=True, verbose_name="GitHub Username" ) is_nep = models.BooleanField(default=False, verbose_name="Is NEP Member?") - date_joined = models.DateField(verbose_name="Date Joined") + date_joined = models.DateTimeField( + default=timezone.now(), verbose_name="Date Joined" + ) def save(self, *args, **kwargs): self.roll_number = self.roll_number.upper() diff --git a/corpus/accounts/urls.py b/corpus/accounts/urls.py index 6c291ade..2eb02876 100644 --- a/corpus/accounts/urls.py +++ b/corpus/accounts/urls.py @@ -1,3 +1,7 @@ +from django.contrib.auth.views import PasswordResetCompleteView +from django.contrib.auth.views import PasswordResetConfirmView +from django.contrib.auth.views import PasswordResetDoneView +from django.contrib.auth.views import PasswordResetView from django.urls import path from .views import signin @@ -8,4 +12,22 @@ path("signup/", signup, name="accounts_signup"), path("login/", signin, name="accounts_signin"), path("logout/", signout, name="accounts_signout"), + path( + "reset/", + PasswordResetView.as_view( + html_email_template_name="../templates/registration/password_reset_email.html" # noqa: E501 + ), + name="password_reset", + ), + path("reset/done/", PasswordResetDoneView.as_view(), name="password_reset_done"), + path( + "reset/confirm///", + PasswordResetConfirmView.as_view(), + name="password_reset_confirm", + ), + path( + "reset/complete/", + PasswordResetCompleteView.as_view(), + name="password_reset_complete", + ), ] diff --git a/corpus/accounts/views.py b/corpus/accounts/views.py index aeefe9aa..3c64f948 100644 --- a/corpus/accounts/views.py +++ b/corpus/accounts/views.py @@ -58,7 +58,7 @@ def signin(request): else: exec_member = None - if exec_member is not None: + if exec_member: user = authenticate( username=exec_member[0].user.email, password=password ) diff --git a/corpus/corpus/decorators.py b/corpus/corpus/decorators.py index 4635cf96..9daec054 100644 --- a/corpus/corpus/decorators.py +++ b/corpus/corpus/decorators.py @@ -1,3 +1,4 @@ +from accounts.models import ExecutiveMember from config.models import ModuleConfiguration from django.contrib import messages from django.shortcuts import redirect @@ -53,3 +54,25 @@ def wrapper(request, *args, **kwargs): return wrapper return decorator + + +def ensure_exec_membership(): + def decorator(view_func): + def wrapper(request, *args, **kwargs): + try: + exec_member = ExecutiveMember.objects.get(user=request.user.id) + request.exec_member = exec_member + return view_func(request, *args, **kwargs) + except ExecutiveMember.DoesNotExist: + messages.error( + request, + """ + Permission denied. + Please contact the administrators if you think there is an issue. + """, + ) + return redirect("index") + + return wrapper + + return decorator diff --git a/corpus/corpus/settings.py b/corpus/corpus/settings.py index 64fdf1f8..38a9d8da 100644 --- a/corpus/corpus/settings.py +++ b/corpus/corpus/settings.py @@ -12,6 +12,9 @@ import os from pathlib import Path +import sentry_sdk +from django.core.exceptions import ImproperlyConfigured + if os.getenv("LIVECYCLE"): from dotenv import load_dotenv @@ -51,6 +54,8 @@ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + "ckeditor", + "ckeditor_uploader", "pages.apps.PagesConfig", "config.apps.ConfigConfig", "accounts.apps.AccountsConfig", @@ -59,6 +64,8 @@ "electrika.apps.ElectrikaConfig", "skyward_expedition.apps.SkywardExpeditionConfig", "robotrix.apps.RobotrixConfig", + "farewell.apps.FarewellConfig", + "virtual_expo.apps.VirtualExpoConfig", ] MIDDLEWARE = [ @@ -164,6 +171,10 @@ AUTHENTICATION_BACKENDS = [ "accounts.backend.CorpusAuthBackend", ] + +# Reset Timeout in seconds. 1 day +PASSWORD_RESET_TIMEOUT = 86400 + LOGIN_URL = "/accounts/login" LOGIN_REDIRECT_URL = "/" LOGOUT_URL = "" @@ -172,11 +183,125 @@ SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") # Email Settings -EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" -EMAIL_HOST = os.getenv("EMAIL_HOST", "smtp.gmail.com") -EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER", "corpusieeenitk@gmail.com") -EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD", "gmailapppassword") +EMAIL_PROTOCOL = os.getenv("EMAIL_PROTOCOL", "console") + +EMAIL_BACKEND = f"django.core.mail.backends.{EMAIL_PROTOCOL}.EmailBackend" +EMAIL_HOST = os.environ.get("EMAIL_HOST", "smtp.gmail.com") +EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", "corpusieeenitk@gmail.com") +EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", "gmailapppassword") EMAIL_PORT = 465 EMAIL_USE_SSL = True USE_TAILWIND_CDN_LINK = os.getenv("LIVECYCLE") is not None + +SENTRY_DSN = os.environ.get("SENTRY_DSN") +if os.getenv("ENVIRONMENT", "PRODUCTION") == "PRODUCTION": + try: + sentry_sdk.init( + dsn=SENTRY_DSN, + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for performance monitoring. + traces_sample_rate=1.0, + # Set profiles_sample_rate to 1.0 to profile 100% + # of sampled transactions. + # We recommend adjusting this value in production. + profiles_sample_rate=1.0, + enable_tracing=True, + ) + except Exception: + raise ImproperlyConfigured("Django Sentry DSN Not found!") + +CKEDITOR_UPLOAD_PATH = "ckeditor_uploads/" +CKEDITOR_RESTRICT_BY_USER = True +CKEDITOR_CONFIGS = { + "default": { + "toolbar_DefaultToolbarConfig": [ + { + "name": "format", + "items": [ + "Format", + ], + }, + { + "name": "extra", + "items": [ + "Link", + "Unlink", + "Blockquote", + "Image", + "Table", + "CodeSnippet", + "Mathjax", + "Embed", + ], + }, + { + "name": "source", + "items": [ + "Maximize", + "Source", + ], + }, + { + "name": "basicstyles", + "items": [ + "Bold", + "Italic", + "Underline", + "Strike", + "Subscript", + "Superscript", + ], + }, + { + "name": "clipboard", + "items": [ + "Undo", + "Redo", + ], + }, + { + "name": "paragraph", + "items": [ + "NumberedList", + "BulletedList", + "Outdent", + "Indent", + "HorizontalRule", + "JustifyLeft", + "JustifyCenter", + "JustifyRight", + "JustifyBlock", + ], + }, + ], + "toolbar": "DefaultToolbarConfig", + "removeDialogTabs": ";".join( + [ + "image:advanced", + "image:Link", + "link:upload", + "table:advanced", + "tableProperties:advanced", + ] + ), + "linkShowTargetTab": False, + "linkShowAdvancedTab": False, + "height": "250px", + "width": "auto", + "forcePasteAsPlainText ": True, + "mathJaxClass": "mathjax-latex", + "mathJaxLib": """ + https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_SVG + """, + "extraPlugins": ",".join( + [ + "mathjax", + "codesnippet", + "image2", + "embed", + "tableresize", + ] + ), + } +} diff --git a/corpus/corpus/urls.py b/corpus/corpus/urls.py index 89d670e4..2aa3b1c2 100644 --- a/corpus/corpus/urls.py +++ b/corpus/corpus/urls.py @@ -14,11 +14,26 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ +from ckeditor_uploader import views as ckeditor_views +from django.conf import settings +from django.conf.urls.static import static from django.contrib import admin +from django.contrib.auth.decorators import login_required from django.urls import include from django.urls import path +from django.views.decorators.cache import never_cache urlpatterns = [ + path( + "ckeditor/upload/", + login_required(ckeditor_views.upload), + name="ckeditor_upload", + ), + path( + "ckeditor/browse/", + never_cache(login_required(ckeditor_views.browse)), + name="ckeditor_browse", + ), path("admin/", admin.site.urls), path("accounts/", include("accounts.urls")), path("", include("pages.urls")), @@ -27,4 +42,9 @@ path("electrika/", include("electrika.urls")), path("skyward_expedition/", include("skyward_expedition.urls")), path("robotrix/", include("robotrix.urls")), + path("farewell/", include("farewell.urls")), + path("virtual_expo/", include("virtual_expo.urls")), ] + +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/corpus/farewell/__init__.py b/corpus/farewell/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/corpus/farewell/add_data.py b/corpus/farewell/add_data.py new file mode 100644 index 00000000..c7173891 --- /dev/null +++ b/corpus/farewell/add_data.py @@ -0,0 +1,174 @@ +import random +import string + +from farewell.models import Senior + +names = [ + "Harish Ravi Kale", + "Madhan Raj R", + "Mohite Manthan Ravindra", + "Amandeep Singh", + "Mehul Todi", + "Rakshith M", + "Rohan Kamat", + "Ashish Bharath", + "Kavya Bhat", + "Madhav Kumar", + "Tejas Sankpal", + "Sathvik Hebbar", + "Shashank SM", + "Vikas Keshavamurthy Bhat", + "Gaurav Kumar", + "Shannon Britney Carlo", + "Anirudh Prabhakaran", + "Jaya Srivastava", + "Palgun N P", + "R S Muthukumar", + "Raghuram Kannan", + "Utkarsh Mahajan", + "Vasanth M", + "Inbasekaran Perumal", + "K A Gaganashree", + "Meghna Uppuluri", + "Nikhil P Reddy", + "Pranav M Koundinya", + "Vaishali S", + "Hrishikesh Kulkarni", + "Anirudh Singh Solanki", + "Ashrith DR", + "DEEPANSHU GUPTA", + "Dharaneedaran K S", + "Apurva S", + "RISHEE K", + "Dhruvil Lakhtaria", + "Mohan Gunakara Nayak", + "Pranav R S", + "Radhika Chhabra", + "Tejaswi Hegde", + "Advaith Prasad Curpod", + "Akheel Muhammed", + "Anurag Kumar", + "Harish Gumnur", + "Mohammed Ayman Nawaz", + "Swetha Mary Thomas", + "Vinayak Vatsalya J", + "Aryan Amit Barsainyan", + "Himanshu S Garud", + "Kshamaa Acharya B", + "Rupankar Das", + "SHRIRAMU A R", + "Siddh Narhari", + "ANANNYA RAO", + "Shivani Chanda", + "Abhilash Bharadwaj", + "SHASHANK H S", + "Saee Sholapurkar", + "Sunaina Sunil", + "Juvva Srinithya", + "Raghwendra Pratap Yadav", + "Sukrit Dass T M", +] + +email_addresses = [ + "harishravikale.201ch024@nitk.edu.in", + "madhanrajr.201ch029@nitk.edu.in", + "manthanrmohite.201ch036@nitk.edu.in", + "amandeepsingh.201cs107@nitk.edu.in", + "mehultodi.201cs133@nitk.edu.in", + "rakshith.201cs146@nitk.edu.in", + "rohankamat.201cs147@nitk.edu.in", + "ashishbharath.201cs208@nitk.edu.in", + "kavyabhat.201cs225@nitk.edu.in", + "madhavkumar.201cs228@nitk.edu.in", + "sankpaltejas.201cs253@nitk.edu.in", + "sathvikhebbar.201cs254@nitk.edu.in", + "shash.201cs257@nitk.edu.in", + "vikaskeshavamurthybhat.201cs266@nitk.edu.in", + "gauravkumar.201cv117@nitk.edu.in", + "shannonbritneycarlo.201cv249@nitk.edu.in", + "anirudhprabhakaran.201ec106@nitk.edu.in", + "jayasrivastava.201ec124@nitk.edu.in", + "palgun.201ec141@nitk.edu.in", + "rsmuthukumar.201ec149@nitk.edu.in", + "raghuram.201ec150@nitk.edu.in", + "ut.201ec164@nitk.edu.in", + "vasanth.201ec165@nitk.edu.in", + "inba.201ec226@nitk.edu.in", + "gaganashree.201ec228@nitk.edu.in", + "meghna.201ec237@nitk.edu.in", + "nikhilreddy.201ec241@nitk.edu.in", + "pranavmkoundinya.201ec247@nitk.edu.in", + "vaish.201ee263@nitk.edu.in", + "kulkarnihrishikeshprahlad.201ee101@nitk.edu.in", + "anirudhsinghsolanki.201ee107@nitk.edu.in", + "ashrithdr.201ee117@nitk.edu.in", + "deepanshugupta.201ee119@nitk.edu.in", + "dharaneedaranks.201ee120@nitk.edu.in", + "apurva.201ee209@nitk.edu.in", + "risheek.201ee244@nitk.edu.in", + "dhruvillakhtaria.201it119@nitk.edu.in", + "mohannayak.201it137@nitk.edu.in", + "pranavrs.201it143@nitk.edu.in", + "radhika.201it144@nitk.edu.in", + "tejaswihegde.201it163@nitk.edu.in", + "advaithprasadcurpod.201it204@nitk.edu.in", + "akheelmuhammed.201it206@nitk.edu.in", + "anuragkumar.201it209@nitk.edu.in", + "gumnurharish.201it223@nitk.edu.in", + "mohammedaymannawaz.201it236@nitk.edu.in", + "swethathomas.201it262@nitk.edu.in", + "vinayakvatsalyaj.201it266@nitk.edu.in", + "aryanab.201me110@nitk.edu.in", + "himan.201me122@nitk.edu.in", + "kshamaaacharyab.201me128@nitk.edu.in", + "rupankar.201me148@nitk.edu.in", + "shriramuar.201me155@nitk.edu.in", + "siddhnarhari.201me156@nitk.edu.in", + "anannya.201me209@nitk.edu.in", + "shivani.201me215@nitk.edu.in", + "abhilashbharadwaj.201me227@nitk.edu.in", + "shashankhs.201me252@nitk.edu.in", + "saeesholapurkar.201me253@nitk.edu.in", + "sunainasunil.201me357@nitk.edu.in", + "juvvasrinithya.201mt023@nitk.edu.in", + "raghw.201mt044@nitk.edu.in", + "tmsdass.201mt056@nitk.edu.in", +] + +# test +# names = [ +# 'Vignaraj', +# 'Aditya Srihari' +# ] + +# email_addresses = [ +# 'vignarajpai@gmail.com', +# 'adithyasriharirao.211me203@nitk.edu.in', +# ] + +# clear the Senior table +Senior.objects.all().delete() +print("Cleared the Senior table") + +url_ids = [] + +for name in names: + url_id = "".join(random.choices(string.ascii_letters + string.digits, k=5)) + # make sure its unique + while url_id in url_ids: + url_id = "".join(random.choices(string.ascii_letters + string.digits, k=5)) + url_ids.append(url_id) + +print("Generated unique url_ids") + + +for name, url_id, email_address in zip(names, url_ids, email_addresses): + Senior.objects.create( + name=name, + url_id=url_id, + email_id=email_address, + coming_farewell=False, + coming_afterparty=False, + ) + +print("Added data to the Senior table") diff --git a/corpus/farewell/admin.py b/corpus/farewell/admin.py new file mode 100644 index 00000000..6fb86216 --- /dev/null +++ b/corpus/farewell/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +from .models import Senior + +# Register your models here. + +admin.site.register(Senior) diff --git a/corpus/farewell/apps.py b/corpus/farewell/apps.py new file mode 100644 index 00000000..0db10d56 --- /dev/null +++ b/corpus/farewell/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FarewellConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "farewell" diff --git a/corpus/farewell/forms.py b/corpus/farewell/forms.py new file mode 100644 index 00000000..3896d739 --- /dev/null +++ b/corpus/farewell/forms.py @@ -0,0 +1,16 @@ +from farewell.models import Senior + +from corpus.forms import CorpusModelForm + + +class SeniorForm(CorpusModelForm): + class Meta: + model = Senior + fields = [ + "coming_farewell", + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.fields["coming_farewell"].widget.attrs["id"] = "check-5" diff --git a/corpus/farewell/migrations/0001_initial.py b/corpus/farewell/migrations/0001_initial.py new file mode 100644 index 00000000..e5627832 --- /dev/null +++ b/corpus/farewell/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.7 on 2024-03-16 11:44 +from django.db import migrations +from django.db import models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Senior", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=30)), + ("url_id", models.CharField(max_length=5)), + ("email_id", models.EmailField(max_length=50, null=True)), + ("coming_farewell", models.BooleanField(default=False)), + ], + ), + ] diff --git a/corpus/farewell/migrations/__init__.py b/corpus/farewell/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/corpus/farewell/models.py b/corpus/farewell/models.py new file mode 100644 index 00000000..128efcbd --- /dev/null +++ b/corpus/farewell/models.py @@ -0,0 +1,12 @@ +from django.db import models + + +# Create your models here. +class Senior(models.Model): + name = models.CharField(max_length=30, blank=False, null=False) + url_id = models.CharField(max_length=5, blank=False, null=False) + email_id = models.EmailField(max_length=50, blank=False, null=True) + coming_farewell = models.BooleanField(default=False) + + def __str__(self): + return self.name diff --git a/corpus/farewell/send_mail.py b/corpus/farewell/send_mail.py new file mode 100644 index 00000000..b8e8c6cb --- /dev/null +++ b/corpus/farewell/send_mail.py @@ -0,0 +1,24 @@ +from farewell.models import Senior + +from corpus.utils import send_email + + +def send_mails(): + # Get all seniors + seniors = Senior.objects.all() + for senior in seniors: + name = senior.name + email = senior.email_id + email = [email] + url_id = senior.url_id + url_link = f"https://ieee.nitk.ac.in/farewell/{url_id}" + send_email( + "", + "emails/farewell/invite.html", + {"url_link": url_link, "name": name}, + bcc=email, + ) + print(f"Email sent to {email}") + + +send_mails() diff --git a/corpus/farewell/tests.py b/corpus/farewell/tests.py new file mode 100644 index 00000000..a39b155a --- /dev/null +++ b/corpus/farewell/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/corpus/farewell/urls.py b/corpus/farewell/urls.py new file mode 100644 index 00000000..9f62f6cd --- /dev/null +++ b/corpus/farewell/urls.py @@ -0,0 +1,8 @@ +from django.urls import path + +from .views import index + +urlpatterns = [ + path("", index, name="farewell"), + path("", index, name="farewell"), +] diff --git a/corpus/farewell/views.py b/corpus/farewell/views.py new file mode 100644 index 00000000..e77854a2 --- /dev/null +++ b/corpus/farewell/views.py @@ -0,0 +1,53 @@ +from django.contrib import messages +from django.http import HttpResponseRedirect +from django.shortcuts import redirect +from django.shortcuts import render +from farewell.forms import SeniorForm +from farewell.models import Senior + + +# Create your views here +def index(request, pk=None): + if pk is None: + return redirect("https://http.cat/404") + try: + form = SeniorForm(instance=Senior.objects.get(url_id=pk)) + except Senior.DoesNotExist: + return redirect("https://http.cat/404") + + if request.method == "POST": + form = SeniorForm(request.POST, instance=Senior.objects.get(url_id=pk)) + try: + senior = Senior.objects.get(url_id=pk) + form = SeniorForm(request.POST, instance=senior) + except Senior.DoesNotExist: + senior = None + form.name = "Senior" + form.url_id = pk + + if form.is_valid(): + form.save() + if form.cleaned_data["coming_farewell"]: + messages.success(request, "Yayy! Here's to a great farewell! 🍻") + else: + messages.success(request, "Oh no! We'll miss you! 😢") + + # save the senior info with the form + senior = form.save(commit=False) + senior.save() + + redirect_url = f"/farewell/{pk}" + return HttpResponseRedirect(redirect_url) + + else: + print(form.errors) + return HttpResponseRedirect(request.path) + + try: + name = Senior.objects.get(url_id=pk).name + except Senior.DoesNotExist: + name = "Senior" + + args = {"name": name, "form": form} + + return render(request, "farewell/farewell.html", args) diff --git a/corpus/pages/views.py b/corpus/pages/views.py index b566d759..e606927f 100644 --- a/corpus/pages/views.py +++ b/corpus/pages/views.py @@ -72,3 +72,7 @@ def achievements(request): "publications_map": publications_year_map, }, ) + + +def farewell(request): + return render(request, "pages/farewell.html") diff --git a/corpus/requirements.txt b/corpus/requirements.txt index 413a85da..c7270643 100644 --- a/corpus/requirements.txt +++ b/corpus/requirements.txt @@ -1,7 +1,10 @@ asgiref==3.7.2 +certifi==2024.2.2 cfgv==3.4.0 distlib==0.3.8 Django==4.2.7 +django-ckeditor==6.7.1 +django-js-asset==2.2.0 filelock==3.13.1 gunicorn==21.2.0 identify==2.5.34 @@ -14,8 +17,10 @@ pre-commit==3.6.1 psycopg2-binary==2.9.9 python-magic==0.4.27 PyYAML==6.0.1 +sentry-sdk==1.40.5 setuptools==68.2.2 sqlparse==0.4.4 typing_extensions==4.8.0 +urllib3==2.2.1 virtualenv==20.25.0 wheel==0.41.2 diff --git a/corpus/templates/accounts/login.html b/corpus/templates/accounts/login.html index 77d943b7..7f93f836 100644 --- a/corpus/templates/accounts/login.html +++ b/corpus/templates/accounts/login.html @@ -47,6 +47,10 @@

Login

{% endif %} +
diff --git a/corpus/templates/components/general_dropdown.html b/corpus/templates/components/general_dropdown.html index da21d2b7..e053fd5e 100644 --- a/corpus/templates/components/general_dropdown.html +++ b/corpus/templates/components/general_dropdown.html @@ -4,7 +4,7 @@
  • About Us
  • Blog
  • Gyan
  • -
  • Virtual Expo +
  • Virtual Expo
  • diff --git a/corpus/templates/components/navbar_large.html b/corpus/templates/components/navbar_large.html index c15d87df..3c1d253d 100644 --- a/corpus/templates/components/navbar_large.html +++ b/corpus/templates/components/navbar_large.html @@ -65,7 +65,7 @@ Blog Gyan - Virtual Expo + Virtual Expo