diff --git a/src/haps/__init__.py b/src/haps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/haps/admin.py b/src/haps/admin.py new file mode 100644 index 0000000..5f6adbd --- /dev/null +++ b/src/haps/admin.py @@ -0,0 +1,33 @@ +from django.contrib import admin +from .models import EventRegistration, Event + + +@admin.register(Event) +class EventAdmin(admin.ModelAdmin): + search_fields = ["name"] + list_display = [ + "name", + "venue", + "start_time", + "accept_reg", + "show_on_home", + "event_page", + ] + list_filter = ["show_on_home", "accept_reg"] + fields = [ + "name", + "description", + "cover_image", + "venue", + "start_time", + "end_time", + "accept_reg", + "show_on_home", + ] + + +@admin.register(EventRegistration) +class EventRegistrationAdmin(admin.ModelAdmin): + search_fields = ["event", "user"] + list_display = ["user", "event"] + list_filter = ["event__name"] diff --git a/src/haps/apps.py b/src/haps/apps.py new file mode 100644 index 0000000..281a0dc --- /dev/null +++ b/src/haps/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class HapsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "haps" diff --git a/src/haps/migrations/0001_initial.py b/src/haps/migrations/0001_initial.py new file mode 100644 index 0000000..d14ff0c --- /dev/null +++ b/src/haps/migrations/0001_initial.py @@ -0,0 +1,78 @@ +# Generated by Django 4.2.1 on 2023-12-23 19:40 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import utils.images + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Event", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=256)), + ("slug", models.SlugField(unique=True)), + ("description", models.TextField(max_length=4096)), + ( + "cover_image", + models.ImageField( + blank=True, null=True, upload_to=utils.images.upload_image_to + ), + ), + ("venue", models.CharField(max_length=128)), + ("start_time", models.DateField()), + ("end_time", models.DateField(blank=True, null=True)), + ( + "accept_reg", + models.BooleanField(verbose_name="Accepting registrations ?"), + ), + ( + "show_on_home", + models.BooleanField(verbose_name="Show on Home Page ?"), + ), + ], + ), + migrations.CreateModel( + name="EventRegistration", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "event", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="haps.event" + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/src/haps/migrations/__init__.py b/src/haps/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/haps/models.py b/src/haps/models.py new file mode 100644 index 0000000..553b03b --- /dev/null +++ b/src/haps/models.py @@ -0,0 +1,41 @@ +from django.db import models +from django.contrib.auth import get_user_model +from django.utils.html import format_html +from utils.images import upload_image_to +from utils.slugs import generate_unique_slug + +User = get_user_model() + + +class Event(models.Model): + name = models.CharField(max_length=256) + slug = models.SlugField(unique=True, blank=True) + description = models.TextField(max_length=4096) + cover_image = models.ImageField(upload_to=upload_image_to, blank=True, null=True) + venue = models.CharField(max_length=128) + start_time = models.DateField() + end_time = models.DateField(null=True, blank=True) + accept_reg = models.BooleanField(verbose_name="Accepting registrations ?") + show_on_home = models.BooleanField(verbose_name="Show on Home Page ?") + + def __str__(self): + return self.name + str(self.start_time) + + def save(self, *args, **kwargs): + if self.slug == "": + self.slug = generate_unique_slug(self.name, Event) + super().save(args, kwargs) + + def get_absolute_url(self): + return f"/events/e/{self.slug}" + + def event_page(self): + return format_html(f'View Page') + + +class EventRegistration(models.Model): + event = models.ForeignKey(Event, on_delete=models.CASCADE) + user = models.ForeignKey(User, on_delete=models.CASCADE) + + def __str__(self) -> str: + return self.user.__str__() + "%" + self.event.__str__() diff --git a/src/haps/templates/haps/item.html b/src/haps/templates/haps/item.html new file mode 100644 index 0000000..e69de29 diff --git a/src/haps/templates/haps/list.html b/src/haps/templates/haps/list.html new file mode 100644 index 0000000..f2467cf --- /dev/null +++ b/src/haps/templates/haps/list.html @@ -0,0 +1,63 @@ +{% extends "commons.html" %} +{% block title %} Events {% endblock title %} +{%block content %} + + +
+ +{%for hap in haps %} + +
+ + + +
+ +
+ {{hap.name}} +
+
+

+ {{hap.description}} +

+ + +

{{hap.venue}} + +

+

{{hap.start_time}}

+ + Read more + + +
+
+ + +{% endfor %} + + + +
+{% endblock %} diff --git a/src/haps/tests.py b/src/haps/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/src/haps/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/src/haps/urls.py b/src/haps/urls.py new file mode 100644 index 0000000..b71b98a --- /dev/null +++ b/src/haps/urls.py @@ -0,0 +1,10 @@ +from django.urls import path + +from . import views + +app_name = "haps" + +urlpatterns = [ + path("", views.haps_list, name="events"), + path("e/", views.haps_item, name="event_item"), +] diff --git a/src/haps/views.py b/src/haps/views.py new file mode 100644 index 0000000..743132a --- /dev/null +++ b/src/haps/views.py @@ -0,0 +1,19 @@ +from django.shortcuts import render +from django.http import HttpRequest, Http404 +from .models import Event +import logging + +log = logging.getLogger(__name__) + + +def haps_list(request: HttpRequest): + haps = Event.objects.all() + context = {"haps": haps} + return render(request, "haps/list.html", context=context) + + +def haps_item(request: HttpRequest, slug: str): + event = Event.objects.get(slug=slug) + context = {"event": event} + + return render(request, "haps/item.html", context=context) diff --git a/src/static/styles.css b/src/static/styles.css index 71a2095..e8142e0 100644 --- a/src/static/styles.css +++ b/src/static/styles.css @@ -1075,14 +1075,6 @@ input:checked + .toggle-bg { right: 0px; } -.right-2 { - right: 0.5rem; -} - -.right-2\.5 { - right: 0.625rem; -} - .top-0 { top: 0px; } @@ -1091,10 +1083,6 @@ input:checked + .toggle-bg { top: 50%; } -.top-3 { - top: 0.75rem; -} - .z-10 { z-index: 10; } @@ -1208,10 +1196,6 @@ input:checked + .toggle-bg { margin-left: 1rem; } -.ml-auto { - margin-left: auto; -} - .mr-2 { margin-right: 0.5rem; } @@ -1220,8 +1204,13 @@ input:checked + .toggle-bg { margin-right: 0.75rem; } -.mr-auto { - margin-right: auto; +.mr-4 { + margin-right: 1rem; +} + +.ms-2 { + -webkit-margin-start: 0.5rem; + margin-inline-start: 0.5rem; } .mt-12 { @@ -1240,10 +1229,6 @@ input:checked + .toggle-bg { margin-top: 1.5rem; } -.mt-8 { - margin-top: 2rem; -} - .mt-auto { margin-top: auto; } @@ -1288,10 +1273,18 @@ input:checked + .toggle-bg { height: 3rem; } +.h-16 { + height: 4rem; +} + .h-3 { height: 0.75rem; } +.h-3\.5 { + height: 0.875rem; +} + .h-4 { height: 1rem; } @@ -1312,10 +1305,6 @@ input:checked + .toggle-bg { height: 20rem; } -.h-\[calc\(100\%-1rem\)\] { - height: calc(100% - 1rem); -} - .h-auto { height: auto; } @@ -1328,8 +1317,8 @@ input:checked + .toggle-bg { height: 1px; } -.max-h-full { - max-height: 100%; +.h-screen { + height: 100vh; } .min-h-screen { @@ -1348,10 +1337,18 @@ input:checked + .toggle-bg { width: 3rem; } +.w-16 { + width: 4rem; +} + .w-3 { width: 0.75rem; } +.w-3\.5 { + width: 0.875rem; +} + .w-4 { width: 1rem; } @@ -1396,6 +1393,10 @@ input:checked + .toggle-bg { max-width: 32rem; } +.max-w-md { + max-width: 28rem; +} + .max-w-screen-md { max-width: 768px; } @@ -1408,6 +1409,10 @@ input:checked + .toggle-bg { max-width: 1280px; } +.max-w-sm { + max-width: 24rem; +} + .flex-1 { flex: 1 1 0%; } @@ -1528,6 +1533,10 @@ input:checked + .toggle-bg { flex-wrap: wrap; } +.content-center { + align-content: center; +} + .items-start { align-items: flex-start; } @@ -1564,10 +1573,6 @@ input:checked + .toggle-bg { justify-content: space-around; } -.gap-16 { - gap: 4rem; -} - .gap-4 { gap: 1rem; } @@ -1606,22 +1611,12 @@ input:checked + .toggle-bg { margin-bottom: calc(1rem * var(--tw-space-y-reverse)); } -.space-y-6 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); -} - .space-y-8 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(2rem * var(--tw-space-y-reverse)); } -.place-self-center { - place-self: center; -} - .self-center { align-self: center; } @@ -1630,18 +1625,6 @@ input:checked + .toggle-bg { overflow: hidden; } -.overflow-y-auto { - overflow-y: auto; -} - -.overflow-x-hidden { - overflow-x: hidden; -} - -.overflow-x-scroll { - overflow-x: scroll; -} - .whitespace-nowrap { white-space: nowrap; } @@ -1676,6 +1659,11 @@ input:checked + .toggle-bg { border-bottom-right-radius: 0.5rem; } +.rounded-t-lg { + border-top-left-radius: 0.5rem; + border-top-right-radius: 0.5rem; +} + .border { border-width: 1px; } @@ -1732,6 +1720,11 @@ input:checked + .toggle-bg { background-color: rgb(225 239 254 / var(--tw-bg-opacity)); } +.bg-blue-500 { + --tw-bg-opacity: 1; + background-color: rgb(63 131 248 / var(--tw-bg-opacity)); +} + .bg-blue-700 { --tw-bg-opacity: 1; background-color: rgb(26 86 219 / var(--tw-bg-opacity)); @@ -1807,10 +1800,6 @@ input:checked + .toggle-bg { background-color: rgb(253 242 242 / var(--tw-bg-opacity)); } -.bg-transparent { - background-color: transparent; -} - .bg-white { --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); @@ -1832,10 +1821,6 @@ input:checked + .toggle-bg { padding: 0.25rem; } -.p-1\.5 { - padding: 0.375rem; -} - .p-2 { padding: 0.5rem; } @@ -1852,6 +1837,10 @@ input:checked + .toggle-bg { padding: 1rem; } +.p-5 { + padding: 1.25rem; +} + .p-6 { padding: 1.5rem; } @@ -1875,6 +1864,11 @@ input:checked + .toggle-bg { padding-right: 0.625rem; } +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + .px-4 { padding-left: 1rem; padding-right: 1rem; @@ -2074,8 +2068,8 @@ input:checked + .toggle-bg { line-height: 2.25rem; } -.leading-none { - line-height: 1; +.leading-tight { + line-height: 1.25; } .tracking-tight { @@ -2092,11 +2086,6 @@ input:checked + .toggle-bg { color: rgb(28 100 242 / var(--tw-text-opacity)); } -.text-gray-400 { - --tw-text-opacity: 1; - color: rgb(156 163 175 / var(--tw-text-opacity)); -} - .text-gray-500 { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); @@ -2270,6 +2259,11 @@ input:checked + .toggle-bg { border-color: rgb(209 213 219 / var(--tw-border-opacity)); } +.hover\:bg-blue-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(28 100 242 / var(--tw-bg-opacity)); +} + .hover\:bg-blue-800:hover { --tw-bg-opacity: 1; background-color: rgb(30 66 159 / var(--tw-bg-opacity)); @@ -2280,11 +2274,6 @@ input:checked + .toggle-bg { background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } -.hover\:bg-gray-200:hover { - --tw-bg-opacity: 1; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)); -} - .hover\:bg-primary-700:hover { --tw-bg-opacity: 1; background-color: rgb(180 83 9 / var(--tw-bg-opacity)); @@ -2356,11 +2345,6 @@ input:checked + .toggle-bg { --tw-ring-color: rgb(164 202 254 / var(--tw-ring-opacity)); } -.focus\:ring-gray-100:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(243 244 246 / var(--tw-ring-opacity)); -} - .focus\:ring-gray-200:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(229 231 235 / var(--tw-ring-opacity)); @@ -2406,6 +2390,15 @@ input:checked + .toggle-bg { --tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity)); } +:is([dir="rtl"] .rtl\:rotate-180) { + --tw-rotate: 180deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +:is(.dark .dark\:border) { + border-width: 1px; +} + :is(.dark .dark\:border-blue-500) { --tw-border-opacity: 1; border-color: rgb(63 131 248 / var(--tw-border-opacity)); @@ -2537,6 +2530,10 @@ input:checked + .toggle-bg { color: rgb(156 163 175 / var(--tw-placeholder-opacity)); } +:is(.dark .dark\:ring-offset-gray-800) { + --tw-ring-offset-color: #1F2937; +} + :is(.dark .dark\:hover\:bg-blue-700:hover) { --tw-bg-opacity: 1; background-color: rgb(26 86 219 / var(--tw-bg-opacity)); @@ -2587,14 +2584,14 @@ input:checked + .toggle-bg { --tw-ring-color: rgb(75 85 99 / var(--tw-ring-opacity)); } -:is(.dark .dark\:focus\:ring-gray-800:focus) { +:is(.dark .dark\:focus\:ring-primary-500:focus) { --tw-ring-opacity: 1; - --tw-ring-color: rgb(31 41 55 / var(--tw-ring-opacity)); + --tw-ring-color: rgb(245 158 11 / var(--tw-ring-opacity)); } -:is(.dark .dark\:focus\:ring-primary-500:focus) { +:is(.dark .dark\:focus\:ring-primary-600:focus) { --tw-ring-opacity: 1; - --tw-ring-color: rgb(245 158 11 / var(--tw-ring-opacity)); + --tw-ring-color: rgb(217 119 6 / var(--tw-ring-opacity)); } :is(.dark .dark\:focus\:ring-primary-800:focus) { @@ -2674,6 +2671,10 @@ input:checked + .toggle-bg { width: 1.5rem; } + .sm\:max-w-md { + max-width: 28rem; + } + .sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } @@ -2722,6 +2723,10 @@ input:checked + .toggle-bg { padding: 1.5rem; } + .sm\:p-8 { + padding: 2rem; + } + .sm\:px-12 { padding-left: 3rem; padding-right: 3rem; @@ -2746,6 +2751,11 @@ input:checked + .toggle-bg { line-height: 1.75rem; } + .sm\:text-sm { + font-size: 0.875rem; + line-height: 1.25rem; + } + .sm\:text-xl { font-size: 1.25rem; line-height: 1.75rem; @@ -2753,10 +2763,6 @@ input:checked + .toggle-bg { } @media (min-width: 768px) { - .md\:inset-0 { - inset: 0px; - } - .md\:col-span-3 { grid-column: span 3 / span 3; } @@ -2793,6 +2799,10 @@ input:checked + .toggle-bg { height: 28rem; } + .md\:h-screen { + height: 100vh; + } + .md\:w-auto { width: auto; } @@ -2833,6 +2843,12 @@ input:checked + .toggle-bg { margin-bottom: calc(0px * var(--tw-space-y-reverse)); } + .md\:space-y-6 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1.5rem * var(--tw-space-y-reverse)); + } + .md\:border-0 { border-width: 0px; } @@ -2859,6 +2875,11 @@ input:checked + .toggle-bg { padding-right: 3rem; } + .md\:text-2xl { + font-size: 1.5rem; + line-height: 2rem; + } + .md\:text-4xl { font-size: 2.25rem; line-height: 2.5rem; @@ -2869,11 +2890,6 @@ input:checked + .toggle-bg { line-height: 1; } - .md\:text-lg { - font-size: 1.125rem; - line-height: 1.75rem; - } - .md\:text-primary-700 { --tw-text-opacity: 1; color: rgb(180 83 9 / var(--tw-text-opacity)); @@ -2909,14 +2925,6 @@ input:checked + .toggle-bg { } @media (min-width: 1024px) { - .lg\:col-span-5 { - grid-column: span 5 / span 5; - } - - .lg\:col-span-7 { - grid-column: span 7 / span 7; - } - .lg\:my-8 { margin-top: 2rem; margin-bottom: 2rem; @@ -2930,22 +2938,6 @@ input:checked + .toggle-bg { margin-bottom: 4rem; } - .lg\:mb-8 { - margin-bottom: 2rem; - } - - .lg\:mt-0 { - margin-top: 0px; - } - - .lg\:mt-10 { - margin-top: 2.5rem; - } - - .lg\:flex { - display: flex; - } - .lg\:grid { display: grid; } @@ -2958,14 +2950,6 @@ input:checked + .toggle-bg { width: 3rem; } - .lg\:grid-cols-12 { - grid-template-columns: repeat(12, minmax(0, 1fr)); - } - - .lg\:grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } @@ -2974,10 +2958,6 @@ input:checked + .toggle-bg { grid-template-columns: repeat(5, minmax(0, 1fr)); } - .lg\:gap-8 { - gap: 2rem; - } - .lg\:space-y-0 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); @@ -2989,9 +2969,9 @@ input:checked + .toggle-bg { padding-right: 1.5rem; } - .lg\:px-8 { - padding-left: 2rem; - padding-right: 2rem; + .lg\:py-0 { + padding-top: 0px; + padding-bottom: 0px; } .lg\:py-16 { @@ -3003,28 +2983,18 @@ input:checked + .toggle-bg { font-size: 8rem; line-height: 1; } - - .lg\:text-xl { - font-size: 1.25rem; - line-height: 1.75rem; - } } @media (min-width: 1280px) { - .xl\:gap-0 { - gap: 0px; - } - .xl\:gap-10 { gap: 2.5rem; } - .xl\:p-8 { - padding: 2rem; + .xl\:p-0 { + padding: 0px; } - .xl\:text-6xl { - font-size: 3.75rem; - line-height: 1; + .xl\:p-8 { + padding: 2rem; } } diff --git a/src/temple_web/settings.py b/src/temple_web/settings.py index d94fb2a..9e09586 100644 --- a/src/temple_web/settings.py +++ b/src/temple_web/settings.py @@ -76,6 +76,7 @@ "accounts.apps.AccountsConfig", "tester.apps.TesterConfig", "users.apps.UsersConfig", + "haps", # more third party apps # recommended to be placed at last "django_cleanup.apps.CleanupConfig", @@ -150,7 +151,7 @@ LANGUAGE_CODE = "en-us" -# TIME_ZONE = "Asia/Calcutta"~~ +TIME_ZONE = "Asia/Kolkata" USE_I18N = True diff --git a/src/temple_web/urls.py b/src/temple_web/urls.py index 698ad3c..fc1ea78 100644 --- a/src/temple_web/urls.py +++ b/src/temple_web/urls.py @@ -35,7 +35,8 @@ # path("online-puja/", include("online_puja.urls")), path("accounts/", include("accounts.urls")), path("tester/", include("tester.urls")), - path("users/",include("users.urls") ), + path("users/", include("users.urls")), + path("events/", include("haps.urls")), # path("404/", views.page_not_found_view, name="404"), path("admin/", admin.site.urls), ] diff --git a/src/users/migrations/0002_alter_templewebuser_email.py b/src/users/migrations/0002_alter_templewebuser_email.py new file mode 100644 index 0000000..ef2e005 --- /dev/null +++ b/src/users/migrations/0002_alter_templewebuser_email.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.1 on 2023-12-23 18:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("users", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="templewebuser", + name="email", + field=models.EmailField( + max_length=255, unique=True, verbose_name="email address" + ), + ), + ] diff --git a/src/users/urls.py b/src/users/urls.py index 33fe802..0afe719 100644 --- a/src/users/urls.py +++ b/src/users/urls.py @@ -11,3 +11,4 @@ path("login/", views.login_view, name="login"), path("logout", views.logout_view, name="logout"), ] + diff --git a/src/utils/slugs.py b/src/utils/slugs.py new file mode 100644 index 0000000..5bb1c76 --- /dev/null +++ b/src/utils/slugs.py @@ -0,0 +1,14 @@ +from django.db.models import Model + +from django.utils.text import slugify + +from uuid import uuid4 + + +def generate_unique_slug(title: str, forModel: Model) -> str: + """The slug field of the model must be called 'slug'""" + slug = slugify(title) + while forModel.objects.filter(slug=slug).exists(): + slug = slugify(title) + "-" + str(uuid4())[0:4] + + return slug