Compare commits

...

9 Commits

Author SHA1 Message Date
bfc2950a1d postgres 2025-04-06 15:28:56 -04:00
8c9bc213b0 merge 2025-04-06 13:47:21 -04:00
e288cd3f31 image update 2025-04-06 13:39:48 -04:00
10db56805f Merge pull request 'db-update' (#1) from add-mad-to-db into api-first
Reviewed-on: #1
Reviewed-by: dominic <me@domdit.com>
2025-04-03 20:00:12 -04:00
794bf82a1c db-update 2025-04-03 20:01:19 -04:00
330b22daf7 event guest 2025-03-30 22:29:59 -04:00
907728fdfb adding event_comment and avail contract 2025-03-30 22:20:59 -04:00
23ffa71032 add gitignore 2025-03-30 22:18:31 -04:00
3683f943a6 api 2025-03-28 21:45:27 -04:00
53 changed files with 906 additions and 105 deletions

59
.gitignore vendored Normal file
View File

@ -0,0 +1,59 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*.pyc
# C extensions
*.so
# Distribution / packaging
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
# Sphinx documentation
docs/_build/
*__pycache__/*
*.pyc
run.sh
venv/
*.bak
scratch*

0
api/__init__.py Normal file
View File

3
api/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
api/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'api'

View File

3
api/models.py Normal file
View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

19
api/serializers/event.py Normal file
View File

@ -0,0 +1,19 @@
from rest_framework import serializers
from api.serializers.event_comment import EventCommentSerializer
from api.services.generate_availability_contract import AvailabilityContractGenerator
from web.models import Event
class EventSerializer(serializers.ModelSerializer):
comments = EventCommentSerializer(many=True)
class Meta:
model = Event
fields = '__all__'
def to_representation(self, instance):
data = super(EventSerializer, self).to_representation(instance)
data['availability_contract'] = AvailabilityContractGenerator(data['id']).main()
return data

View File

@ -0,0 +1,10 @@
from rest_framework import serializers
from web.models import EventComment
class EventCommentSerializer(serializers.ModelSerializer):
class Meta:
model = EventComment
fields = '__all__'

View File

@ -0,0 +1,10 @@
from rest_framework import serializers
from web.models import EventDivision
class EventDivisionSerializer(serializers.ModelSerializer):
class Meta:
model = EventDivision
fields = '__all__'

View File

@ -0,0 +1,51 @@
import copy
from datetime import date, timedelta, time
from django.shortcuts import get_object_or_404
from web.models.event import Event
DIVISION_MAP = {
1: [time(i).strftime('%I %p') for i in range(24)],
2: ["Morning", "Afternoon", "Night"]
}
class AvailabilityContractGenerator:
def __init__(self, event_id):
self.event_id = event_id
self.event = get_object_or_404(Event, pk=event_id)
self.availability_contract = {
'unavailable': False,
'dates': {}
}
def main(self):
dates = self.generate_date_list()
self.generate_availability_contract(dates)
return self.availability_contract
def generate_date_list(self):
start_date = copy.deepcopy(self.event.start_date)
delta = timedelta(days=1)
dates = []
while start_date <= self.event.end_date:
dates.append(start_date.isoformat())
start_date += delta
return dates
def generate_availability_contract(self, dates):
for event_date in dates:
self.availability_contract['dates'][event_date] = {'divisions': []}
for division in DIVISION_MAP.get(self.event.division.id):
self.availability_contract['dates'][event_date]['divisions'].append(
{
"name": division,
"status": None
}
)

40
api/views/availability.py Normal file
View File

@ -0,0 +1,40 @@
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from api.serializers.event import EventSerializer
from common.build_response import build_response
from web.models import Event, EventComment
class AvailabilityView(APIView):
def post(self, request, event_id):
try:
event = get_object_or_404(Event, pk=event_id)
except Exception:
return build_response(404, message='Unable to find related event!')
data = request.POST
try:
user = User.objects.filter(email=data.get('created_by')).first()
except Exception:
return build_response(500, message="Could not find user!")
try:
new_comment = EventComment(
event=event,
content=data.get('content'),
submitted_by=user
)
new_comment.save()
except Exception:
return build_response(500, message='Unable to create new comment!')
try:
event_serializer = EventSerializer(event)
except Exception:
return build_response(422)
return build_response(data=event_serializer.data)

112
api/views/event.py Normal file
View File

@ -0,0 +1,112 @@
from rest_framework.views import APIView
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from api.serializers.event import EventSerializer
from common.build_response import build_response
from web.models import Event, EventDivision
class EventView(APIView):
def get(self, request, event_id):
try:
event = get_object_or_404(Event, pk=event_id)
except Exception:
return build_response(404)
try:
event_serializer = EventSerializer(event)
except Exception:
return build_response(422)
return build_response(data=event_serializer.data)
def post(self, request):
data = request.POST
try:
division = get_object_or_404(EventDivision, pk=data.get('division'))
except Exception:
return build_response(500, message="Unable to retrieve division info")
try:
user = User.objects.filter(email=data.get('created_by')).first()
except Exception:
return build_response(500, message="Could not find user!")
try:
new_event = Event(
name=data.get("name"),
description=data.get("description"),
division=division,
start_date=data.get('start_date'),
end_date=data.get('end_date'),
submit_by_date=data.get('submit_by_date'),
chosen_date=None,
created_by=user
)
new_event.save()
except Exception:
return build_response(500, message="Unable to create new event!")
try:
event_serializer = EventSerializer(new_event)
except Exception:
return build_response(422)
return build_response(200, data=event_serializer.data)
def put(self, request, event_id):
try:
event = get_object_or_404(Event, pk=event_id)
except Exception:
return build_response(404)
data = request.POST
try:
division = get_object_or_404(EventDivision, pk=data.get('division'))
except Exception:
return build_response(500, message="Unable to retrieve division info")
try:
event.name = data.get('name', event.name)
event.description = data.get('description', event.description)
event.division = None
event.start_date = data.get('start_date', event.start_date)
event.end_date = data.get('end_date', event.end_date)
event.submit_by_date = data.get('submit_by_date', event.submit_by_date)
event.chosen_date = data.get('chosen_date', event.chosen_date)
event.created_by = data.get('created_by', event.created_by)
event.save()
except Exception:
build_response(500, message='Unable to update event')
try:
event_serializer = EventSerializer(event)
except Exception:
return build_response(422)
return build_response(200, data=event_serializer.data)
def delete(self, request, event_id):
try:
event = get_object_or_404(Event, pk=event_id)
except Exception:
return build_response(404)
try:
event.active = False
event.save()
except Exception:
return build_response(500, message="Unable to deactivate event")
try:
event_serializer = EventSerializer(event)
except Exception:
return build_response(422)
return build_response(204, data=event_serializer)

View File

@ -0,0 +1,90 @@
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from api.serializers.event import EventSerializer
from common.build_response import build_response
from web.models import Event, EventComment
class EventCommentView(APIView):
def post(self, request, event_id):
try:
event = get_object_or_404(Event, pk=event_id)
except Exception:
return build_response(404, message='Unable to find related event!')
data = request.POST
try:
user = User.objects.filter(email=data.get('created_by')).first()
except Exception:
return build_response(500, message="Could not find user!")
try:
new_comment = EventComment(
event=event,
content=data.get('content'),
submitted_by=user
)
new_comment.save()
except Exception:
return build_response(500, message='Unable to create new comment!')
try:
event_serializer = EventSerializer(event)
except Exception:
return build_response(422)
return build_response(data=event_serializer.data)
def put(self, request, event_id, comment_id):
try:
event = get_object_or_404(Event, pk=event_id)
except Exception:
return build_response(404, message='Unable to find related event!')
data = request.POST
try:
comment = get_object_or_404(EventComment, pk=comment_id)
except Exception:
return build_response(404, message='Unable to find comment!')
try:
comment.content = data.get('content', comment.content)
comment.save()
except Exception:
return build_response(500, message='Unable to edit comment')
try:
event_serializer = EventSerializer(event)
except Exception:
return build_response(422)
return build_response(data=event_serializer.data)
def delete(request, event_id, comment_id):
try:
event = get_object_or_404(Event, pk=event_id)
except Exception:
return build_response(404, message='Unable to find related event!')
try:
comment = get_object_or_404(EventComment, pk=comment_id)
except Exception:
return build_response(404, message='Unable to find comment!')
try:
comment.active = False
comment.save()
except Exception:
return build_response(500, message='Unable to delete comment!')
try:
event_serializer = EventSerializer(event)
except Exception:
return build_response(422)
return build_response(data=event_serializer.data)

View File

@ -0,0 +1,24 @@
from rest_framework.views import APIView
from api.serializers.event_division import EventDivisionSerializer
from common.build_response import build_response
from web.models import EventDivision
class EventDivisionView(APIView):
def get(self, request):
try:
event_divisions = EventDivision.objects.all()
except Exception:
return build_response(404)
try:
parsed_event_divisions = []
for event_division in event_divisions:
parsed_event_divisions.append(
EventDivisionSerializer(event_division).data
)
except Exception:
return build_response(422)
return build_response(data=parsed_event_divisions)

30
common/build_response.py Normal file
View File

@ -0,0 +1,30 @@
import sys
import traceback
from rest_framework.response import Response
status_code_message_map = {
204: 'Successfully deleted entity.',
403: 'User does not have access to this entity.',
404: 'No entity matches the given query',
500: 'Something went wrong!'
}
def build_response(status_code=200, data=None, message=None):
response = Response()
response.status_code = status_code
if response.status_code == 200:
response.data = data
else:
response.data = {}
response.data['message'] = message if message else status_code_message_map.get(status_code)
exc_info = sys.exc_info()
exception_info = ''.join(traceback.format_exception(*exc_info))
response.data['details'] = exception_info
return response

Binary file not shown.

View File

@ -35,13 +35,15 @@ CSRF_TRUSTED_ORIGINS = ['https://korabo.domdit.com']
INSTALLED_APPS = [
'web',
'api',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap5'
'bootstrap5',
'rest_framework'
]
MIDDLEWARE = [
@ -80,8 +82,12 @@ WSGI_APPLICATION = 'korabo.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASS'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
}
}
@ -129,3 +135,6 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"

View File

@ -1,28 +1,26 @@
"""
URL configuration for korabo project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from api.views.event import EventView
from api.views.event_division import EventDivisionView
from api.views.event_comment import EventCommentView
from web import views
urlpatterns = [
path("accounts/", include("django.contrib.auth.urls")),
path('admin/', admin.site.urls),
path('api/event/', EventView.as_view(), name='event'),
path('api/event/<int:event_id>', EventView.as_view(), name='event'),
path('api/event/<int:event_id>/comment/', EventCommentView.as_view(), name='event'),
path('api/event/<int:event_id>/comment/<int:comment_id>', EventCommentView.as_view(), name='event'),
path('api/event_division/', EventDivisionView.as_view(), name='event_division'),
path("", views.index, name="index"),
path("accounts/", include("django.contrib.auth.urls")),
path("event/<int:event_id>", views.event, name="event"),
path('change_password/', views.change_password, name='change_password'),
path('password_change_done/', views.password_change_done, name='password_change_done')
]
if settings.DEBUG: # new
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

21
requests/event_post.py Normal file
View File

@ -0,0 +1,21 @@
import requests
url = 'http://127.0.0.1:8000/api/event/'
data = {
'name': 'this is a test',
'description': 'Some long ass description',
'start_date': '2025-03-28T23:30:00Z',
'end_date': '2025-04-04T23:30:00Z',
'submit_by_date': '2025-04-03T23:30:00Z',
'created_by': 'me@domdit.com',
'division': 1
}
resp = requests.post(url, data=data)
print(resp.status_code)
print('------------')
print(resp.json())

20
requests/event_put.py Normal file
View File

@ -0,0 +1,20 @@
import requests
url = "http://127.0.0.1:8000/api/event/3"
data = {
"name": "this is a test and a change",
# 'description': 'Some long ass description',
# 'start_date': '2025-03-28T23:30:00Z',
"end_date": "2025-04-07T23:30:00Z",
# 'submit_by_date': '2025-04-03T23:30:00Z',
# 'created_by': 'me@domdit.com',
"division": 2,
}
resp = requests.put(url, data=data)
print(resp.status_code)
print("------------")
print(resp.json())

View File

@ -1,8 +1,15 @@
asgiref==3.8.1
beautifulsoup4==4.12.3
certifi==2025.1.31
charset-normalizer==3.4.1
Django==4.2.16
django-bootstrap-v5==1.0.11
djangorestframework==3.15.2
gunicorn==23.0.0
idna==3.10
packaging==24.1
requests==2.32.3
soupsieve==2.6
sqlparse==0.5.1
urllib3==2.3.0
pillow==11.1.0

Binary file not shown.

View File

@ -1,6 +1,24 @@
from django.contrib import admin
from web.models import Event, EventAdmin, Availability
from web.models import (
Event,
EventAdmin,
Availability,
EventComment,
EventCommentReaction,
EventCommentReactionAdmin,
EventDivision,
EventDivisionAdmin,
SharedEvent,
SharedEventAdmin,
EventGuest,
EventGuestAdmin
)
admin.site.register(Event, EventAdmin)
admin.site.register(Availability)
admin.site.register(EventComment)
admin.site.register(EventCommentReaction, EventCommentReactionAdmin)
admin.site.register(EventDivision, EventDivisionAdmin)
admin.site.register(SharedEvent, SharedEventAdmin)
admin.site.register(EventGuest, EventGuestAdmin)

View File

@ -1,7 +1,8 @@
# Generated by Django 5.1.2 on 2024-10-22 20:31
# Generated by Django 4.2.16 on 2025-03-29 00:40
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
@ -9,6 +10,7 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
@ -20,14 +22,82 @@ class Migration(migrations.Migration):
('active', models.BooleanField(default=True)),
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.TextField()),
('description', models.TextField()),
('start_date', models.DateTimeField()),
('end_date', models.DateTimeField()),
('submit_by_date', models.DateTimeField()),
('chosen_date', models.DateTimeField()),
('participants', models.IntegerField()),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'events',
},
),
migrations.CreateModel(
name='EventComment',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, null=True)),
('updated_at', models.DateTimeField(auto_now=True, null=True)),
('active', models.BooleanField(default=True)),
('id', models.AutoField(primary_key=True, serialize=False)),
('content', models.TextField()),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.event')),
('submitted_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'events_comments',
},
),
migrations.CreateModel(
name='EventDivision',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, null=True)),
('updated_at', models.DateTimeField(auto_now=True, null=True)),
('active', models.BooleanField(default=True)),
('id', models.AutoField(primary_key=True, serialize=False)),
('name', models.CharField(blank=True, max_length=255, null=True)),
('description', models.TextField(blank=True, null=True)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='SharedEvent',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, null=True)),
('updated_at', models.DateTimeField(auto_now=True, null=True)),
('active', models.BooleanField(default=True)),
('id', models.AutoField(primary_key=True, serialize=False)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.event')),
('shared_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shared_by', to=settings.AUTH_USER_MODEL)),
('shared_to', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shared_to', to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'shared_event',
},
),
migrations.CreateModel(
name='EventCommentReaction',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, null=True)),
('updated_at', models.DateTimeField(auto_now=True, null=True)),
('active', models.BooleanField(default=True)),
('id', models.AutoField(primary_key=True, serialize=False)),
('reaction', models.CharField(blank=True, default=None, max_length=8)),
('event_comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.eventcomment')),
('submitted_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'event_comment_reactions',
},
),
migrations.AddField(
model_name='event',
name='division',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.eventdivision'),
),
migrations.CreateModel(
name='Availability',
fields=[
@ -35,12 +105,12 @@ class Migration(migrations.Migration):
('updated_at', models.DateTimeField(auto_now=True, null=True)),
('active', models.BooleanField(default=True)),
('id', models.AutoField(primary_key=True, serialize=False)),
('user', models.TextField()),
('time_table', models.JSONField()),
('event_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.event')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'availabilities',
'db_table': 'availability',
},
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.16 on 2024-10-24 17:59
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('web', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='availability',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.16 on 2025-03-29 01:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='event',
name='chosen_date',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='event',
name='participants',
field=models.IntegerField(default=1),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.16 on 2025-03-29 01:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0002_alter_event_chosen_date_alter_event_participants'),
]
operations = [
migrations.AlterField(
model_name='event',
name='participants',
field=models.IntegerField(blank=True, default=1),
),
]

View File

@ -0,0 +1,38 @@
# Generated by Django 4.2.16 on 2025-03-31 02:28
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web', '0003_alter_event_participants'),
]
operations = [
migrations.RemoveField(
model_name='event',
name='participants',
),
migrations.AlterField(
model_name='eventcomment',
name='event',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='web.event'),
),
migrations.CreateModel(
name='EventGuest',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, null=True)),
('updated_at', models.DateTimeField(auto_now=True, null=True)),
('active', models.BooleanField(default=True)),
('id', models.AutoField(primary_key=True, serialize=False)),
('guest_email', models.TextField()),
('guest_hash', models.TextField()),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.event')),
],
options={
'db_table': 'event_guests',
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.16 on 2025-04-06 01:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0004_remove_event_participants_alter_eventcomment_event_and_more'),
]
operations = [
migrations.AddField(
model_name='event',
name='cover_image',
field=models.ImageField(blank=True, default=None, null=True, upload_to='event_cover_images/'),
),
]

View File

@ -1,38 +0,0 @@
from django.contrib import admin
from django.db import models
from django.contrib.auth.models import User
class BaseModel(models.Model):
created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
updated_at = models.DateTimeField(blank=True, null=True, auto_now=True)
active = models.BooleanField(default=True)
class Meta:
abstract = True
class Event(BaseModel):
id = models.AutoField(primary_key=True)
name = models.TextField(blank=False, null=False)
start_date = models.DateTimeField(blank=False, null=False)
end_date = models.DateTimeField(blank=False, null=False)
participants = models.IntegerField(blank=False)
class Meta:
db_table = 'events'
class EventAdmin(admin.ModelAdmin):
list_display = ('name', 'start_date', 'end_date', 'active')
class Availability(BaseModel):
id = models.AutoField(primary_key=True)
event_id = models.ForeignKey(Event, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
time_table = models.JSONField()
class Meta:
db_table = 'availabilities'

7
web/models/__init__.py Normal file
View File

@ -0,0 +1,7 @@
from .availability import Availability
from .event import Event, EventAdmin
from .event_comment import EventComment, EventCommentAdmin
from .event_comment_reaction import EventCommentReaction, EventCommentReactionAdmin
from .event_division import EventDivision, EventDivisionAdmin
from .shared_event import SharedEvent, SharedEventAdmin
from .event_guest import EventGuest, EventGuestAdmin

View File

@ -0,0 +1,15 @@
from django.db import models
from django.contrib.auth.models import User
from web.models.base import BaseModel
from web.models.event import Event
class Availability(BaseModel):
id = models.AutoField(primary_key=True)
event_id = models.ForeignKey(Event, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
time_table = models.JSONField()
class Meta:
db_table = 'availability'

10
web/models/base.py Normal file
View File

@ -0,0 +1,10 @@
from django.db import models
class BaseModel(models.Model):
created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
updated_at = models.DateTimeField(blank=True, null=True, auto_now=True)
active = models.BooleanField(default=True)
class Meta:
abstract = True

26
web/models/event.py Normal file
View File

@ -0,0 +1,26 @@
from django.contrib import admin
from django.contrib.auth.models import User
from django.db import models
from web.models.base import BaseModel
from web.models.event_division import EventDivision
class Event(BaseModel):
id = models.AutoField(primary_key=True)
name = models.TextField(blank=False, null=False)
description = models.TextField(blank=False, null=False)
cover_image = models.ImageField(blank=True, null=True, default=None, upload_to='event_cover_images/')
division = models.ForeignKey(EventDivision, on_delete=models.CASCADE)
start_date = models.DateTimeField(blank=False, null=False)
end_date = models.DateTimeField(blank=False, null=False)
submit_by_date = models.DateTimeField(blank=False, null=False)
chosen_date = models.DateTimeField(blank=True, null=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
db_table = 'events'
class EventAdmin(admin.ModelAdmin):
list_display = ('name', 'start_date', 'end_date', 'active', 'created_by')

View File

@ -0,0 +1,20 @@
from django.contrib import admin
from django.contrib.auth.models import User
from django.db import models
from web.models.base import BaseModel
from web.models.event import Event
class EventComment(BaseModel):
id = models.AutoField(primary_key=True)
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='comments')
content = models.TextField(blank=False, null=False)
submitted_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
db_table = 'events_comments'
class EventCommentAdmin(admin.ModelAdmin):
list_display = ('event', 'content', 'submitted_by')

View File

@ -0,0 +1,20 @@
from django.contrib import admin
from django.contrib.auth.models import User
from django.db import models
from web.models.base import BaseModel
from web.models.event_comment import EventComment
class EventCommentReaction(BaseModel):
id = models.AutoField(primary_key=True)
reaction = models.CharField(default=None, blank=True, max_length=8)
event_comment = models.ForeignKey(EventComment, on_delete=models.CASCADE)
submitted_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
db_table = 'event_comment_reactions'
class EventCommentReactionAdmin(admin.ModelAdmin):
list_display = ('event_comment', 'reaction', 'submitted_by')

View File

@ -0,0 +1,14 @@
from django.contrib import admin
from django.db import models
from web.models.base import BaseModel
class EventDivision(BaseModel):
id = models.AutoField(primary_key=True)
name = models.CharField(blank=True, null=True, max_length=255)
description = models.TextField(blank=True, null=True)
class EventDivisionAdmin(admin.ModelAdmin):
list_display = ('name', )

20
web/models/event_guest.py Normal file
View File

@ -0,0 +1,20 @@
from django.contrib import admin
from django.contrib.auth.models import User
from django.db import models
from web.models.base import BaseModel
from web.models.event import Event
class EventGuest(BaseModel):
id = models.AutoField(primary_key=True)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
guest_email = models.TextField(blank=False, null=False)
guest_hash = models.TextField(blank=False, null=False)
class Meta:
db_table = 'event_guests'
class EventGuestAdmin(admin.ModelAdmin):
list_display = ('event', 'guest_email', 'guest_hash')

View File

@ -0,0 +1,20 @@
from django.contrib import admin
from django.contrib.auth.models import User
from django.db import models
from web.models.base import BaseModel
from web.models.event import Event
class SharedEvent(BaseModel):
id = models.AutoField(primary_key=True)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
shared_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='shared_by')
shared_to = models.ForeignKey(User, on_delete=models.CASCADE, related_name='shared_to')
class Meta:
db_table = 'shared_event'
class SharedEventAdmin(admin.ModelAdmin):
list_display = ('shared_by', 'shared_to', 'event')

View File

@ -1,26 +1,36 @@
{% extends 'base.html' %}
{% block content %}
<table class="table">
<thead>
<tr>
<td>Event Name</td>
<td>Already Responded</td>
<td>Start Date</td>
<td>End Date</td>
</tr>
</thead>
<tbody>
{% for event in events %}
<table class="table">
<thead>
<tr>
<td><a href="{% url 'event' event.id %}">{{event.name}}</a></td>
<td>{{event.responses}}</td>
<td>{{event.start_date|date:"m/d/Y"}}</td>
<td>{{event.end_date|date:"m/d/Y"}}</td>
<td>Event Name</td>
<td>Already Responded</td>
<td>Start Date</td>
<td>End Date</td>
<td>img</td>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for event in events %}
<div class="accordion-item">
<div class="accordion-item">
<h2 class="accordion-header" id="event-{{ event.id }}">
<button class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#event-collapse-{{ event.id }}"
aria-expanded="true"
aria-controls="event-collapse-{{ event.id }}">{{ event.name }}</button>
</h2>
<div id="event-collapse-{{ event.id }}"
class="accordion-collapse collapse"
aria-labelledby="event-{{ event.id }}"
data-bs-parent="#accordionExample">
<div class="accordion-body">{{ event.description }}</div>
</div>
</div>
</div>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -18,6 +18,7 @@ def index(request):
'name': active_event.name,
'start_date': active_event.start_date.date(),
'end_date': active_event.end_date.date(),
'cover_image': active_event.cover_image,
'responses': ', '.join([x.user.username for x in active_event.availability_set.all()])
}