Compare commits
1 Commits
api-first
...
ui-event-p
Author | SHA1 | Date | |
---|---|---|---|
69b7942f00 |
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,7 +1,6 @@
|
|||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# C extensions
|
# C extensions
|
||||||
*.so
|
*.so
|
||||||
@ -52,8 +51,3 @@ docs/_build/
|
|||||||
|
|
||||||
*__pycache__/*
|
*__pycache__/*
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
run.sh
|
|
||||||
venv/
|
|
||||||
*.bak
|
|
||||||
scratch*
|
|
||||||
|
BIN
api/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
api/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api/__pycache__/admin.cpython-312.pyc
Normal file
BIN
api/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api/__pycache__/apps.cpython-312.pyc
Normal file
BIN
api/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api/__pycache__/models.cpython-312.pyc
Normal file
BIN
api/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
api/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api/serializers/__pycache__/event.cpython-312.pyc
Normal file
BIN
api/serializers/__pycache__/event.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api/views/__pycache__/event.cpython-312.pyc
Normal file
BIN
api/views/__pycache__/event.cpython-312.pyc
Normal file
Binary file not shown.
BIN
common/__pycache__/build_response.cpython-312.pyc
Normal file
BIN
common/__pycache__/build_response.cpython-312.pyc
Normal file
Binary file not shown.
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
BIN
korabo/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
korabo/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
korabo/__pycache__/settings.cpython-312.pyc
Normal file
BIN
korabo/__pycache__/settings.cpython-312.pyc
Normal file
Binary file not shown.
BIN
korabo/__pycache__/urls.cpython-312.pyc
Normal file
BIN
korabo/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
korabo/__pycache__/wsgi.cpython-312.pyc
Normal file
BIN
korabo/__pycache__/wsgi.cpython-312.pyc
Normal file
Binary file not shown.
@ -82,12 +82,8 @@ WSGI_APPLICATION = 'korabo.wsgi.application'
|
|||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.postgresql',
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': os.getenv('DB_NAME'),
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
'USER': os.getenv('DB_USER'),
|
|
||||||
'PASSWORD': os.getenv('DB_PASS'),
|
|
||||||
'HOST': os.getenv('DB_HOST'),
|
|
||||||
'PORT': os.getenv('DB_PORT'),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +131,3 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
|
|||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = '/'
|
||||||
LOGOUT_REDIRECT_URL = '/'
|
LOGOUT_REDIRECT_URL = '/'
|
||||||
|
|
||||||
MEDIA_URL = "/media/"
|
|
||||||
MEDIA_ROOT = BASE_DIR / "media"
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path, include
|
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 import EventView
|
||||||
from api.views.event_division import EventDivisionView
|
from api.views.event_division import EventDivisionView
|
||||||
from api.views.event_comment import EventCommentView
|
from api.views.event_comment import EventCommentView
|
||||||
@ -17,10 +16,7 @@ urlpatterns = [
|
|||||||
path('api/event_division/', EventDivisionView.as_view(), name='event_division'),
|
path('api/event_division/', EventDivisionView.as_view(), name='event_division'),
|
||||||
path("", views.index, name="index"),
|
path("", views.index, name="index"),
|
||||||
path("accounts/", include("django.contrib.auth.urls")),
|
path("accounts/", include("django.contrib.auth.urls")),
|
||||||
path("event/<int:event_id>", views.event, name="event"),
|
#path("event/<int:event_id>", views.event, name="event"),
|
||||||
path('change_password/', views.change_password, name='change_password'),
|
#path('change_password/', views.change_password, name='change_password'),
|
||||||
path('password_change_done/', views.password_change_done, name='password_change_done')
|
#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.
Before Width: | Height: | Size: 48 KiB |
@ -12,4 +12,3 @@ requests==2.32.3
|
|||||||
soupsieve==2.6
|
soupsieve==2.6
|
||||||
sqlparse==0.5.1
|
sqlparse==0.5.1
|
||||||
urllib3==2.3.0
|
urllib3==2.3.0
|
||||||
pillow==11.1.0
|
|
||||||
|
BIN
web/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
web/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/__pycache__/admin.cpython-312.pyc
Normal file
BIN
web/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/__pycache__/apps.cpython-312.pyc
Normal file
BIN
web/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/__pycache__/models.cpython-312.pyc
Normal file
BIN
web/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/__pycache__/views.cpython-312.pyc
Normal file
BIN
web/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
@ -1,18 +0,0 @@
|
|||||||
# 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/'),
|
|
||||||
),
|
|
||||||
]
|
|
BIN
web/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
BIN
web/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
web/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
web/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/models/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
web/models/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/models/__pycache__/availability.cpython-312.pyc
Normal file
BIN
web/models/__pycache__/availability.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/models/__pycache__/base.cpython-312.pyc
Normal file
BIN
web/models/__pycache__/base.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/models/__pycache__/event.cpython-312.pyc
Normal file
BIN
web/models/__pycache__/event.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/models/__pycache__/event_comment.cpython-312.pyc
Normal file
BIN
web/models/__pycache__/event_comment.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/models/__pycache__/event_comment_reaction.cpython-312.pyc
Normal file
BIN
web/models/__pycache__/event_comment_reaction.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/models/__pycache__/event_division.cpython-312.pyc
Normal file
BIN
web/models/__pycache__/event_division.cpython-312.pyc
Normal file
Binary file not shown.
BIN
web/models/__pycache__/shared_event.cpython-312.pyc
Normal file
BIN
web/models/__pycache__/shared_event.cpython-312.pyc
Normal file
Binary file not shown.
@ -10,7 +10,6 @@ class Event(BaseModel):
|
|||||||
id = models.AutoField(primary_key=True)
|
id = models.AutoField(primary_key=True)
|
||||||
name = models.TextField(blank=False, null=False)
|
name = models.TextField(blank=False, null=False)
|
||||||
description = 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)
|
division = models.ForeignKey(EventDivision, on_delete=models.CASCADE)
|
||||||
start_date = models.DateTimeField(blank=False, null=False)
|
start_date = models.DateTimeField(blank=False, null=False)
|
||||||
end_date = models.DateTimeField(blank=False, null=False)
|
end_date = models.DateTimeField(blank=False, null=False)
|
||||||
|
@ -20,9 +20,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="float:right;">
|
<div style="float:right;">
|
||||||
<a href="{% url 'index' %}">home</a> |
|
<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>
|
</div>
|
||||||
|
|
||||||
@ -38,4 +35,4 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,36 +1,28 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<table class="table">
|
<div class="container">
|
||||||
<thead>
|
|
||||||
<tr>
|
<div class="accordion">
|
||||||
<td>Event Name</td>
|
{% for event in events%}
|
||||||
<td>Already Responded</td>
|
<div class="accordion-item">
|
||||||
<td>Start Date</td>
|
<div class="accordion-item">
|
||||||
<td>End Date</td>
|
<h2 class="accordion-header" id="event-{{event.id}}">
|
||||||
<td>img</td>
|
<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}}">
|
||||||
</tr>
|
{{event.name}}
|
||||||
</thead>
|
</button>
|
||||||
<tbody>
|
</h2>
|
||||||
{% for event in events %}
|
<div id="event-collapse-{{event.id}}" class="accordion-collapse collapse" aria-labelledby="event-{{event.id}}" data-bs-parent="#accordionExample">
|
||||||
<div class="accordion-item">
|
<div class="accordion-body">
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="event-{{ event.id }}">
|
{{event.description}}
|
||||||
<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>
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
145
web/views.py
145
web/views.py
@ -1,6 +1,7 @@
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from django.contrib.auth import update_session_auth_hash
|
from django.contrib.auth import update_session_auth_hash
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.forms import PasswordChangeForm
|
from django.contrib.auth.forms import PasswordChangeForm
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from scripts.bp_deactivate import deactivate
|
from scripts.bp_deactivate import deactivate
|
||||||
@ -9,148 +10,10 @@ from web.models import Event, Availability
|
|||||||
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def index(request):
|
def index(request):
|
||||||
deactivate()
|
user = User.objects.filter(username='dominic').first()
|
||||||
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 = {
|
context = {
|
||||||
'events': parsed_events
|
'events': Event.objects.filter(created_by=user).all() # TODO: How to determine user?
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, "index.html", context)
|
return render(request, template_name='index.html', context=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