From 33870561208c545933c03a877c9d29d168ad3fa8 Mon Sep 17 00:00:00 2001 From: Jannes Hikmat Date: Sun, 8 Jan 2023 19:51:05 +0100 Subject: [PATCH] update --- mensaviewer/admin.py | 4 +- mensaviewer/forms.py | 6 +- mensaviewer/helpers.py | 96 ++------- ...6_remove_menu_days_delete_day_menu_days.py | 25 +++ ...e_menu_locations_location_city_and_more.py | 37 ++++ ...rename_username_comment_author_and_more.py | 42 ++++ ...ter_comment_text_alter_newsarticle_text.py | 23 +++ .../migrations/0020_newsarticle_timestamp.py | 19 ++ .../migrations/0021_newsarticle_title.py | 18 ++ ...alter_menu_art_alter_menu_name_and_more.py | 38 ++++ ...alter_menu_art_alter_menu_name_and_more.py | 38 ++++ mensaviewer/models.py | 10 +- mensaviewer/templates/base.html | 25 ++- mensaviewer/templates/comment/delete.html | 12 ++ mensaviewer/templates/comment/detail.html | 12 ++ mensaviewer/templates/comment/edit.html | 11 + mensaviewer/templates/comment/list.html | 31 +++ mensaviewer/templates/custom.html | 60 ++++++ mensaviewer/templates/flensburg.html | 42 ++-- mensaviewer/templates/location/delete.html | 12 ++ mensaviewer/templates/location/detail.html | 29 +++ mensaviewer/templates/location/edit.html | 11 + mensaviewer/templates/location/list.html | 31 +++ mensaviewer/templates/menu/delete.html | 12 ++ mensaviewer/templates/menu/detail.html | 28 +++ mensaviewer/templates/menu/edit.html | 11 + mensaviewer/templates/menu/list.html | 31 +++ mensaviewer/templates/news/delete.html | 12 ++ mensaviewer/templates/news/detail.html | 12 ++ mensaviewer/templates/news/edit.html | 11 + mensaviewer/templates/news/list.html | 33 +++ mensaviewer/urls.py | 42 +++- mensaviewer/views.py | 193 +++++++++++++++--- static/base.css | 182 ++++++++++++++++- 34 files changed, 1047 insertions(+), 152 deletions(-) create mode 100644 mensaviewer/migrations/0016_remove_menu_days_delete_day_menu_days.py create mode 100644 mensaviewer/migrations/0017_remove_menu_days_remove_menu_locations_location_city_and_more.py create mode 100644 mensaviewer/migrations/0018_rename_username_comment_author_and_more.py create mode 100644 mensaviewer/migrations/0019_alter_comment_text_alter_newsarticle_text.py create mode 100644 mensaviewer/migrations/0020_newsarticle_timestamp.py create mode 100644 mensaviewer/migrations/0021_newsarticle_title.py create mode 100644 mensaviewer/migrations/0022_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more.py create mode 100644 mensaviewer/migrations/0023_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more.py create mode 100644 mensaviewer/templates/comment/delete.html create mode 100644 mensaviewer/templates/comment/detail.html create mode 100644 mensaviewer/templates/comment/edit.html create mode 100644 mensaviewer/templates/comment/list.html create mode 100644 mensaviewer/templates/custom.html create mode 100644 mensaviewer/templates/location/delete.html create mode 100644 mensaviewer/templates/location/detail.html create mode 100644 mensaviewer/templates/location/edit.html create mode 100644 mensaviewer/templates/location/list.html create mode 100644 mensaviewer/templates/menu/delete.html create mode 100644 mensaviewer/templates/menu/detail.html create mode 100644 mensaviewer/templates/menu/edit.html create mode 100644 mensaviewer/templates/menu/list.html create mode 100644 mensaviewer/templates/news/delete.html create mode 100644 mensaviewer/templates/news/detail.html create mode 100644 mensaviewer/templates/news/edit.html create mode 100644 mensaviewer/templates/news/list.html diff --git a/mensaviewer/admin.py b/mensaviewer/admin.py index 4989254..38a0f6f 100644 --- a/mensaviewer/admin.py +++ b/mensaviewer/admin.py @@ -18,6 +18,6 @@ class LocationAdmin(admin.ModelAdmin): pass -@admin.register(Day) -class DayAdmin(admin.ModelAdmin): +@admin.register(NewsArticle) +class NewsArticleAdmin(admin.ModelAdmin): pass diff --git a/mensaviewer/forms.py b/mensaviewer/forms.py index ffdaedd..243ac0a 100644 --- a/mensaviewer/forms.py +++ b/mensaviewer/forms.py @@ -9,9 +9,7 @@ from datetime import date class MenuForm(forms.ModelForm): class Meta: model = Menu - fields = ['art', 'name', 'price', 'allergens', 'types', 'day'] + fields = ['location', 'art', 'name', 'price', 'allergens', 'types', 'day'] widgets = { - 'types': forms.CheckboxSelectMultiple(choices=TYPES_CHOICES), - 'allergens': forms.CheckboxSelectMultiple(choices=ALLERGENS_CHOICES), - 'day': forms.DateInput(attrs={'type': 'date'}, format="%d.%m.%Y"), + 'day': forms.DateInput(attrs={'type': 'date'}), } diff --git a/mensaviewer/helpers.py b/mensaviewer/helpers.py index f1e0569..4208655 100644 --- a/mensaviewer/helpers.py +++ b/mensaviewer/helpers.py @@ -20,46 +20,39 @@ example_json = [ def load_data(locations, checked_types, status): current_week = datetime.date.today().isocalendar().week - days = Day.objects.filter(date__week=current_week) - for location in locations: - menus = Menu.objects.filter(days__in=days, locations=location) + menus = Menu.objects.filter(day__week=current_week, location=location) if not menus.exists(): fetched_data = fetch(location.mensa_id) store(fetched_data, location) - data = formatted_menu_data(locations, checked_types, status) return data def formatted_menu_data(locations, checked_types, status): current_week = datetime.date.today().isocalendar().week - days = Day.objects.filter(date__week=current_week) + today = datetime.date.today() + days = [today + datetime.timedelta(days=i) + for i in range(0 - today.weekday(), 5 - today.weekday())] formatted_data = {} - - for day in days: - formatted_data[str(day.date)] = [] - for day in days: + if day not in formatted_data: + formatted_data[day] = [] for location in locations: - menus = Menu.objects.filter(days=day, locations=location) + menus = Menu.objects.filter(location=location, day=day) for menu in menus: - - # AND or OR filter ??? if set(checked_types).issubset(set(menu.types)): # <-- AND - - - - formatted_data[str(day.date)].append({ + formatted_data[day].append({ 'art': menu.art, 'name': menu.name, - 'price': menu.price if status is None else menu.get_price[status], + 'price': menu.price if status is None + else menu.get_price[status], 'allergens': menu.get_allergens, 'types': menu.get_types, 'likes': menu.likes, - 'location': location.name, + 'location': location, 'pk': menu.pk, }) return formatted_data @@ -67,32 +60,21 @@ def formatted_menu_data(locations, checked_types, status): def store(data, location): for day_json in data: - date_string= day_json['day'] + date_string = day_json['day'] menus_json = day_json['menus'] - - date = parse_date(date_string) - - if not Day.objects.filter(date=date).exists(): - Day(date=date).save() - - day = Day.objects.get(date=date) - + day = parse_date(date_string) for menu_json in menus_json: art = menu_json['art'] name = menu_json['name'] - price = menu_json['price'] or "0,00€ / 0,00€ / 0,00€" + price = menu_json['price'] or "0,00 € / 0,00 € / 0,00 €" allergens = menu_json['allergens'] types = menu_json['types'] - - menu_exists = Menu.objects.filter(art=art, name=name, price=price, allergens=allergens, types=types).exists() - + menu_exists = Menu.objects.filter(art=art, name=name, price=price, + allergens=allergens, types=types, + day=day).exists() if not menu_exists: - Menu(art=art, name=name, price=price, allergens=allergens, types=types).save() - - menu = Menu.objects.get(art=art, name=name, price=price, allergens=allergens, types=types) - menu.locations.add(location) - menu.days.add(day) - menu.save() + Menu(art=art, name=name, price=price, allergens=allergens, + types=types, day=day, location=location).save() def fetch(mensa_id: int): @@ -100,43 +82,3 @@ def fetch(mensa_id: int): if res.status_code != 200: raise Exception('request failed') return res.json() - - -def models_from_json(mensa_id: int): - for day_json in fetch_menus(mensa_id): - day_date = datetime.datetime.strptime(day_json['day'], '%Y-%m-%d').date() - - if not Day.objects.filter(mensa_id=mensa_id, date__contains=day_date): - # create new day model ONLY if it does not yet exist for the given - # day_date(s) and mensa_id. - - Day(mensa_id=mensa_id, date=day_date).save() - day = Day.objects.get(mensa_id=mensa_id, date=day_date) - - for menu_json in day_json['menus']: - # if meal already exists, simply add day to related menus. - # otherwise, build new meal model from json with the specified menu - # as the first related menu. - - if not Menu.objects.filter(name=menu_json['name']): - Menu.from_json(menu_json, day).save() - - day.menus.add(Menu.objects.get(name=menu_json['name'])) - - -def days_as_json(mensa_ids: list, types_filter: list, price_filter: str): - cw = datetime.date.today().isocalendar().week - dates = list(dict.fromkeys([day.date for day in Day.objects.filter(date__week=cw)])) - - days_list = [] - for date in dates: - day_json = { 'day': date, 'menus': [] } - for mensa_id in mensa_ids: - try: - day = Day.objects.get(mensa_id=mensa_id, date=date) - for menu in Menu.objects.filter(day=day, related_types__in=Type.objects.filter(type__in=types_filter) if types_filter else Type.objects.all()).distinct(): - day_json['menus'].append({ 'menu': menu, 'mensa_id': mensa_id }) - except ObjectDoesNotExist: - pass - days_list.append(day_json) - return days_list diff --git a/mensaviewer/migrations/0016_remove_menu_days_delete_day_menu_days.py b/mensaviewer/migrations/0016_remove_menu_days_delete_day_menu_days.py new file mode 100644 index 0000000..ba441b8 --- /dev/null +++ b/mensaviewer/migrations/0016_remove_menu_days_delete_day_menu_days.py @@ -0,0 +1,25 @@ +# Generated by Django 4.1.4 on 2023-01-06 00:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0015_comment_timestamp'), + ] + + operations = [ + migrations.RemoveField( + model_name='menu', + name='days', + ), + migrations.DeleteModel( + name='Day', + ), + migrations.AddField( + model_name='menu', + name='days', + field=models.JSONField(blank=True, null=True), + ), + ] diff --git a/mensaviewer/migrations/0017_remove_menu_days_remove_menu_locations_location_city_and_more.py b/mensaviewer/migrations/0017_remove_menu_days_remove_menu_locations_location_city_and_more.py new file mode 100644 index 0000000..74db3bd --- /dev/null +++ b/mensaviewer/migrations/0017_remove_menu_days_remove_menu_locations_location_city_and_more.py @@ -0,0 +1,37 @@ +# Generated by Django 4.1.4 on 2023-01-06 22:11 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0016_remove_menu_days_delete_day_menu_days'), + ] + + operations = [ + migrations.RemoveField( + model_name='menu', + name='days', + ), + migrations.RemoveField( + model_name='menu', + name='locations', + ), + migrations.AddField( + model_name='location', + name='city', + field=models.CharField(blank=True, max_length=144, null=True), + ), + migrations.AddField( + model_name='menu', + name='day', + field=models.DateField(blank=True, null=True), + ), + migrations.AddField( + model_name='menu', + name='location', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.location'), + ), + ] diff --git a/mensaviewer/migrations/0018_rename_username_comment_author_and_more.py b/mensaviewer/migrations/0018_rename_username_comment_author_and_more.py new file mode 100644 index 0000000..e8bc311 --- /dev/null +++ b/mensaviewer/migrations/0018_rename_username_comment_author_and_more.py @@ -0,0 +1,42 @@ +# Generated by Django 4.1.4 on 2023-01-06 22:32 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0017_remove_menu_days_remove_menu_locations_location_city_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='comment', + old_name='username', + new_name='author', + ), + migrations.RenameField( + model_name='comment', + old_name='related_menu', + new_name='menu', + ), + migrations.RemoveField( + model_name='comment', + name='comment', + ), + migrations.AddField( + model_name='comment', + name='text', + field=models.CharField(blank=True, max_length=512, null=True), + ), + migrations.CreateModel( + name='NewsArticle', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('author', models.CharField(default='anon', max_length=144)), + ('text', models.CharField(blank=True, max_length=8192, null=True)), + ('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.location')), + ], + ), + ] diff --git a/mensaviewer/migrations/0019_alter_comment_text_alter_newsarticle_text.py b/mensaviewer/migrations/0019_alter_comment_text_alter_newsarticle_text.py new file mode 100644 index 0000000..18f1dc5 --- /dev/null +++ b/mensaviewer/migrations/0019_alter_comment_text_alter_newsarticle_text.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.4 on 2023-01-06 22:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0018_rename_username_comment_author_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='comment', + name='text', + field=models.TextField(blank=True, null=True), + ), + migrations.AlterField( + model_name='newsarticle', + name='text', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/mensaviewer/migrations/0020_newsarticle_timestamp.py b/mensaviewer/migrations/0020_newsarticle_timestamp.py new file mode 100644 index 0000000..22c1ef3 --- /dev/null +++ b/mensaviewer/migrations/0020_newsarticle_timestamp.py @@ -0,0 +1,19 @@ +# Generated by Django 4.1.4 on 2023-01-08 01:01 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0019_alter_comment_text_alter_newsarticle_text'), + ] + + operations = [ + migrations.AddField( + model_name='newsarticle', + name='timestamp', + field=models.DateTimeField(blank=True, default=django.utils.timezone.now), + ), + ] diff --git a/mensaviewer/migrations/0021_newsarticle_title.py b/mensaviewer/migrations/0021_newsarticle_title.py new file mode 100644 index 0000000..68be4bf --- /dev/null +++ b/mensaviewer/migrations/0021_newsarticle_title.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.4 on 2023-01-08 02:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0020_newsarticle_timestamp'), + ] + + operations = [ + migrations.AddField( + model_name='newsarticle', + name='title', + field=models.CharField(blank=True, max_length=144), + ), + ] diff --git a/mensaviewer/migrations/0022_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more.py b/mensaviewer/migrations/0022_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more.py new file mode 100644 index 0000000..e2dac3f --- /dev/null +++ b/mensaviewer/migrations/0022_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 4.1.4 on 2023-01-08 03:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0021_newsarticle_title'), + ] + + operations = [ + migrations.AlterField( + model_name='menu', + name='allergens', + field=models.JSONField(blank=True, default=[]), + ), + migrations.AlterField( + model_name='menu', + name='art', + field=models.CharField(choices=[('M', 'Mensa'), ('C', 'Cafeteria')], default='M', max_length=1), + ), + migrations.AlterField( + model_name='menu', + name='name', + field=models.CharField(blank=True, default='', max_length=144), + ), + migrations.AlterField( + model_name='menu', + name='price', + field=models.CharField(blank=True, default='', max_length=144), + ), + migrations.AlterField( + model_name='menu', + name='types', + field=models.JSONField(blank=True, default=[]), + ), + ] diff --git a/mensaviewer/migrations/0023_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more.py b/mensaviewer/migrations/0023_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more.py new file mode 100644 index 0000000..83050e1 --- /dev/null +++ b/mensaviewer/migrations/0023_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 4.1.4 on 2023-01-08 18:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0022_alter_menu_allergens_alter_menu_art_alter_menu_name_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='menu', + name='allergens', + field=models.JSONField(blank=True, default=list), + ), + migrations.AlterField( + model_name='menu', + name='art', + field=models.CharField(choices=[('Mensa', 'Mensa'), ('Cafeteria', 'Cafeteria')], default='M', max_length=24), + ), + migrations.AlterField( + model_name='menu', + name='name', + field=models.CharField(blank=True, default='---', max_length=144), + ), + migrations.AlterField( + model_name='menu', + name='price', + field=models.CharField(blank=True, default='---', max_length=144), + ), + migrations.AlterField( + model_name='menu', + name='types', + field=models.JSONField(blank=True, default=list), + ), + ] diff --git a/mensaviewer/models.py b/mensaviewer/models.py index ffe945b..d820e14 100644 --- a/mensaviewer/models.py +++ b/mensaviewer/models.py @@ -10,7 +10,7 @@ class Location(models.Model): mensa_id = models.CharField(max_length=2, null=True, blank=True) def __str__(self): - return f"{self.city} - {self.name} [{self.mensa_id}]" + return f"{self.city} - {self.name}" @property def menus(self): @@ -33,7 +33,7 @@ class Menu(models.Model): blank=True) def __str__(self): - return f"{self.name}" + return f"{self.name} - {self.location} | {self.day}" @property def get_price(self): @@ -69,6 +69,9 @@ class Comment(models.Model): author = models.CharField(max_length=144, default='anon') text = models.TextField(null=True, blank=True) + def __str__(self): + return f"{self.menu} - {self.author} | {self.timestamp}" + class NewsArticle(models.Model): location = models.ForeignKey(Location, on_delete=models.CASCADE) @@ -76,3 +79,6 @@ class NewsArticle(models.Model): author = models.CharField(max_length=144, default='anon') title = models.CharField(max_length=144, blank=True) text = models.TextField(null=True, blank=True) + + def __str__(self): + return f"{self.title} | {self.title} - {self.author} | {self.timestamp}" diff --git a/mensaviewer/templates/base.html b/mensaviewer/templates/base.html index e8f51df..2c8f291 100644 --- a/mensaviewer/templates/base.html +++ b/mensaviewer/templates/base.html @@ -5,19 +5,28 @@ - Mensaviewer | {% block title %}Home{%endblock%} + Mensaviewer | {% block title %}Home{% endblock %}
-

Header Title

+ {% block header %}

Header Title

{% endblock %}
-
- {% block content %} - {% endblock %} + +
+ {% block content %} + {% endblock %} +
diff --git a/mensaviewer/templates/comment/delete.html b/mensaviewer/templates/comment/delete.html new file mode 100644 index 0000000..ac3307c --- /dev/null +++ b/mensaviewer/templates/comment/delete.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ {% csrf_token %} +

Are you sure you want to delete "{{ object }}"?

+ {{ form }} + +
+ +{% endblock %} diff --git a/mensaviewer/templates/comment/detail.html b/mensaviewer/templates/comment/detail.html new file mode 100644 index 0000000..103231e --- /dev/null +++ b/mensaviewer/templates/comment/detail.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block content %} + +
+

By {{ comment.author }}

+

Timestamp: {{ comment.timestamp }}

+

Menu: {{ comment.menu.name }}

+

Text: {{ comment.text }}

+
+ +{% endblock %} diff --git a/mensaviewer/templates/comment/edit.html b/mensaviewer/templates/comment/edit.html new file mode 100644 index 0000000..f56eaaf --- /dev/null +++ b/mensaviewer/templates/comment/edit.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ {% csrf_token %} + {{ form }} + +
+ +{% endblock %} diff --git a/mensaviewer/templates/comment/list.html b/mensaviewer/templates/comment/list.html new file mode 100644 index 0000000..d1857bd --- /dev/null +++ b/mensaviewer/templates/comment/list.html @@ -0,0 +1,31 @@ +{% extends 'base.html' %} + +{% block content %} + +

Comments

+ + + + + + + + + + + + + {% for comment in object_list %} + + + + + + + + {% endfor %} +
+ Add Comment +
AuthorTimestampMenu
{{ comment.author }}{{ comment.timestamp }}{{ comment.menu }}EditDelete
+ +{% endblock %} diff --git a/mensaviewer/templates/custom.html b/mensaviewer/templates/custom.html new file mode 100644 index 0000000..ce1808e --- /dev/null +++ b/mensaviewer/templates/custom.html @@ -0,0 +1,60 @@ +{% extends 'base.html' %} + +{% block title %}Custom Locations{% endblock %} + +{% block header %}

Show menus for custom location selection

{% endblock %} + +{% block content %} + +
+ +
+ {% for name, id in types %} + + {% endfor %} +
+
+ {% for status_value in status_values %} + + {% endfor %} +
+
+ {% for location in locations %} + + {% endfor %} +
+ +
+ +
+ {% for day, menus in menu_data.items %} +
+

{{ day }}

+ + {% for menu in menus %} + + {% endfor %} + +
+ {% endfor %} +
+ +{% endblock %} diff --git a/mensaviewer/templates/flensburg.html b/mensaviewer/templates/flensburg.html index 1da86c9..100951c 100644 --- a/mensaviewer/templates/flensburg.html +++ b/mensaviewer/templates/flensburg.html @@ -1,17 +1,18 @@ {% extends 'base.html' %} +{% block title %}Flensburg{% endblock %} + +{% block header %}

Mensen in Flensburg

{% endblock %} + {% block content %} -
+ -
+
{% for name, id in types %} {% endfor %}
@@ -19,25 +20,10 @@ {% for status_value in status_values %} {% endfor %}
-
- {% for location in locations %} - - {% endfor %} -
- New Location
@@ -47,23 +33,21 @@

{{ day }}

{% for menu in menus %} - {% endfor %} - {% endblock %} diff --git a/mensaviewer/templates/location/delete.html b/mensaviewer/templates/location/delete.html new file mode 100644 index 0000000..ac3307c --- /dev/null +++ b/mensaviewer/templates/location/delete.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ {% csrf_token %} +

Are you sure you want to delete "{{ object }}"?

+ {{ form }} + +
+ +{% endblock %} diff --git a/mensaviewer/templates/location/detail.html b/mensaviewer/templates/location/detail.html new file mode 100644 index 0000000..282c154 --- /dev/null +++ b/mensaviewer/templates/location/detail.html @@ -0,0 +1,29 @@ +{% extends 'base.html' %} + +{% block content %} + +
+

{{ location.name }}

+

City: {{ location.city }}

+

ID: {{ location.mensa_id }}

+ Add News + Add Menu + + +
+ +{% endblock %} diff --git a/mensaviewer/templates/location/edit.html b/mensaviewer/templates/location/edit.html new file mode 100644 index 0000000..f56eaaf --- /dev/null +++ b/mensaviewer/templates/location/edit.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ {% csrf_token %} + {{ form }} + +
+ +{% endblock %} diff --git a/mensaviewer/templates/location/list.html b/mensaviewer/templates/location/list.html new file mode 100644 index 0000000..f074165 --- /dev/null +++ b/mensaviewer/templates/location/list.html @@ -0,0 +1,31 @@ +{% extends 'base.html' %} + +{% block content %} + +

Locations

+ + + + + + + + + + + + + {% for location in object_list %} + + + + + + + + {% endfor %} +
+ New Location +
NameCityID
{{ location.name }}{{ location.city }}{{ location.mensa_id }}EditDelete
+ +{% endblock %} diff --git a/mensaviewer/templates/menu/delete.html b/mensaviewer/templates/menu/delete.html new file mode 100644 index 0000000..ac3307c --- /dev/null +++ b/mensaviewer/templates/menu/delete.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ {% csrf_token %} +

Are you sure you want to delete "{{ object }}"?

+ {{ form }} + +
+ +{% endblock %} diff --git a/mensaviewer/templates/menu/detail.html b/mensaviewer/templates/menu/detail.html new file mode 100644 index 0000000..729c4f5 --- /dev/null +++ b/mensaviewer/templates/menu/detail.html @@ -0,0 +1,28 @@ +{% extends 'base.html' %} + +{% block content %} + +
+

{{ menu.name }}

+

Art: {{ menu.art }}

+

Price for Students: {{ menu.get_price.Student }}

+

Price for Employees: {{ menu.get_price.Employee }}

+

Price for Guests: {{ menu.get_price.Guest }}

+

Allergens: {{ menu.get_allergens }}

+

Types: {{ menu.get_types }}

+

Rating: {{ menu.likes }}

+

Location and Date: {{ menu.location.city }} {{ menu.location.name }} | {{ menu.day }}

+ Like + Dislike + Comment + +
+ +{% endblock %} diff --git a/mensaviewer/templates/menu/edit.html b/mensaviewer/templates/menu/edit.html new file mode 100644 index 0000000..f56eaaf --- /dev/null +++ b/mensaviewer/templates/menu/edit.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ {% csrf_token %} + {{ form }} + +
+ +{% endblock %} diff --git a/mensaviewer/templates/menu/list.html b/mensaviewer/templates/menu/list.html new file mode 100644 index 0000000..aeb8579 --- /dev/null +++ b/mensaviewer/templates/menu/list.html @@ -0,0 +1,31 @@ +{% extends 'base.html' %} + +{% block content %} + +

Menus

+ + + + + + + + + + + + + {% for menu in object_list %} + + + + + + + + {% endfor %} + + +{% endblock %} diff --git a/mensaviewer/templates/news/delete.html b/mensaviewer/templates/news/delete.html new file mode 100644 index 0000000..ac3307c --- /dev/null +++ b/mensaviewer/templates/news/delete.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ {% csrf_token %} +

Are you sure you want to delete "{{ object }}"?

+ {{ form }} + +
+ +{% endblock %} diff --git a/mensaviewer/templates/news/detail.html b/mensaviewer/templates/news/detail.html new file mode 100644 index 0000000..73b2198 --- /dev/null +++ b/mensaviewer/templates/news/detail.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} + +{% block content %} + +
+

By {{ newsarticle.author }}

+

Timestamp: {{ newsarticle.timestamp }}

+

Location: {{ newsarticle.location.name }}

+

Text: {{ newsarticle.text }}

+
+ +{% endblock %} diff --git a/mensaviewer/templates/news/edit.html b/mensaviewer/templates/news/edit.html new file mode 100644 index 0000000..f56eaaf --- /dev/null +++ b/mensaviewer/templates/news/edit.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} + +{% block content %} + +
+ {% csrf_token %} + {{ form }} + +
+ +{% endblock %} diff --git a/mensaviewer/templates/news/list.html b/mensaviewer/templates/news/list.html new file mode 100644 index 0000000..725ffdb --- /dev/null +++ b/mensaviewer/templates/news/list.html @@ -0,0 +1,33 @@ +{% extends 'base.html' %} + +{% block content %} + +

News Articles

+ + + + + + + + + + + + + + {% for newsarticle in object_list %} + + + + + + + + + {% endfor %} +
+ Add News Article +
TitleAuthorTimestampMenu
{{ newsarticle.title }}{{ newsarticle.author }}{{ newsarticle.timestamp }}{{ newsarticle.location.city }} - {{ newsarticle.location.name }}EditDelete
+ +{% endblock %} diff --git a/mensaviewer/urls.py b/mensaviewer/urls.py index 825038f..133137b 100644 --- a/mensaviewer/urls.py +++ b/mensaviewer/urls.py @@ -3,10 +3,46 @@ from . import views app_name = 'mensaviewer' urlpatterns = [ - path('', views.home, name='home'), + # routes for overview + path('', views.flensburg, name='flensburg'), + path('custom-location', views.custom, name='custom'), + + # raw create routes + path('add-location/', views.LocationCreateView.as_view(), name='location_create'), + path('add-news-article/', views.NewsArticleCreateView.as_view(), name='news_create'), + path('add-menu/', views.MenuCreateView.as_view(), name='menu_create'), + path('add-comment/', views.CommentCreateView.as_view(), name='comment_create'), + + # relation-dependent create routes + path('location//add-news-article/', views.NewsArticleCreateView.as_view(), name='news_add'), + path('location//add-menu/', views.MenuCreateView.as_view(), name='menu_add'), + path('menu//add-comment/', views.CommentCreateView.as_view(), name='comment_add'), + + # list-view routes + path('locations/', views.LocationListView.as_view(), name='location_list'), + path('news-articles/', views.NewsArticleListView.as_view(), name='news_list'), + path('menus/', views.MenuListView.as_view(), name='menu_list'), + path('comments/', views.CommentListView.as_view(), name='comment_list'), + + # detail-view routes + path('location//', views.LocationDetailView.as_view(), name='location_detail'), + path('news-article//', views.NewsArticleDetailView.as_view(), name='news_detail'), path('menu//', views.MenuDetailView.as_view(), name='menu_detail'), + path('comment//', views.CommentDetailView.as_view(), name='comment_detail'), + + # update-view routes + path('location//edit/', views.LocationUpdateView.as_view(), name='location_update'), + path('news-artice//edit/', views.NewsArticleUpdateView.as_view(), name='news_update'), + path('menu//edit/', views.MenuUpdateView.as_view(), name='menu_update'), + path('comment//edit/', views.CommentUpdateView.as_view(), name='comment_update'), + + # delete-view routes + path('location//delete/', views.LocationDeleteView.as_view(), name='location_delete'), + path('news-artice//delete/', views.NewsArticleDeleteView.as_view(), name='news_delete'), + path('menu//delete/', views.MenuDeleteView.as_view(), name='menu_delete'), + path('comment//delete/', views.CommentDeleteView.as_view(), name='comment_delete'), + + # like / dislike routes path('menu//like/', views.like, name='like'), path('menu//dislike/', views.dislike, name='dislike'), - path('menu//comment/', views.CommentCreateView.as_view(), name='comment'), - path('location/create/', views.LocationCreateView.as_view(), name='location_create') ] diff --git a/mensaviewer/views.py b/mensaviewer/views.py index d11481e..683ef11 100644 --- a/mensaviewer/views.py +++ b/mensaviewer/views.py @@ -1,6 +1,7 @@ -from django.views.generic import DetailView -from django.views.generic.edit import CreateView +from django.views.generic import DetailView, ListView +from django.views.generic.edit import CreateView, UpdateView, DeleteView from django.shortcuts import render, redirect, reverse +from django.urls import reverse_lazy from .models import * from .helpers import * @@ -8,16 +9,36 @@ from .forms import * from .data import * -def home(request): +def flensburg(request): filter_query = request.COOKIES.get('filter_query', '') if len(request.GET.getlist('filterform')) == 0 and filter_query != '': - return redirect(reverse('mensaviewer:home') + '?' + filter_query) + return redirect(reverse('mensaviewer:flensburg') + '?' + filter_query) + + checked_types = request.GET.getlist('type') + status = request.GET.get('status') + selected_locations = Location.objects.filter(mensa_id__in=[1, 6]) + context = { + 'types': [(TYPES[type], type) for type in TYPES], + 'checked_types': checked_types, + 'status_values': STATUS_VALUES, + 'status': status, + 'locations': Location.objects.all(), + 'menu_data': load_data(selected_locations, checked_types, status), + } + response = render(request, "flensburg.html", context) + response.set_cookie('filter_query', request.GET.urlencode()) + return response + + +def custom(request): + filter_query = request.COOKIES.get('filter_query', '') + if len(request.GET.getlist('filterform')) == 0 and filter_query != '': + return redirect(reverse('mensaviewer:custom') + '?' + filter_query) selected_location_ids = request.GET.getlist('location') checked_types = request.GET.getlist('type') status = request.GET.get('status') selected_locations = Location.objects.filter(mensa_id__in=selected_location_ids) - context = { 'types': [(TYPES[type], type) for type in TYPES], 'checked_types': checked_types, @@ -27,8 +48,7 @@ def home(request): 'selected_locations': selected_location_ids, 'menu_data': load_data(selected_locations, checked_types, status), } - - response = render(request, "flensburg.html", context) + response = render(request, "custom.html", context) response.set_cookie('filter_query', request.GET.urlencode()) return response @@ -38,7 +58,7 @@ def like(request, pk): menu = Menu.objects.get(pk=pk) menu.likes += 1 menu.save() - return redirect(reverse('mensaviewer:home') + '?' + request.GET.get('next')) + return redirect(request.GET.get('next')) def dislike(request, pk): @@ -46,30 +66,155 @@ def dislike(request, pk): menu = Menu.objects.get(pk=pk) menu.likes -= 1 menu.save() - return redirect(reverse('mensaviewer:home') + '?' + request.GET.get('next')) + return redirect(request.GET.get('next')) -class MenuDetailView(DetailView): - model = Menu - template_name = "menu_detail.html" - queryset = Menu.objects.all() class LocationCreateView(CreateView): model = Location + template_name = "location/edit.html" + fields = '__all__' + success_url = reverse_lazy("mensaviewer:location_list") + + +class LocationUpdateView(UpdateView): + model = Location + template_name = "location/edit.html" fields = '__all__' - template_name = "create_location.html" - success_url = "/" + success_url = reverse_lazy("mensaviewer:location_list") + + +class LocationDeleteView(DeleteView): + model = Location + template_name = "location/delete.html" + success_url = reverse_lazy("mensaviewer:location_list") + + +class LocationDetailView(DetailView): + model = Location + template_name = "location/detail.html" + + +class LocationListView(ListView): + model = Location + template_name = "location/list.html" + + + + +class NewsArticleCreateView(CreateView): + model = NewsArticle + template_name = "news/edit.html" + fields = ['location', 'title', 'author', 'text'] + success_url = reverse_lazy("mensaviewer:news_list") + + def get_initial(self): + if 'pk' in self.kwargs: + return { 'location': get_object_or_404(Location, pk=self.kwargs['pk']) } + else: + return { 'location': None } + + +class NewsArticleUpdateView(UpdateView): + model = NewsArticle + template_name = "news/edit.html" + fields = ['location', 'title', 'author', 'text'] + success_url = reverse_lazy("mensaviewer:news_list") + + +class NewsArticleDeleteView(DeleteView): + model = NewsArticle + template_name = "news/delete.html" + success_url = reverse_lazy("mensaviewer:news_list") + + +class NewsArticleDetailView(DetailView): + model = NewsArticle + template_name = "news/detail.html" + + +class NewsArticleListView(ListView): + model = NewsArticle + template_name = "news/list.html" + + + + +class MenuCreateView(CreateView): + model = Menu + form_class = MenuForm + template_name = "menu/edit.html" + success_url = reverse_lazy("mensaviewer:menu_list") + + def get_initial(self): + if 'pk' in self.kwargs: + return { 'location': get_object_or_404(Location, pk=self.kwargs['pk']) } + else: + return { 'location': None } + + +class MenuUpdateView(UpdateView): + model = Menu + form_class = MenuForm + template_name = "menu/edit.html" + success_url = reverse_lazy("mensaviewer:menu_list") + + def get_initial(self): + menu = get_object_or_404(Menu, pk=self.kwargs['pk']) + print(menu.types) + return { 'types': menu.types } + + +class MenuDeleteView(DeleteView): + model = Menu + template_name = "menu/delete.html" + success_url = reverse_lazy("mensaviewer:menu_list") + + +class MenuDetailView(DetailView): + model = Menu + template_name = "menu/detail.html" + + +class MenuListView(ListView): + model = Menu + template_name = "menu/list.html" + + class CommentCreateView(CreateView): model = Comment - fields = ['username', 'comment'] - template_name = "comment.html" - success_url = '/menu/{pk}/' - - def form_valid(self, form): - self.menu = get_object_or_404(Menu, pk=self.kwargs['pk']) - form.instance.menu = self.menu - print(self.menu) - return super().form_valid(form) + fields = ['menu', 'author', 'text'] + template_name = "comment/edit.html" + success_url = '/menu/{menu_id}/' + + def get_initial(self): + if 'pk' in self.kwargs: + return { 'menu': get_object_or_404(Menu, pk=self.kwargs['pk']) } + else: + return { 'menu': None } + + +class CommentUpdateView(UpdateView): + model = Comment + fields = ['author', 'text'] + template_name = "comment/edit.html" + success_url = '/menu/{menu_id}/' + + +class CommentDeleteView(DeleteView): + model = Comment + template_name = "comment/delete.html" + success_url = '/menu/{menu_id}/' + + +class CommentDetailView(DetailView): + model = Comment + template_name = "comment/detail.html" + + +class CommentListView(ListView): + model = Comment + template_name = "comment/list.html" diff --git a/static/base.css b/static/base.css index fb859d9..baa8f88 100644 --- a/static/base.css +++ b/static/base.css @@ -1,15 +1,170 @@ * { - font-family: monospace; + font-family: Tahoma; box-sizing: border-box; - outline: 1px solid green; - background-color: rgba(16, 16, 16, 0.1) } body { margin: 0; + background-color: #1D1D28; + color: #EEEDFF; +} + +h1, h2, h3 { + margin: 0; + padding: 1em; +} + +header { + padding-left: 12vw; + box-shadow: 0px 0px 32px rgba(0, 0, 0, 0.5); +} + +main { + display: flex; + background-color: #3E3949; +} + +nav { + border-right: 1px solid rgba(0, 0, 0, 0.2); + display: flex; + flex-direction: column; + width: 16vw; + min-width: 16em; + padding-top: 4em; +} + +nav a { + text-align: center; + font-size: 18px; + padding: 0.6em; +} + +nav a:hover { + transition: 250ms; + background-color: rgba(0, 0, 0, 0.2); +} + +nav hr { + width: 16em; + opacity: 0.1; +} + +a { + text-decoration: none; + color: #EEEDFF; +} + +a:hover { + transition: 250ms; + color: #FFEFCA; +} + +a:active { + color: #CEA716; +} + +form { + padding: 1em; + margin: 0.5em; + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 0.5em; + box-shadow: inset 0px 0px 1em rgba(0, 0, 0, 0.2); +} + +table { + width: 100%; + padding: 1em; + margin: 0.5em; + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 0.5em; + box-shadow: inset 0px 0px 1em rgba(0, 0, 0, 0.2); +} + +th { + padding: 0.5em; + color: #CEA716; + text-align: left; +} + +td { + padding: 0.5em; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 0.2em; + max-width: 30vw; +} + +.fit-width { + width: 1%; +} + +.content { + margin-left: 4vw; + margin-right: 4vw; + flex: 1; +} + +.centered-td { + text-align: center; + padding: 1em; +} + +.btn { + padding: 0.4em; + background-color: rgba(0, 0, 0, 0.2); + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 0.5em; +} + +.model-form { + display: flex; + flex-direction: column; +} + +.model-form input, .model-form textarea, .model-form select, button { + margin-top: 0.5em; + margin-bottom: 1em; + padding: 0.5em; + background-color: rgba(0, 0, 0, 0.5); + border: 1px solid rgba(0, 0, 0, 1); + border-radius: 0.5em; + color: #EEEDFF; +} + +.filter-form { + display: flex; + flex-direction: column; +} + +.filter-form .type-filter, .filter-form .status-filter, .filter-form .location-filter { + display: flex; + flex-direction: row; +} + +.filter-form label { + background-color: rgba(0, 0, 0, 0.2); + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 0.3em; + padding: 0.3em; + margin: 0.5em; + text-align: right; +} + +input[type="submit"], button { + cursor: pointer; +} + +input[type="submit"]:active, button:active { + transition: 200ms; + background-color: rgba(0, 0, 0, 0.7); + cursor: pointer; } .container { + padding: 0.3em; + margin: 0.3em; + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 0.5em; + box-shadow: inset 0px 0px 1em rgba(0, 0, 0, 0.2); display: flex; flex-flow: row wrap; } @@ -20,10 +175,31 @@ body { } .menu { + padding: 1em; + margin: 0.2em; + border-radius: 0.5em; + box-shadow: inset 0px 0px 1em rgba(0, 0, 0, 0.2); + background-color: rgba(0, 0, 0, 0.2); display: flex; flex-direction: column; } +.menu * { + margin: 0; +} + +.menu hr { + opacity: 0.2; +} + +.menu p { + font-size: 12px; +} + +.menu a { + display: inline-block; +} + .a-mensa { background-color: rgba(16, 64, 16, 0.2); }