diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6ceec31..cae8a7bb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,7 +42,7 @@ repos: hooks: - id: reorder-python-imports - # Use the following hooks locally to check for issues. These will mostly always fail on CI. + # # Use the following hooks locally to check for issues. These will mostly always fail on CI. # - repo: https://github.com/PyCQA/bandit # rev: 1.7.5 # hooks: @@ -58,7 +58,7 @@ repos: # hooks: # - id: shellcheck - - repo: https://github.com/ecugol/pre-commit-hooks-django - rev: v0.4.0 # Use the ref you want to point at - hooks: - - id: check-untracked-migrations + # - repo: https://github.com/ecugol/pre-commit-hooks-django + # rev: v0.4.0 + # hooks: + # - id: check-untracked-migrations diff --git a/corpus/accounts/admin.py b/corpus/accounts/admin.py index c5f61419..7521e2b9 100644 --- a/corpus/accounts/admin.py +++ b/corpus/accounts/admin.py @@ -52,7 +52,7 @@ class CorpusUserAdmin(UserAdmin): class ExecutiveMemberAdmin(admin.ModelAdmin): fieldsets = ( - (None, {"fields": ("user", "sig")}), + (None, {"fields": ("user", "sig", "date_joined")}), ( "NITK Related Details", { diff --git a/corpus/accounts/forms.py b/corpus/accounts/forms.py index 3f89abf0..40b78832 100644 --- a/corpus/accounts/forms.py +++ b/corpus/accounts/forms.py @@ -30,7 +30,15 @@ def __init__(self, *args, **kwargs): for visible in self.visible_fields(): visible.field.widget.attrs[ "class" - ] = "mt-1 block w-full rounded-md border-base-800 text-black shadow-sm focus:border-primary focus:ring focus:ring-primary-200 focus:ring-opacity-50" # noqa: E501 + ] = "mt-1 w-full rounded-md shadow-sm" # noqa: E501 + if visible.field.widget.input_type in ["text", "password", "email"]: + visible.field.widget.attrs[ + "class" + ] += " input input-bordered focus:input-primary" + elif visible.field.widget.input_type == "select": + visible.field.widget.attrs[ + "class" + ] += " select select-bordered focus:select-primary" class CorpusChangeForm(UserChangeForm): @@ -54,7 +62,11 @@ def __init__(self, *args, **kwargs): for visible in self.visible_fields(): visible.field.widget.attrs[ "class" - ] = "mt-1 block w-full rounded-md border-base-800 text-black shadow-sm focus:border-primary focus:ring focus:ring-primary-200 focus:ring-opacity-50" # noqa: E501 + ] = "mt-1 w-full rounded-md shadow-sm" # noqa: E501 + if visible.field.widget.input_type in ["text", "password", "email"]: + visible.field.widget.attrs[ + "class" + ] += " input input-bordered focus:input-primary" def clean_username(self): username = self.cleaned_data.get("username") diff --git a/corpus/dev_accounts_db.json b/corpus/dev_accounts_db.json new file mode 100644 index 00000000..f0efa1b6 --- /dev/null +++ b/corpus/dev_accounts_db.json @@ -0,0 +1,237 @@ +[ + { + "fields": { + "date_joined": "2024-02-25T15:58:04Z", + "email": "admin@example.com", + "first_name": "Admin", + "gender": "N", + "groups": [], + "is_active": true, + "is_staff": true, + "is_superuser": true, + "last_login": "2024-02-25T16:00:26Z", + "last_name": "Example", + "password": "pbkdf2_sha256$600000$fcABeeEsmGM15Dd4lG7WiW$9G/1iMoCAGb4whUweOPTRyCpLy6IMY8Pmu1zg7zi27c=", + "phone_no": "1234567890", + "user_permissions": [] + }, + "model": "accounts.user", + "pk": 1 + }, + { + "fields": { + "date_joined": "2024-02-25T16:09:40Z", + "email": "user1@example.com", + "first_name": "User", + "gender": "N", + "groups": [], + "is_active": true, + "is_staff": false, + "is_superuser": false, + "last_login": null, + "last_name": "One", + "password": "pbkdf2_sha256$600000$Cwv74DWoks3V5dS0dQnP1a$7VX3L74bdTOEgwabvhSU+JuOPCvoFtNC/vIMYP/SfTo=", + "phone_no": "1234567891", + "user_permissions": [] + }, + "model": "accounts.user", + "pk": 2 + }, + { + "fields": { + "date_joined": "2024-02-25T16:11:26Z", + "email": "user2@example.com", + "first_name": "User", + "gender": "N", + "groups": [], + "is_active": true, + "is_staff": false, + "is_superuser": false, + "last_login": null, + "last_name": "Two", + "password": "pbkdf2_sha256$600000$gL00s5frbSpEo4YXULxMXX$NOYvJ9dtdbI/5JkjRwMC+JAcGlftqinNXqkyaTGLroo=", + "phone_no": "1234567892", + "user_permissions": [] + }, + "model": "accounts.user", + "pk": 4 + }, + { + "fields": { + "date_joined": "2024-02-25T16:12:05Z", + "email": "user3@example.com", + "first_name": "User", + "gender": "N", + "groups": [], + "is_active": true, + "is_staff": false, + "is_superuser": false, + "last_login": null, + "last_name": "Three", + "password": "pbkdf2_sha256$600000$Uez7rmaWTOC8H6w7f5G4XA$f9m+LV1q6rpucl45hRMyEK7Lw61nxy+hxS7TUfhwwqM=", + "phone_no": "1234567893", + "user_permissions": [] + }, + "model": "accounts.user", + "pk": 5 + }, + { + "fields": { + "date_joined": "2024-02-25T16:13:01Z", + "email": "user4@example.com", + "first_name": "User", + "gender": "N", + "groups": [], + "is_active": true, + "is_staff": false, + "is_superuser": false, + "last_login": null, + "last_name": "Four", + "password": "pbkdf2_sha256$600000$4R9AoWCJlh5aEjreZQ0jVr$G2z4zf69SkLbKt+dbjGgasj/0LdvSK8Q5hm9jQIi9Ro=", + "phone_no": "1234567894", + "user_permissions": [] + }, + "model": "accounts.user", + "pk": 6 + }, + { + "fields": { + "date_joined": "2024-02-25T16:13:47Z", + "email": "user5@example.com", + "first_name": "User", + "gender": "N", + "groups": [], + "is_active": true, + "is_staff": false, + "is_superuser": false, + "last_login": null, + "last_name": "Five", + "password": "pbkdf2_sha256$600000$278aPjc0My2xPLEwb9Vy4E$K4xSetizP3uXDyITBDvWMly3ZjoETgugL0mRxmFlF+U=", + "phone_no": "1234567895", + "user_permissions": [] + }, + "model": "accounts.user", + "pk": 7 + }, + { + "fields": { + "date_joined": "2024-02-25T16:14:32Z", + "email": "user6@example.com", + "first_name": "User", + "gender": "N", + "groups": [], + "is_active": true, + "is_staff": false, + "is_superuser": false, + "last_login": null, + "last_name": "Six", + "password": "pbkdf2_sha256$600000$ealY6zpHM8mFG7rU5XD4Kv$OpV5Hxbk7FBx4rnlLG8s+aRG+byAXvSIAdtj+fAZmUk=", + "phone_no": "1234567896", + "user_permissions": [] + }, + "model": "accounts.user", + "pk": 8 + }, + { + "fields": { + "date_joined": "2024-02-25", + "edu_email": "user1@nitk.edu.in", + "github": "user1", + "ieee_email": "user1@ieee.org", + "ieee_number": "12345671", + "is_nep": true, + "linkedin": "https://www.linkedin.com/in/user1/", + "minor_branch": "CS", + "reg_number": "123001", + "roll_number": "123XX001", + "sig": 1 + }, + "model": "accounts.executivemember", + "pk": 2 + }, + { + "fields": { + "date_joined": "2024-02-25", + "edu_email": "user2@nitk.edu.in", + "github": "user2", + "ieee_email": "user2@ieee.org", + "ieee_number": "12345672", + "is_nep": true, + "linkedin": null, + "minor_branch": null, + "reg_number": "123002", + "roll_number": "123XX002", + "sig": 2 + }, + "model": "accounts.executivemember", + "pk": 4 + }, + { + "fields": { + "date_joined": "2024-02-25", + "edu_email": "user3@nitk.edu.in", + "github": null, + "ieee_email": null, + "ieee_number": null, + "is_nep": false, + "linkedin": "https://www.linkedin.com/in/user3/", + "minor_branch": "PS", + "reg_number": "123003", + "roll_number": "123XX003", + "sig": 3 + }, + "model": "accounts.executivemember", + "pk": 5 + }, + { + "fields": { + "date_joined": "2024-02-25", + "edu_email": "user4@nitk.edu.in", + "github": "user4", + "ieee_email": null, + "ieee_number": "12345674", + "is_nep": false, + "linkedin": null, + "minor_branch": "IT", + "reg_number": "123004", + "roll_number": "123XX004", + "sig": 1 + }, + "model": "accounts.executivemember", + "pk": 6 + }, + { + "fields": { + "date_joined": "2024-02-25", + "edu_email": "user5@nitk.edu.in", + "github": null, + "ieee_email": "user5@ieee.org", + "ieee_number": null, + "is_nep": true, + "linkedin": null, + "minor_branch": "EC", + "reg_number": "123005", + "roll_number": "123XX005", + "sig": 2 + }, + "model": "accounts.executivemember", + "pk": 7 + }, + { + "fields": { + "date_joined": "2024-02-25", + "edu_email": "user6@nitk.edu.in", + "github": null, + "ieee_email": null, + "ieee_number": null, + "is_nep": false, + "linkedin": null, + "minor_branch": null, + "reg_number": "123006", + "roll_number": "123XX006", + "sig": 3 + }, + "model": "accounts.executivemember", + "pk": 8 + } +] diff --git a/corpus/dev_pages_db.json b/corpus/dev_pages_db.json new file mode 100644 index 00000000..e3f0532c --- /dev/null +++ b/corpus/dev_pages_db.json @@ -0,0 +1,71 @@ +[ + { + "fields": { + "date": "2023-03-01", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In volutpat pretium imperdiet. Donec sit amet orci dignissim, commodo odio in.", + "title": "Example Achievement 1", + "url": "https://www.example.com/", + "user": 2 + }, + "model": "pages.achievement", + "pk": 1 + }, + { + "fields": { + "date": "2023-10-04", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet cursus ligula, sit amet semper nisi. Sed ut ex.", + "title": "Example Achievement 2", + "url": null, + "user": null + }, + "model": "pages.achievement", + "pk": 2 + }, + { + "fields": { + "date": "2022-11-30", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse purus urna, interdum ut diam eu, venenatis tristique augue. Praesent eu.", + "title": "Example Achievement 3", + "url": null, + "user": null + }, + "model": "pages.achievement", + "pk": 3 + }, + { + "fields": { + "achievement": 1, + "tag": "GSOC" + }, + "model": "pages.tag", + "pk": 1 + }, + { + "fields": { + "achievement": 3, + "tag": "IAS SRFP" + }, + "model": "pages.tag", + "pk": 2 + }, + { + "fields": { + "achievement": 3, + "tag": "SB" + }, + "model": "pages.tag", + "pk": 3 + }, + { + "fields": { + "authors": "John Doe, Jane Doe, Someone Else", + "date": "2023-05-10", + "source": "Journal of Example", + "title": "Example Publication 1", + "url": "https://www.example.com/", + "user": null + }, + "model": "pages.publication", + "pk": 1 + } +] diff --git a/corpus/package.json b/corpus/package.json index 9dbece05..6bef96f3 100644 --- a/corpus/package.json +++ b/corpus/package.json @@ -4,7 +4,6 @@ "devDependencies": { "@tailwindcss/aspect-ratio": "^0.4.2", "@tailwindcss/container-queries": "^0.1.1", - "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.10", "daisyui": "^4.4.24", "tailwindcss": "^3.4.0" diff --git a/corpus/pages/admin.py b/corpus/pages/admin.py new file mode 100644 index 00000000..15f7eb0d --- /dev/null +++ b/corpus/pages/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +from .models import Achievement +from .models import Publication +from .models import Tag + +admin.site.register(Achievement) +admin.site.register(Publication) +admin.site.register(Tag) diff --git a/corpus/pages/migrations/0001_initial.py b/corpus/pages/migrations/0001_initial.py new file mode 100644 index 00000000..e859e1a7 --- /dev/null +++ b/corpus/pages/migrations/0001_initial.py @@ -0,0 +1,111 @@ +# Generated by Django 4.2.7 on 2024-03-10 14:36 +import django.db.models.deletion +from django.conf import settings +from django.db import migrations +from django.db import models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Achievement", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=128, verbose_name="Title")), + ("date", models.DateField(verbose_name="Date of Achievement")), + ( + "url", + models.URLField(blank=True, null=True, verbose_name="Related URL"), + ), + ("description", models.TextField(verbose_name="Description")), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Related User", + ), + ), + ], + ), + migrations.CreateModel( + name="Tag", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "tag", + models.CharField( + choices=[ + ("GSOC", "Google Summer of Code"), + ("IAS SRFP", "IAS Summer Research Fellowship Program"), + ("SB", "Student Branch Award"), + ], + max_length=32, + verbose_name="Tag", + ), + ), + ( + "achievement", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="pages.achievement", + verbose_name="Achievement", + ), + ), + ], + ), + migrations.CreateModel( + name="Publication", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=256, verbose_name="Title")), + ("date", models.DateField(verbose_name="Publish Date")), + ("url", models.URLField(verbose_name="URL")), + ("authors", models.CharField(max_length=256, verbose_name="Authors")), + ("source", models.CharField(max_length=512, verbose_name="Source")), + ( + "user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + verbose_name="Related User", + ), + ), + ], + ), + ] diff --git a/corpus/pages/models.py b/corpus/pages/models.py new file mode 100644 index 00000000..a964679c --- /dev/null +++ b/corpus/pages/models.py @@ -0,0 +1,51 @@ +from accounts.models import User +from django.db import models + + +class Achievement(models.Model): + title = models.CharField(max_length=128, verbose_name="Title") + date = models.DateField(verbose_name="Date of Achievement") + url = models.URLField(blank=True, null=True, verbose_name="Related URL") + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + verbose_name="Related User", + blank=True, + null=True, + ) + description = models.TextField(verbose_name="Description") + + def __str__(self): + return self.title + + +class Tag(models.Model): + TAGS = [ + ("GSOC", "Google Summer of Code"), + ("IAS SRFP", "IAS Summer Research Fellowship Program"), + ("SB", "Student Branch Award"), + # TODO: Add more tags + ] + + tag = models.CharField(max_length=32, choices=TAGS, verbose_name="Tag") + achievement = models.ForeignKey( + Achievement, on_delete=models.CASCADE, verbose_name="Achievement" + ) + + +class Publication(models.Model): + title = models.CharField(max_length=256, verbose_name="Title") + date = models.DateField(verbose_name="Publish Date") + url = models.URLField(verbose_name="URL") + authors = models.CharField(max_length=256, verbose_name="Authors") + source = models.CharField(max_length=512, verbose_name="Source") + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + verbose_name="Related User", + blank=True, + null=True, + ) + + def __str__(self): + return self.title diff --git a/corpus/pages/urls.py b/corpus/pages/urls.py index 1d3a5671..d9f06899 100644 --- a/corpus/pages/urls.py +++ b/corpus/pages/urls.py @@ -6,4 +6,5 @@ path("", views.index, name="index"), path("about_us/", views.about_us, name="about_us"), path("sig//", views.sig, name="sig"), + path("achievements/", views.achievements, name="achievements"), ] diff --git a/corpus/pages/views.py b/corpus/pages/views.py index 3995c0a4..435b7257 100644 --- a/corpus/pages/views.py +++ b/corpus/pages/views.py @@ -3,6 +3,9 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import render +from .models import Achievement +from .models import Publication + def index(request): # Get all societies to render on landing page Societies section @@ -43,4 +46,35 @@ def sig(request, sig_name): return render(request, "pages/sig.html", args) def farewell(request): - return render(request, "pages/farewell.html") \ No newline at end of file + return render(request, "pages/farewell.html") + +def achievements(request): + achievements_all = Achievement.objects.order_by("-date") + achievements_year_map = {} + for achievement in achievements_all: + year = achievement.date.year + if year in achievements_year_map: + achievements_year_map[year].append(achievement) + else: + achievements_year_map[year] = [achievement] + + publications_all = Publication.objects.order_by("-date") + publications_year_map = {} + for publication in publications_all: + year = publication.date.year + if year in publications_year_map: + publications_year_map[year].append(publication) + else: + publications_year_map[year] = [publication] + return render( + request, + "pages/achievements.html", + { + "achievements_map": achievements_year_map, + "publications_map": publications_year_map, + }, + ) + + +def farewell(request): + return render(request, "pages/farewell.html") diff --git a/corpus/tailwind.config.js b/corpus/tailwind.config.js index 498c789c..206d4450 100644 --- a/corpus/tailwind.config.js +++ b/corpus/tailwind.config.js @@ -9,7 +9,6 @@ module.exports = { extend: {}, }, plugins: [ - require("@tailwindcss/forms"), require("@tailwindcss/aspect-ratio"), require("@tailwindcss/typography"), require("@tailwindcss/container-queries"), diff --git a/corpus/templates/base.html b/corpus/templates/base.html index 74ef0bdd..c9566d5d 100644 --- a/corpus/templates/base.html +++ b/corpus/templates/base.html @@ -4,7 +4,6 @@ - @@ -72,7 +71,7 @@ - {% block title %} {% endblock %} | Corpus + {% block title %} {% endblock %} | IEEE NITK diff --git a/corpus/templates/pages/achievements.html b/corpus/templates/pages/achievements.html new file mode 100644 index 00000000..515a34c5 --- /dev/null +++ b/corpus/templates/pages/achievements.html @@ -0,0 +1,111 @@ +{% extends 'base.html' %} +{% load static %} + +{% block title %} +Achievements +{% endblock %} + +{% block content %} + +
+
+
+

Achievements

+
+
+ +
+ +
+ {% for year, achievements in achievements_map.items %} +
+
{{ year }}
+
    + {% for achievement in achievements %} +
  • + {% if achievement.url %} + {{ achievement.title }}{{ achievement.date | date:"F j, Y" }} + {% else %} + {{ achievement.title }}{{ achievement.date | date:"F j, Y" }} + {% endif %} + +

    {{ achievement.description }}

    +
  • + {% endfor %} +
+
+ {% empty %} +
+
{% now "Y" %}
+
    +
  • + You forgot to add achievements!{% now "F j, Y" %} +

    You probably forgot to add achievements. Add them using: python manage.py loaddata dev_pages_db.json

    +
  • +
+
+ {% endfor %} +
+ + +
+{% endblock %} + + +{% block script %} + + +{% endblock %} diff --git a/corpus/templates/tailwind.html b/corpus/templates/tailwind.html new file mode 100644 index 00000000..c24c728e --- /dev/null +++ b/corpus/templates/tailwind.html @@ -0,0 +1,13 @@ +Tailwind HTML File + +This file will be used to reference classes that are used indirectly in HTML templates. +For example, we define CSS class names to be used in forms in the Python code. +Tailwind will not know to reference these classes unless we define them in a file that is included in a HTML template. + +This file will never be referenced within Django, so feel free to add any classes that aren't referenced in HTML here. + +

+

+

+

+