diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..68dc517 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'webprog.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/mensaviewer/__init__.py b/mensaviewer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mensaviewer/admin.py b/mensaviewer/admin.py new file mode 100644 index 0000000..4989254 --- /dev/null +++ b/mensaviewer/admin.py @@ -0,0 +1,23 @@ +from django.contrib import admin + +from .models import * + + +@admin.register(Menu) +class MenuAdmin(admin.ModelAdmin): + pass + + +@admin.register(Comment) +class CommentAdmin(admin.ModelAdmin): + pass + + +@admin.register(Location) +class LocationAdmin(admin.ModelAdmin): + pass + + +@admin.register(Day) +class DayAdmin(admin.ModelAdmin): + pass diff --git a/mensaviewer/apps.py b/mensaviewer/apps.py new file mode 100644 index 0000000..6a1cb7e --- /dev/null +++ b/mensaviewer/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MensaviewerConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'mensaviewer' diff --git a/mensaviewer/data.py b/mensaviewer/data.py new file mode 100644 index 0000000..aefcf23 --- /dev/null +++ b/mensaviewer/data.py @@ -0,0 +1,16 @@ +STATUS_VALUES = ['Student', 'Employee', 'Guest'] +TYPES = { + 'vn': 'Vegan', + 've': 'Vegetarisch', + 'BIO': 'Bio', + 'IN': 'International', + 'MV': 'MensaVital', + 'S': 'Schwein', + 'R': 'Rind', + 'G': 'Geflügel', + 'L': 'Lamm', + 'AGS': 'Artgerechtes Schwein', + 'AGR': 'Artgerechtes Rind', + 'AGG': 'Artgerechtes Geflügel', + 'AGL': 'Artgerechtes Lamm', +} diff --git a/mensaviewer/forms.py b/mensaviewer/forms.py new file mode 100644 index 0000000..cab3579 --- /dev/null +++ b/mensaviewer/forms.py @@ -0,0 +1,11 @@ +from django import forms + +from .models import * + +from datetime import date + + +class CommentForm(forms.ModelForm): + class Meta: + model = Comment + fields = '__all__' diff --git a/mensaviewer/helpers.py b/mensaviewer/helpers.py new file mode 100644 index 0000000..f1e0569 --- /dev/null +++ b/mensaviewer/helpers.py @@ -0,0 +1,142 @@ +from django.shortcuts import get_object_or_404 +from django.core.exceptions import ObjectDoesNotExist +from django.utils.dateparse import parse_date + +from .models import * + +from collections import OrderedDict + +import datetime +import requests + + +example_json = [ +{"day": "2022-12-19", "menus": [{"art": "Mensa", "name": "Spaghetti Carbonara", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["GlW", "Mi"], "types": ["S", "IN"]}, {"art": "Mensa", "name": "Currywurst VEGAN Hot Pot(t) Karamellisierte Balsamico Zwiebeln Kartoffelspalten", "price": "4,05 € / 5,85 € / 6,55 €", "allergens": ["Sf", "Sl", "So", "Sw"], "types": ["ve", "vn"]}, {"art": "Mensa", "name": "Schupfnudeln, Schmorgemüse, Sojasoße", "price": "3,95 € / 5,75 € / 6,45 €", "allergens": ["GlW", "Se", "So"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Currywurst Pommes Frites", "price": "4,70 € / 4,70 € / 4,70 €", "allergens": ["Sf"], "types": ["AGS"]}, {"art": "Cafeteria", "name": "Hähnchenschnitzel, Knuspermantel", "price": "2,95 € / 2,95 € / 2,95 €", "allergens": ["GlW", "GlG"], "types": ["G"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}]}, +{"day": "2022-12-20", "menus": [{"art": "Mensa", "name": "Linseneintopf Baguettebrot", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["Sl", "Sw", "GlW"], "types": ["ve", "vn"]}, {"art": "Mensa", "name": "Phat Krapao Würzige Thai Soja Bolognese, Ingwer, Basilikum, Koriander, Limettenblätter, Mienudeln", "price": "2,80 € / 4,60 € / 5,30 €", "allergens": ["GlW", "GlG", "So"], "types": ["IN", "ve", "vn"]}, {"art": "Mensa", "name": "Bockwurst zum Eintopf", "price": "1,00 € / 1,10 € / 1,20 €", "allergens": [], "types": ["S"]}, {"art": "Mensa", "name": "Filipino Beef Caldereta Basmatireis", "price": "3,50 € / 5,30 € / 6,00 €", "allergens": ["Fi", "GlW", "Mi", "Sf", "So"], "types": ["G", "R", "IN"]}, {"art": "Cafeteria", "name": "Hähnchenschnitzel, Knuspermantel", "price": "2,95 € / 2,95 € / 2,95 €", "allergens": ["GlW", "GlG"], "types": ["G"]}, {"art": "Cafeteria", "name": "Currywurst Pommes Frites", "price": "4,70 € / 4,70 € / 4,70 €", "allergens": ["Sf"], "types": ["AGS"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}]}, +{"day": "2022-12-21", "menus": [{"art": "Mensa", "name": "Currywurst Hot Pot(t) Kartoffelspalten", "price": "3,90 € / 5,70 € / 6,40 €", "allergens": ["Sf", "Sl", "GlW"], "types": ["AGS"]}, {"art": "Mensa", "name": "Pasta, Kürbis- Ricotta- Soße, Walnüsse", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["GlW", "Mi", "NW"], "types": ["ve"]}, {"art": "Mensa", "name": "Rindfleischcurry, Kokos, Karotten, Koriander Basmatireis", "price": "4,10 € / 5,90 € / 6,60 €", "allergens": ["GlW", "Mi", "Sf", "So"], "types": ["R"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}]}, +{"day": "2022-12-22", "menus": [{"art": "Mensa", "name": "Spaghetti Carbonara", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["Ei", "GlW", "Mi"], "types": ["S", "IN"]}, {"art": "Mensa", "name": "Tortellini, Kicherbsen, Spitzkohl, Cashewkerne und Rosmarin", "price": "3,50 € / 5,30 € / 6,00 €", "allergens": ["GlW", "NC"], "types": ["ve", "vn"]}, {"art": "Mensa", "name": "Bockwurst zum Eintopf", "price": "", "allergens": [], "types": ["S"]}, {"art": "Mensa", "name": "Vegetarisches Schnitzel, mediterran gefüllt Kartoffelpüree Gurkensalat", "price": "3,65 € / 5,45 € / 6,15 €", "allergens": ["Ei", "GlW", "GlH", "Mi"], "types": ["ve"]}, {"art": "Mensa", "name": "Linseneintopf", "price": "2,00 € / 3,80 € / 4,50 €", "allergens": ["Sl", "Sw"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}]}, +{"day": "2022-12-23", "menus": [{"art": "Mensa", "name": "Spaghetti Carbonara", "price": "2,35 € / 4,15 € / 4,85 €", "allergens": ["Ei", "GlW", "Mi"], "types": ["S", "IN"]}, {"art": "Mensa", "name": "Tortellini, Kicherbsen, Spitzkohl, Cashewkerne und Rosmarin", "price": "3,50 € / 5,30 € / 6,00 €", "allergens": ["GlW", "NC"], "types": ["ve", "vn"]}, {"art": "Mensa", "name": "Bockwurst zum Eintopf", "price": "", "allergens": [], "types": ["S"]}, {"art": "Mensa", "name": "Vegetarisches Schnitzel, mediterran gefüllt Kartoffelpüree Gurkensalat", "price": "3,65 € / 5,45 € / 6,15 €", "allergens": ["Ei", "GlW", "GlH", "Mi"], "types": ["ve"]}, {"art": "Mensa", "name": "Linseneintopf", "price": "2,00 € / 3,80 € / 4,50 €", "allergens": ["Sl", "Sw"], "types": ["ve", "vn"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Hähnchenbruststreifen, Gouda", "price": "3,95 € / 3,95 € / 3,95 €", "allergens": ["Ei", "Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "Kartoffelgratin, Erbsen, Karotten, Gouda", "price": "3,60 € / 3,60 € / 3,60 €", "allergens": ["Ei", "Mi"], "types": ["ve"]}, {"art": "Cafeteria", "name": "Ofenkartoffel mit Sour Creme [Bio]", "price": "3,30 € / 3,30 € / 3,30 €", "allergens": ["Mi"], "types": ["ve", "BIO"]}, {"art": "Cafeteria", "name": "Ofenkartoffel Hähnchenstreifen", "price": "3,80 € / 3,80 € / 3,80 €", "allergens": ["Mi"], "types": ["G"]}, {"art": "Cafeteria", "name": "OfenkartoffelTomaten- Zwiebel- Marmelade", "price": "", "allergens": ["Sf", "Sw"], "types": ["ve", "vn"]}]}] + + +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) + 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) + + formatted_data = {} + + for day in days: + formatted_data[str(day.date)] = [] + + for day in days: + for location in locations: + menus = Menu.objects.filter(days=day, locations=location) + for menu in menus: + + + # AND or OR filter ??? + if set(checked_types).issubset(set(menu.types)): # <-- AND + + + + formatted_data[str(day.date)].append({ + 'art': menu.art, + 'name': menu.name, + '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, + 'pk': menu.pk, + }) + return formatted_data + + +def store(data, location): + for day_json in data: + 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) + + 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€" + allergens = menu_json['allergens'] + types = menu_json['types'] + + menu_exists = Menu.objects.filter(art=art, name=name, price=price, allergens=allergens, types=types).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() + + +def fetch(mensa_id: int): + res = requests.get('https://mensa.fly.dev/' + str(mensa_id)) + 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/0001_initial.py b/mensaviewer/migrations/0001_initial.py new file mode 100644 index 0000000..17b6426 --- /dev/null +++ b/mensaviewer/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# Generated by Django 4.1.4 on 2022-12-25 15:48 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Menu', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('mensa_id', models.IntegerField()), + ('date', models.CharField(max_length=10)), + ], + ), + migrations.CreateModel( + name='Meal', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=144)), + ('type', models.CharField(max_length=144)), + ('allergens', models.CharField(max_length=144)), + ('tags', models.CharField(max_length=144)), + ('likes', models.IntegerField(default=0)), + ('dislikes', models.IntegerField(default=0)), + ('price_student', models.FloatField(max_length=8)), + ('price_employee', models.FloatField(max_length=8)), + ('price_guest', models.FloatField(max_length=8)), + ('related_menus', models.ManyToManyField(to='mensaviewer.menu')), + ], + ), + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('username', models.CharField(default='anon', max_length=144)), + ('comment', models.CharField(max_length=720)), + ('related_meal', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.meal')), + ], + ), + ] diff --git a/mensaviewer/migrations/0002_alter_menu_date.py b/mensaviewer/migrations/0002_alter_menu_date.py new file mode 100644 index 0000000..c0c3094 --- /dev/null +++ b/mensaviewer/migrations/0002_alter_menu_date.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.4 on 2022-12-26 15:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='menu', + name='date', + field=models.DateField(), + ), + ] diff --git a/mensaviewer/migrations/0003_alter_menu_date.py b/mensaviewer/migrations/0003_alter_menu_date.py new file mode 100644 index 0000000..7ffaf64 --- /dev/null +++ b/mensaviewer/migrations/0003_alter_menu_date.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.4 on 2022-12-26 15:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0002_alter_menu_date'), + ] + + operations = [ + migrations.AlterField( + model_name='menu', + name='date', + field=models.DateField(max_length=10), + ), + ] diff --git a/mensaviewer/migrations/0004_day_remove_menu_date_remove_menu_mensa_id_and_more.py b/mensaviewer/migrations/0004_day_remove_menu_date_remove_menu_mensa_id_and_more.py new file mode 100644 index 0000000..1073589 --- /dev/null +++ b/mensaviewer/migrations/0004_day_remove_menu_date_remove_menu_mensa_id_and_more.py @@ -0,0 +1,88 @@ +# Generated by Django 4.1.4 on 2022-12-26 16:01 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0003_alter_menu_date'), + ] + + operations = [ + migrations.CreateModel( + name='Day', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('mensa_id', models.IntegerField()), + ('date', models.DateField(max_length=10)), + ], + ), + migrations.RemoveField( + model_name='menu', + name='date', + ), + migrations.RemoveField( + model_name='menu', + name='mensa_id', + ), + migrations.AddField( + model_name='menu', + name='allergens', + field=models.CharField(blank=True, max_length=144, null=True), + ), + migrations.AddField( + model_name='menu', + name='dislikes', + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name='menu', + name='likes', + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name='menu', + name='name', + field=models.CharField(blank=True, max_length=144, null=True), + ), + migrations.AddField( + model_name='menu', + name='price_employee', + field=models.FloatField(default=0, max_length=8), + ), + migrations.AddField( + model_name='menu', + name='price_guest', + field=models.FloatField(default=0, max_length=8), + ), + migrations.AddField( + model_name='menu', + name='price_student', + field=models.FloatField(default=0, max_length=8), + ), + migrations.AddField( + model_name='menu', + name='tags', + field=models.CharField(blank=True, max_length=144, null=True), + ), + migrations.AddField( + model_name='menu', + name='type', + field=models.CharField(blank=True, max_length=144, null=True), + ), + migrations.AlterField( + model_name='comment', + name='related_meal', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.menu'), + ), + migrations.DeleteModel( + name='Meal', + ), + migrations.AddField( + model_name='menu', + name='related_menus', + field=models.ManyToManyField(to='mensaviewer.day'), + ), + ] diff --git a/mensaviewer/migrations/0005_rename_related_menus_menu_related_days.py b/mensaviewer/migrations/0005_rename_related_menus_menu_related_days.py new file mode 100644 index 0000000..2b351bd --- /dev/null +++ b/mensaviewer/migrations/0005_rename_related_menus_menu_related_days.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.4 on 2022-12-26 21:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0004_day_remove_menu_date_remove_menu_mensa_id_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='menu', + old_name='related_menus', + new_name='related_days', + ), + ] diff --git a/mensaviewer/migrations/0006_allergen_tag_remove_menu_allergens_remove_menu_tags_and_more.py b/mensaviewer/migrations/0006_allergen_tag_remove_menu_allergens_remove_menu_tags_and_more.py new file mode 100644 index 0000000..41d2c6c --- /dev/null +++ b/mensaviewer/migrations/0006_allergen_tag_remove_menu_allergens_remove_menu_tags_and_more.py @@ -0,0 +1,50 @@ +# Generated by Django 4.1.4 on 2022-12-27 00:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0005_rename_related_menus_menu_related_days'), + ] + + operations = [ + migrations.CreateModel( + name='Allergen', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('allergen', models.CharField(blank=True, max_length=16, null=True)), + ], + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('tag', models.CharField(blank=True, max_length=16, null=True)), + ], + ), + migrations.RemoveField( + model_name='menu', + name='allergens', + ), + migrations.RemoveField( + model_name='menu', + name='tags', + ), + migrations.AlterField( + model_name='menu', + name='related_days', + field=models.ManyToManyField(related_name='menus', to='mensaviewer.day'), + ), + migrations.AddField( + model_name='menu', + name='related_allergens', + field=models.ManyToManyField(related_name='menus', to='mensaviewer.allergen'), + ), + migrations.AddField( + model_name='menu', + name='related_tags', + field=models.ManyToManyField(related_name='menus', to='mensaviewer.tag'), + ), + ] diff --git a/mensaviewer/migrations/0007_allergen_name_tag_name.py b/mensaviewer/migrations/0007_allergen_name_tag_name.py new file mode 100644 index 0000000..08f6493 --- /dev/null +++ b/mensaviewer/migrations/0007_allergen_name_tag_name.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.4 on 2023-01-02 02:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0006_allergen_tag_remove_menu_allergens_remove_menu_tags_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='allergen', + name='name', + field=models.CharField(blank=True, max_length=144, null=True), + ), + migrations.AddField( + model_name='tag', + name='name', + field=models.CharField(blank=True, max_length=144, null=True), + ), + ] diff --git a/mensaviewer/migrations/0008_rename_tag_type_and_more.py b/mensaviewer/migrations/0008_rename_tag_type_and_more.py new file mode 100644 index 0000000..d5fa164 --- /dev/null +++ b/mensaviewer/migrations/0008_rename_tag_type_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 4.1.4 on 2023-01-02 17:22 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0007_allergen_name_tag_name'), + ] + + operations = [ + migrations.RenameModel( + old_name='Tag', + new_name='Type', + ), + migrations.RenameField( + model_name='menu', + old_name='related_tags', + new_name='related_types', + ), + migrations.RenameField( + model_name='type', + old_name='tag', + new_name='type', + ), + ] diff --git a/mensaviewer/migrations/0009_rename_type_menu_art.py b/mensaviewer/migrations/0009_rename_type_menu_art.py new file mode 100644 index 0000000..f232b93 --- /dev/null +++ b/mensaviewer/migrations/0009_rename_type_menu_art.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.4 on 2023-01-03 02:20 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0008_rename_tag_type_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='menu', + old_name='type', + new_name='art', + ), + ] diff --git a/mensaviewer/migrations/0010_remove_menu_related_days_day_menus_alter_day_date_and_more.py b/mensaviewer/migrations/0010_remove_menu_related_days_day_menus_alter_day_date_and_more.py new file mode 100644 index 0000000..a6285f9 --- /dev/null +++ b/mensaviewer/migrations/0010_remove_menu_related_days_day_menus_alter_day_date_and_more.py @@ -0,0 +1,37 @@ +# Generated by Django 4.1.4 on 2023-01-03 23:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0009_rename_type_menu_art'), + ] + + operations = [ + migrations.RemoveField( + model_name='menu', + name='related_days', + ), + migrations.AddField( + model_name='day', + name='menus', + field=models.ManyToManyField(related_name='day', to='mensaviewer.menu'), + ), + migrations.AlterField( + model_name='day', + name='date', + field=models.DateField(max_length=64), + ), + migrations.AlterField( + model_name='menu', + name='related_allergens', + field=models.ManyToManyField(related_name='menu', to='mensaviewer.allergen'), + ), + migrations.AlterField( + model_name='menu', + name='related_types', + field=models.ManyToManyField(related_name='menu', to='mensaviewer.type'), + ), + ] diff --git a/mensaviewer/migrations/0011_rename_related_meal_comment_related_menu.py b/mensaviewer/migrations/0011_rename_related_meal_comment_related_menu.py new file mode 100644 index 0000000..f8a6f36 --- /dev/null +++ b/mensaviewer/migrations/0011_rename_related_meal_comment_related_menu.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.4 on 2023-01-04 03:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0010_remove_menu_related_days_day_menus_alter_day_date_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='comment', + old_name='related_meal', + new_name='related_menu', + ), + ] diff --git a/mensaviewer/migrations/0012_location_remove_day_menus_remove_menu_dislikes_and_more.py b/mensaviewer/migrations/0012_location_remove_day_menus_remove_menu_dislikes_and_more.py new file mode 100644 index 0000000..02d8036 --- /dev/null +++ b/mensaviewer/migrations/0012_location_remove_day_menus_remove_menu_dislikes_and_more.py @@ -0,0 +1,84 @@ +# Generated by Django 4.1.4 on 2023-01-04 16:57 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0011_rename_related_meal_comment_related_menu'), + ] + + operations = [ + migrations.CreateModel( + name='Location', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, max_length=144, null=True)), + ('mensa_id', models.CharField(blank=True, max_length=2, null=True)), + ], + ), + migrations.RemoveField( + model_name='day', + name='menus', + ), + migrations.RemoveField( + model_name='menu', + name='dislikes', + ), + migrations.RemoveField( + model_name='menu', + name='price_employee', + ), + migrations.RemoveField( + model_name='menu', + name='price_guest', + ), + migrations.RemoveField( + model_name='menu', + name='price_student', + ), + migrations.RemoveField( + model_name='menu', + name='related_allergens', + ), + migrations.RemoveField( + model_name='menu', + name='related_types', + ), + migrations.AddField( + model_name='menu', + name='allergens', + field=models.JSONField(blank=True, null=True), + ), + migrations.AddField( + model_name='menu', + name='day', + field=models.DateField(blank=True, null=True), + ), + migrations.AddField( + model_name='menu', + name='types', + field=models.JSONField(blank=True, null=True), + ), + migrations.AlterField( + model_name='comment', + name='related_menu', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.menu'), + ), + migrations.DeleteModel( + name='Allergen', + ), + migrations.DeleteModel( + name='Day', + ), + migrations.DeleteModel( + name='Type', + ), + migrations.AddField( + model_name='menu', + name='location', + field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='mensaviewer.location'), + ), + ] diff --git a/mensaviewer/migrations/0013_menu_price.py b/mensaviewer/migrations/0013_menu_price.py new file mode 100644 index 0000000..7de9fa5 --- /dev/null +++ b/mensaviewer/migrations/0013_menu_price.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.4 on 2023-01-04 22:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0012_location_remove_day_menus_remove_menu_dislikes_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='menu', + name='price', + field=models.CharField(blank=True, max_length=144, null=True), + ), + ] diff --git a/mensaviewer/migrations/0014_day_remove_menu_day_remove_menu_location_and_more.py b/mensaviewer/migrations/0014_day_remove_menu_day_remove_menu_location_and_more.py new file mode 100644 index 0000000..5879d1a --- /dev/null +++ b/mensaviewer/migrations/0014_day_remove_menu_day_remove_menu_location_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 4.1.4 on 2023-01-04 23:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0013_menu_price'), + ] + + operations = [ + migrations.CreateModel( + name='Day', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField(blank=True, null=True)), + ], + ), + migrations.RemoveField( + model_name='menu', + name='day', + ), + migrations.RemoveField( + model_name='menu', + name='location', + ), + migrations.AddField( + model_name='menu', + name='locations', + field=models.ManyToManyField(to='mensaviewer.location'), + ), + migrations.AddField( + model_name='menu', + name='days', + field=models.ManyToManyField(to='mensaviewer.day'), + ), + ] diff --git a/mensaviewer/migrations/0015_comment_timestamp.py b/mensaviewer/migrations/0015_comment_timestamp.py new file mode 100644 index 0000000..d670106 --- /dev/null +++ b/mensaviewer/migrations/0015_comment_timestamp.py @@ -0,0 +1,19 @@ +# Generated by Django 4.1.4 on 2023-01-05 00:43 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensaviewer', '0014_day_remove_menu_day_remove_menu_location_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='comment', + name='timestamp', + field=models.DateTimeField(blank=True, default=django.utils.timezone.now), + ), + ] diff --git a/mensaviewer/migrations/__init__.py b/mensaviewer/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mensaviewer/models.py b/mensaviewer/models.py new file mode 100644 index 0000000..a5679c1 --- /dev/null +++ b/mensaviewer/models.py @@ -0,0 +1,60 @@ +from django.db import models +from django.utils.timezone import now + +from .data import TYPES + + +class Day(models.Model): + date = models.DateField(null=True, blank=True) + + def __str__(self): + return str(self.date) + + +class Location(models.Model): + name = models.CharField(max_length=144, null=True, blank=True) + mensa_id = models.CharField(max_length=2, null=True, blank=True) + + def __str__(self): + return self.name + + +class Menu(models.Model): + art = models.CharField(max_length=144, null=True, blank=True) + name = models.CharField(max_length=144, null=True, blank=True) + price = models.CharField(max_length=144, null=True, blank=True) + allergens = models.JSONField(null=True, blank=True) + types = models.JSONField(null=True, blank=True) + likes = models.IntegerField(default=0) + locations = models.ManyToManyField(Location) + days = models.ManyToManyField(Day) + + def __str__(self): + return self.name + + @property + def get_price(self): + return { + 'Student': self.price.split(' / ')[0] or 0, + 'Employee': self.price.split(' / ')[1] or 0, + 'Guest': self.price.split(' / ')[2] or 0, + } + + @property + def get_types(self): + return ', '.join([TYPES[type] for type in self.types]) + + @property + def get_allergens(self): + return ', '.join([allergen for allergen in self.allergens]) + + @property + def comments(self): + return [comment for comment in Comment.objects.filter(related_menu=self)] + + +class Comment(models.Model): + related_menu = models.ForeignKey(Menu, on_delete=models.CASCADE) + timestamp = models.DateTimeField(default=now, blank=True) + username = models.CharField(max_length=144, default='anon') + comment = models.CharField(max_length=720) diff --git a/mensaviewer/templates/base.html b/mensaviewer/templates/base.html new file mode 100644 index 0000000..e8f51df --- /dev/null +++ b/mensaviewer/templates/base.html @@ -0,0 +1,23 @@ +{% load static %} + + + +
+ + +
{{ comment.username }}
+{{ comment.comment }}
+