Compare commits
5 Commits
ui-event-p
...
api-first
Author | SHA1 | Date | |
---|---|---|---|
bfc2950a1d | |||
8c9bc213b0 | |||
e288cd3f31 | |||
10db56805f | |||
794bf82a1c |
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyc
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
@ -51,3 +52,8 @@ docs/_build/
|
||||
|
||||
*__pycache__/*
|
||||
*.pyc
|
||||
|
||||
run.sh
|
||||
venv/
|
||||
*.bak
|
||||
scratch*
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -82,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'),
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,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"
|
||||
|
@ -1,6 +1,7 @@
|
||||
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
|
||||
@ -16,7 +17,10 @@ urlpatterns = [
|
||||
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')
|
||||
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)
|
||||
|
BIN
media/event_cover_images/9ndu0d.jpg
Normal file
BIN
media/event_cover_images/9ndu0d.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
@ -12,3 +12,4 @@ requests==2.32.3
|
||||
soupsieve==2.6
|
||||
sqlparse==0.5.1
|
||||
urllib3==2.3.0
|
||||
pillow==11.1.0
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
18
web/migrations/0005_event_cover_image.py
Normal file
18
web/migrations/0005_event_cover_image.py
Normal 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/'),
|
||||
),
|
||||
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -10,6 +10,7 @@ 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)
|
||||
|
@ -20,6 +20,9 @@
|
||||
</div>
|
||||
<div style="float:right;">
|
||||
<a href="{% url 'index' %}">home</a> |
|
||||
<a href="{% url 'change_password' %}">change password</a> |
|
||||
<a href="{% url 'logout' %}">logout</a> |
|
||||
{% if request.user.is_authenticated %}Hello {{ request.user.username }} {% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
@ -35,4 +38,4 @@
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
@ -1,28 +1,36 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
|
||||
<div class="accordion">
|
||||
{% 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}}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Event Name</td>
|
||||
<td>Already Responded</td>
|
||||
<td>Start Date</td>
|
||||
<td>End Date</td>
|
||||
<td>img</td>
|
||||
</tr>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
145
web/views.py
145
web/views.py
@ -1,7 +1,6 @@
|
||||
from datetime import timedelta
|
||||
from django.contrib.auth import update_session_auth_hash
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.forms import PasswordChangeForm
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from scripts.bp_deactivate import deactivate
|
||||
@ -10,10 +9,148 @@ from web.models import Event, Availability
|
||||
|
||||
@login_required()
|
||||
def index(request):
|
||||
user = User.objects.filter(username='dominic').first()
|
||||
deactivate()
|
||||
parsed_events = []
|
||||
|
||||
for active_event in Event.objects.filter(active=True).order_by('start_date')[:10]:
|
||||
data = {
|
||||
'id': active_event.id,
|
||||
'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()])
|
||||
}
|
||||
|
||||
parsed_events.append(data)
|
||||
|
||||
context = {
|
||||
'events': Event.objects.filter(created_by=user).all() # TODO: How to determine user?
|
||||
'events': parsed_events
|
||||
}
|
||||
|
||||
return render(request, template_name='index.html', context=context)
|
||||
return render(request, "index.html", context)
|
||||
|
||||
|
||||
def change_password(request):
|
||||
if request.method == 'POST':
|
||||
form = PasswordChangeForm(request.user, request.POST)
|
||||
if form.is_valid():
|
||||
user = form.save()
|
||||
update_session_auth_hash(request, user)
|
||||
return redirect('password_change_done')
|
||||
else:
|
||||
form = PasswordChangeForm(request.user)
|
||||
return render(request, 'change-password/change_password.html', {'form': form})
|
||||
|
||||
def password_change_done(request):
|
||||
return render(request, 'change-password/password_change_done.html')
|
||||
|
||||
|
||||
@login_required()
|
||||
def event(request, event_id):
|
||||
|
||||
event = get_object_or_404(Event, pk=event_id)
|
||||
|
||||
if request.method == 'POST':
|
||||
handle_availability_update(event, request)
|
||||
return redirect('event', event_id=event_id)
|
||||
|
||||
elif request.method == 'GET':
|
||||
day_count = (event.end_date - event.start_date).days + 1
|
||||
morning = {}
|
||||
noon = {}
|
||||
night = {}
|
||||
all_availabilities = {}
|
||||
requesting_user_submitted = False
|
||||
|
||||
context = {
|
||||
'event': event,
|
||||
'morning': morning,
|
||||
'noon': noon,
|
||||
'night': night,
|
||||
'user_availability': None,
|
||||
'active_dates': None,
|
||||
'user_responses': 0,
|
||||
'best_days': {},
|
||||
'no_overlap_message': ''
|
||||
}
|
||||
|
||||
user_availability = Availability.objects.filter(event_id=event)
|
||||
if user_availability:
|
||||
for user_avail in user_availability:
|
||||
context['user_responses'] += 1
|
||||
|
||||
for time in user_avail.time_table.get('active', []):
|
||||
if time not in all_availabilities:
|
||||
all_availabilities[time] = []
|
||||
|
||||
all_availabilities[time].append(user_avail.user.username)
|
||||
|
||||
if request.user == user_avail.user:
|
||||
requesting_user_submitted = True
|
||||
context['active_dates'] = user_avail.time_table['active']
|
||||
|
||||
context['all_availabilities'] = all_availabilities
|
||||
|
||||
for i in range(day_count):
|
||||
date = event.start_date + timedelta(days=i)
|
||||
|
||||
human_readable_date = date.strftime('%m/%d/%Y %A')
|
||||
for idx, time_period_array in enumerate([morning, noon, night]):
|
||||
date_id = date.strftime(f'%m/%d/%Y %A-{idx}')
|
||||
users = ', '.join(all_availabilities.get(date_id, []))
|
||||
|
||||
if not requesting_user_submitted:
|
||||
users = ''
|
||||
|
||||
time_period_array[human_readable_date] = (date_id, users)
|
||||
|
||||
if all_availabilities:
|
||||
most_avail = None
|
||||
for day in sorted(all_availabilities, key=lambda k: len(all_availabilities[k]), reverse=True):
|
||||
if not most_avail:
|
||||
most_avail = len(all_availabilities[day])
|
||||
|
||||
if len(all_availabilities[day]) >= most_avail - 1 and len(all_availabilities[day]) != 1:
|
||||
|
||||
day_arr = day.split('-')
|
||||
if day_arr[-1] == '0':
|
||||
hday = day_arr[0] + ' Morning'
|
||||
|
||||
if day_arr[-1] == '1':
|
||||
hday = day_arr[0] + ' Noon'
|
||||
|
||||
if day_arr[-1] == '2':
|
||||
hday = day_arr[0] + ' Night'
|
||||
|
||||
context['best_days'][hday] = ', '.join(all_availabilities[day])
|
||||
|
||||
if not requesting_user_submitted:
|
||||
all_availabilities = {}
|
||||
|
||||
if context['best_days'] == {}:
|
||||
context['no_overlap_message'] = 'There are currently no overlapping times or dates!'
|
||||
|
||||
return render(request, "event.html", context)
|
||||
|
||||
def handle_availability_update(event, request):
|
||||
availability_data = {
|
||||
'active': []
|
||||
}
|
||||
|
||||
for date, value in request.POST.items():
|
||||
if date != 'csrfmiddlewaretoken':
|
||||
availability_data['active'].append(date)
|
||||
|
||||
user_availability = Availability.objects.filter(event_id=event).filter(user=request.user)
|
||||
if not user_availability:
|
||||
a = Availability(
|
||||
event_id=event,
|
||||
user=request.user,
|
||||
time_table=availability_data
|
||||
)
|
||||
a.save()
|
||||
else:
|
||||
avail = user_availability[0]
|
||||
avail.time_table = availability_data
|
||||
avail.save()
|
||||
|
Loading…
x
Reference in New Issue
Block a user