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 %}
+
+
+
+
+{% 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