From 3fd46c94d7bb7f90683b280169341c85d258eac7 Mon Sep 17 00:00:00 2001 From: michigg Date: Thu, 22 Mar 2018 14:39:26 +0100 Subject: [PATCH 01/20] Disable non official links --- ofu_app/static/css/main.css | 6 ++++++ ofu_app/templates/base.jinja | 1 + ofu_app/templates/home.jinja | 9 +++++++-- ofu_app/templates/macros/overview_pages.jinja | 6 +++--- 4 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 ofu_app/static/css/main.css diff --git a/ofu_app/static/css/main.css b/ofu_app/static/css/main.css new file mode 100644 index 0000000..3204286 --- /dev/null +++ b/ofu_app/static/css/main.css @@ -0,0 +1,6 @@ +.disabled, .disabled:hover { + color: #999999; + cursor: not-allowed; + opacity: 0.5; + text-decoration: none; +} \ No newline at end of file diff --git a/ofu_app/templates/base.jinja b/ofu_app/templates/base.jinja index bac2e6b..0870be5 100644 --- a/ofu_app/templates/base.jinja +++ b/ofu_app/templates/base.jinja @@ -16,6 +16,7 @@ + {% block css_extra %}{% endblock %} + + {% block js_extra %}{% endblock %} + + + + + + {% block css_extra %}{% endblock %} + + + + + +{# ===== Body ===== #} + +{% block body %} +
+
+
+ {% if request.user.is_authenticated %} + + {% else %} + + {% endif %} +
+
+ {% block headline %}{% endblock %}
+
+ +
+
+
{% block bottom_nav %}{% endblock %}
+
+ {% block content %}{% endblock %} +
+ + + +
MethodRequest URLDescription
+
+
+ + {% block test %} +
+
+ Hinweis: Diese Seite dient nur zu Testzwecken. + Wir garantieren weder die Vollständigkeit, noch + die Korrektheit der dargestellten Daten. +
+
+ {% endblock %} + {% block footer %} + + + {% endblock %} +
+{% endblock %} + + + + + +{% block js_tail %}{% endblock %} + + \ No newline at end of file diff --git a/ofu_app/apps/food/tests/tests_api.py b/ofu_app/apps/food/tests/tests_api.py index 18d16a4..10a562b 100644 --- a/ofu_app/apps/food/tests/tests_api.py +++ b/ofu_app/apps/food/tests/tests_api.py @@ -4,9 +4,8 @@ from __future__ import unicode_literals from django.test import TestCase from django.urls import reverse from apps.food.models import SingleFood, Menu -from apps.food.api.serializers import MenuSerializer +from apps.food.api.v1_1.serializers import MenuSerializer from rest_framework import status -from rest_framework.test import APIRequestFactory from datetime import datetime diff --git a/ofu_app/apps/food/urls.py b/ofu_app/apps/food/urls.py index 571dfa8..f85beb9 100644 --- a/ofu_app/apps/food/urls.py +++ b/ofu_app/apps/food/urls.py @@ -13,12 +13,11 @@ Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ -from django.conf.urls import url, include from rest_framework import routers from apps.food import views, admin_views -from django.conf.urls import url, include -from apps.food.api import views as api_views +from django.conf.urls import url +from apps.food.api.v1_1 import views as api_views # API Version 1.0 apiRouter_v1 = routers.DefaultRouter() diff --git a/ofu_app/apps/food/utils/migrate_data.py b/ofu_app/apps/food/utils/migrate_data.py index 0840cfc..6d6c43e 100644 --- a/ofu_app/apps/food/utils/migrate_data.py +++ b/ofu_app/apps/food/utils/migrate_data.py @@ -2,7 +2,7 @@ import json from datetime import datetime from pprint import pprint from django.db.utils import IntegrityError -from apps.food.models import SingleFood, Menu, HappyHour, Allergene +from apps.food.models import SingleFood, Menu, HappyHour, Allergene, HappyHourLocation from apps.food.utils.parser import mensa_page_parser, fekide_happyhour_page_parser, cafete_page_parser import logging @@ -75,21 +75,22 @@ def writeStudentenwerkDataInDB(data): def writeFekideDataInDB(data): for happyhour_data in data['happyhours']: time = str(happyhour_data['time']).replace(" ", "").split("-") - happyhour, new = HappyHour.objects.get_or_create(date=datetime.strptime(data['day'], "%A, %d.%m.%Y"), - location=happyhour_data['location'], - description=happyhour_data['description'], - starttime=datetime.strptime(time[0], "%H:%M").time(), - endtime=datetime.strptime(time[1], "%H:%M").time()) - if not new: + try: + location, _ = HappyHourLocation.objects.get_or_create(name=happyhour_data['location']) + happyhour, _ = HappyHour.objects.get_or_create(location=location, + starttime=datetime.strptime(time[0], "%H:%M").time(), + endtime=datetime.strptime(time[1], "%H:%M").time()) happyhour.date = datetime.strptime(data['day'], "%A, %d.%m.%Y") - happyhour.location = happyhour_data['location'] happyhour.description = happyhour_data['description'] - happyhour.starttime = datetime.strptime(time[0], "%H:%M").time() - happyhour.endtime = datetime.strptime(time[1], "%H:%M").time() happyhour.save() - logger.info("%s: Happy Hour: Location: %s, Description: %s", - str(happyhour.date.date()), str(happyhour.location), str(happyhour.description)) + logger.info("{date}: Happy Hour: Location: {location}, Description: {description}".format( + date=happyhour.date, + location=happyhour.location, + description=happyhour.description) + ) + except Exception as e: + logger.exception(e) def writeoutDBObjects(): @@ -102,10 +103,13 @@ def writeoutDBObjects(): def delete(): happy_hours = HappyHour.objects.all() - print("Deleted following Happy Hours:") + logger.info("Deleted following Happy Hours:") for happy_hour in happy_hours: - print("%s: Happy Hour: Location: %s, Description: %s" % ( - str(happy_hour.date), str(happy_hour.location), str(happy_hour.description))) + logger.info("{date}: Happy Hour: Location: {location}, Description: {description}".format( + date=happy_hour.date, + location=happy_hour.location, + description=happy_hour.description) + ) happy_hour.delete() diff --git a/ofu_app/apps/food/views.py b/ofu_app/apps/food/views.py index 399461e..b209ecd 100644 --- a/ofu_app/apps/food/views.py +++ b/ofu_app/apps/food/views.py @@ -7,7 +7,7 @@ from django.http import HttpResponse from django.shortcuts import render from apps.food.forms import UploadImageForm -from apps.food.models import Menu, HappyHour, SingleFood, UserRating, UserFoodImage, FoodImage +from apps.food.models import Menu, HappyHour, SingleFood, UserFoodRating, UserFoodImage, FoodImage # Create your views here. @@ -100,12 +100,12 @@ def food_rating(request): rating = request.GET.get('rating', None) if food_id and rating: food = SingleFood.objects.get(id=food_id) - user_rating, created = UserRating.objects.get_or_create(user=request.user, - food=food) + user_rating, created = UserFoodRating.objects.get_or_create(user=request.user, + food=food) user_rating.rating = rating user_rating.save() - food_user_ratings = UserRating.objects.all().filter(food=food) + food_user_ratings = UserFoodRating.objects.all().filter(food=food) sum = 0 for food_user_rating in food_user_ratings: sum += food_user_rating.rating From 9b5d294703eb0a5690de4dca775c76c5198f9585 Mon Sep 17 00:00:00 2001 From: michigg Date: Wed, 28 Mar 2018 15:21:51 +0200 Subject: [PATCH 14/20] Add new api urls --- ofu_app/core/urls.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ofu_app/core/urls.py b/ofu_app/core/urls.py index e7a3e43..75d6b51 100755 --- a/ofu_app/core/urls.py +++ b/ofu_app/core/urls.py @@ -18,6 +18,7 @@ from django.conf.urls import url, include from django.contrib import admin from django.contrib.auth import views as auth_views from rest_framework import routers +from rest_framework.authtoken import views as token_auth_views from apps.food import urls as food_urls from django.conf import settings from django.conf.urls.static import static @@ -46,7 +47,17 @@ urlpatterns = [ url(r'^impressum/$', views.impressum, name='impressum'), # -- API -- + # -- Version 1.0 url(r'^api/v1/', include(api_router_v1.urls)), - url(r'^api/v1.1/', include('apps.food.api.urls')), - url(r'^api/auth/', include('rest_framework.urls', namespace='rest_framework')) + # -- Version 1.1 + url(r'^api/v1.1/', include('apps.food.api.v1_1.urls')), + url(r'^api/v1.1/', include('apps.registration.api.urls')), + + # -- Version 1.2 + url(r'^api/v1.2/', include('apps.food.api.v1_2.urls')), + url(r'^api/v1.2/', include('apps.registration.api.urls')), + + # -- Third Party APIs + url(r'^api/auth/', include('rest_framework.urls', namespace='rest_framework')), + url(r'^api/token-auth/', token_auth_views.obtain_auth_token), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) From f4dd21440ff7130854540270c75f534cfd0fe250 Mon Sep 17 00:00:00 2001 From: michigg Date: Sat, 31 Mar 2018 22:58:33 +0200 Subject: [PATCH 15/20] Update food api, fix query proplems --- ofu_app/apps/food/admin.py | 3 +- .../food/api/v1_2/serializers/__init__.py | 0 .../main_serializers.py} | 61 ++--------- .../api/v1_2/serializers/user_serializers.py | 100 ++++++++++++++++++ ofu_app/apps/food/api/v1_2/urls.py | 16 ++- ofu_app/apps/food/api/v1_2/views/__init__.py | 0 .../v1_2/{views.py => views/main_views.py} | 39 +++---- .../apps/food/api/v1_2/views/user_views.py | 59 +++++++++++ .../migrations/0013_auto_20180330_1045.py | 24 +++++ .../migrations/0014_singlefood_comments.py | 18 ++++ .../migrations/0015_auto_20180331_1427.py | 23 ++++ .../migrations/0016_auto_20180331_1446.py | 25 +++++ .../food/migrations/0017_foodimage_thumb.py | 18 ++++ .../migrations/0018_remove_foodimage_thumb.py | 17 +++ .../food/migrations/0019_foodimage_thumb.py | 19 ++++ ofu_app/apps/food/models.py | 51 ++++++--- 16 files changed, 380 insertions(+), 93 deletions(-) create mode 100644 ofu_app/apps/food/api/v1_2/serializers/__init__.py rename ofu_app/apps/food/api/v1_2/{serializers.py => serializers/main_serializers.py} (61%) create mode 100644 ofu_app/apps/food/api/v1_2/serializers/user_serializers.py create mode 100644 ofu_app/apps/food/api/v1_2/views/__init__.py rename ofu_app/apps/food/api/v1_2/{views.py => views/main_views.py} (87%) create mode 100644 ofu_app/apps/food/api/v1_2/views/user_views.py create mode 100644 ofu_app/apps/food/migrations/0013_auto_20180330_1045.py create mode 100644 ofu_app/apps/food/migrations/0014_singlefood_comments.py create mode 100644 ofu_app/apps/food/migrations/0015_auto_20180331_1427.py create mode 100644 ofu_app/apps/food/migrations/0016_auto_20180331_1446.py create mode 100644 ofu_app/apps/food/migrations/0017_foodimage_thumb.py create mode 100644 ofu_app/apps/food/migrations/0018_remove_foodimage_thumb.py create mode 100644 ofu_app/apps/food/migrations/0019_foodimage_thumb.py diff --git a/ofu_app/apps/food/admin.py b/ofu_app/apps/food/admin.py index 62f0bd6..40c25e2 100644 --- a/ofu_app/apps/food/admin.py +++ b/ofu_app/apps/food/admin.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.contrib import admin -from apps.food.models import SingleFood, Menu, HappyHour, UserFoodRating, UserFoodImage, FoodImage +from apps.food.models import SingleFood, Menu, HappyHour, UserFoodRating, UserFoodImage, FoodImage, UserFoodComment class SingleFoodInline(admin.TabularInline): @@ -24,5 +24,6 @@ admin.site.register(SingleFood) admin.site.register(HappyHour) admin.site.register(UserFoodRating) admin.site.register(UserFoodImage) +admin.site.register(UserFoodComment) admin.site.register(Menu, MenuAdmin) admin.site.register(FoodImage) diff --git a/ofu_app/apps/food/api/v1_2/serializers/__init__.py b/ofu_app/apps/food/api/v1_2/serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ofu_app/apps/food/api/v1_2/serializers.py b/ofu_app/apps/food/api/v1_2/serializers/main_serializers.py similarity index 61% rename from ofu_app/apps/food/api/v1_2/serializers.py rename to ofu_app/apps/food/api/v1_2/serializers/main_serializers.py index b5e98dd..f69e118 100644 --- a/ofu_app/apps/food/api/v1_2/serializers.py +++ b/ofu_app/apps/food/api/v1_2/serializers/main_serializers.py @@ -1,11 +1,6 @@ +from apps.food.models import Menu, SingleFood, HappyHour, Allergene, FoodImage, HappyHourLocation, UserFoodComment from rest_framework import serializers -from apps.food.models import Menu, SingleFood, HappyHour, Allergene, FoodImage, HappyHourLocation -from apps.food.models import UserFoodRating, UserFoodImage -from django.contrib.auth.models import User -from rest_framework import serializers -from rest_framework import validators - class DefaultFoodImageSerializer(serializers.Serializer): """Your data serializer, define your fields here.""" @@ -33,6 +28,12 @@ class MenusLocationsSerializer(serializers.Serializer): name = serializers.CharField() +class UserFoodCommentSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = UserFoodComment + fields = ('id', 'description', 'title') + + class AllergensSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Allergene @@ -68,10 +69,12 @@ class MinimalSingleFoodSerializer(serializers.HyperlinkedModelSerializer): class DetailedSingleFoosdSerializer(serializers.HyperlinkedModelSerializer): allergens = AllergensSerializer(many=True, read_only=True) image = DetailedFoodImageSerializer(many=False, read_only=True) + comments = UserFoodCommentSerializer(many=True, read_only=True) class Meta: model = SingleFood - fields = ('id', 'name', 'rating', 'price_student', 'price_employee', 'price_guest', 'allergens', 'image') + fields = ( + 'id', 'name', 'rating', 'price_student', 'price_employee', 'price_guest', 'allergens', 'image', 'comments') class OverviewMenuSerializer(serializers.HyperlinkedModelSerializer): @@ -109,47 +112,3 @@ class HappyHourLocationSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = HappyHourLocation fields = ('id', 'name') - - -# --------------------------- User -------------------------------------------- -class UserFoodImageSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = UserFoodImage - fields = ('id', 'image_image', 'image_thumb') - - -class UserFoodRatingSerializer(serializers.ModelSerializer): - # food = MinimalSingleFoodSerializer(many=False, read_only=False) - - class Meta: - model = UserFoodRating - fields = ('id', 'rating') - - def run_validators(self, value): - for validator in self.validators: - if isinstance(validator, validators.UniqueTogetherValidator): - self.validators.remove(validator) - super(UserFoodRatingSerializer, self).run_validators(value) - - def create(self, validated_data): - # TODO: Custom exception handler - rating = validated_data.pop('rating') - if rating >= 1 or rating <= 5: - food_id = self.context.get('food_id') - # user = self.context['request'].user - user = User.objects.get(id=1) - food = SingleFood.objects.get(id=food_id) - user_rating, _ = UserFoodRating.objects.get_or_create(food=food, user=user) - user_rating.rating = rating - user_rating.save() - - food_user_ratings = UserFoodRating.objects.all().filter(food=food) - sum = 0 - for food_user_rating in food_user_ratings: - sum += food_user_rating.rating - - food.rating = sum / food_user_ratings.count() - food.save() - return user_rating - else: - raise ValueError diff --git a/ofu_app/apps/food/api/v1_2/serializers/user_serializers.py b/ofu_app/apps/food/api/v1_2/serializers/user_serializers.py new file mode 100644 index 0000000..032cf7f --- /dev/null +++ b/ofu_app/apps/food/api/v1_2/serializers/user_serializers.py @@ -0,0 +1,100 @@ +from apps.food.models import Menu, SingleFood +from apps.food.models import UserFoodRating, UserFoodImage, UserFoodComment, FoodImage +from django.contrib.auth.models import User +from rest_framework import validators +from rest_framework import serializers +from django.db.utils import IntegrityError + + +class UserFoodImageSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = UserFoodImage + fields = ('id', 'image_image', 'image_thumb') + + +class UserFoodCommentSerializer(serializers.ModelSerializer): + class Meta: + model = UserFoodComment + fields = ('id', 'title', 'description') + + def run_validators(self, value): + for validator in self.validators: + if isinstance(validator, validators.UniqueTogetherValidator): + self.validators.remove(validator) + super(UserFoodCommentSerializer, self).run_validators(value) + + def create(self, validated_data): + comment_title = validated_data.pop('title') + comment_description = validated_data.pop('description') + food_id = self.context.get('food_id') + user = self.context['request'].user + food = SingleFood.objects.get(id=food_id) + + user_comment, _ = UserFoodComment.objects.get_or_create(food=food, user=user) + user_comment.title = comment_title + user_comment.description = comment_description + user_comment.save() + return user_comment + + +class UserFoodRatingSerializer(serializers.ModelSerializer): + class Meta: + model = UserFoodRating + fields = ('id', 'rating') + + def run_validators(self, value): + for validator in self.validators: + if isinstance(validator, validators.UniqueTogetherValidator): + self.validators.remove(validator) + super(UserFoodRatingSerializer, self).run_validators(value) + + def create(self, validated_data): + # TODO: Custom exception handler + rating = validated_data.pop('rating') + if rating >= 1 or rating <= 5: + food_id = self.context.get('food_id') + user = self.context['request'].user + food = SingleFood.objects.get(id=food_id) + user_rating, _ = UserFoodRating.objects.get_or_create(food=food, user=user) + user_rating.rating = rating + user_rating.save() + + food_user_ratings = UserFoodRating.objects.all().filter(food=food) + sum = 0 + for food_user_rating in food_user_ratings: + sum += food_user_rating.rating + + food.rating = sum / food_user_ratings.count() + food.save() + return user_rating + else: + raise ValueError + + +class UserFoodImageSerializer(serializers.ModelSerializer): + class Meta: + model = FoodImage + fields = ('id', 'image') + + def run_validators(self, value): + for validator in self.validators: + if isinstance(validator, validators.UniqueTogetherValidator): + self.validators.remove(validator) + super(UserFoodImageSerializer, self).run_validators(value) + + def create(self, validated_data): + # TODO: Custom exception handler + food_id = self.context.get('food_id') + food = SingleFood.objects.get(id=food_id) + user = self.context['request'].user + image = validated_data.pop('image') + food_image = FoodImage.objects.create(image=image) + food_image.save() + try: + user_food_image = UserFoodImage.objects.create(user=user, food=food, image=food_image) + user_food_image.save() + except IntegrityError as err: + user_food_image = UserFoodImage.objects.get(user=user, food=food) + user_food_image.image = food_image + user_food_image.save() + return food_image diff --git a/ofu_app/apps/food/api/v1_2/urls.py b/ofu_app/apps/food/api/v1_2/urls.py index 25b8669..89dca3a 100644 --- a/ofu_app/apps/food/api/v1_2/urls.py +++ b/ofu_app/apps/food/api/v1_2/urls.py @@ -14,7 +14,8 @@ Including another URLconf 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.urls import path -from apps.food.api.v1_2 import views as api_views +from apps.food.api.v1_2.views import main_views as api_views +from apps.food.api.v1_2.views import user_views as user_api_views urlpatterns = [ # API Version 1.2 @@ -24,12 +25,17 @@ urlpatterns = [ path('food/meals/', api_views.ApiMeals.as_view(), name='meals'), path('food/meals/', api_views.ApiMeal.as_view(), name='meal'), - path('food/allergens/', api_views.ApiAllergens.as_view(), name='allergens'), + path('food/meals//comments', api_views.ApiMealComments.as_view(), name='meal-comments'), + + path('food/meals//comment', user_api_views.ApiUserFoodCommentUpload.as_view(), name='meals-comment-upload'), + path('food/meals//rating', user_api_views.ApiFoodRatingUpload.as_view(), name='meals-rating-upload'), + path('food/meals//image', user_api_views.ApiFoodImageUpload.as_view(), name='meals-image-upload'), + path('food/meals/image', user_api_views.ApiFoodImageUpload.as_view(), name='meals-image-upload'), + path('food/meals/images/', api_views.ApiFoodImages.as_view(), name='images'), path('food/meals/images/default', api_views.ApiFoodImagesDefault.as_view(), name='images-default'), - path('food/meals//rating', api_views.ApiFoodRatingUpload.as_view(), name='meals-rating-upload'), - # path('food/meals//image', api_views.ApiFoodImagesDefault.as_view(), name='meals-image-upload'), - # path('food/meals//comment', api_views.ApiFoodImagesDefault.as_view(), name='meals-comment-upload'), + + path('food/allergens/', api_views.ApiAllergens.as_view(), name='allergens'), path('food/happy-hours/', api_views.ApiHappyHours.as_view(), name='happy-hours'), path('food/happy-hours/', api_views.ApiHappyHours.as_view(), name='happy-hours'), diff --git a/ofu_app/apps/food/api/v1_2/views/__init__.py b/ofu_app/apps/food/api/v1_2/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ofu_app/apps/food/api/v1_2/views.py b/ofu_app/apps/food/api/v1_2/views/main_views.py similarity index 87% rename from ofu_app/apps/food/api/v1_2/views.py rename to ofu_app/apps/food/api/v1_2/views/main_views.py index b5cbf63..c5cf761 100644 --- a/ofu_app/apps/food/api/v1_2/views.py +++ b/ofu_app/apps/food/api/v1_2/views/main_views.py @@ -6,18 +6,19 @@ from django.templatetags.static import static from datetime import datetime from datetime import timedelta -from apps.food.api.v1_2.serializers import OverviewMenuSerializer, DetailMenuSerializer, MenusLocationsSerializer -from apps.food.api.v1_2.serializers import OverviewSingleFoodSerializer, DetailedSingleFoosdSerializer, \ - AllergensSerializer, DetailedFoodImageSerializer, DefaultFoodImageSerializer, MinimalSingleFoodSerializer -from apps.food.api.v1_2.serializers import HappyHourSerializer, HappyHourLocationSerializer -from apps.food.api.v1_2.serializers import UserFoodRatingSerializer -from apps.food.models import Menu, SingleFood, Allergene, HappyHour, HappyHourLocation, FoodImage, UserFoodRating +from apps.food.api.v1_2.serializers.main_serializers import OverviewMenuSerializer, DetailMenuSerializer, \ + MenusLocationsSerializer +from apps.food.api.v1_2.serializers.main_serializers import OverviewSingleFoodSerializer, DetailedSingleFoosdSerializer, \ + AllergensSerializer, DetailedFoodImageSerializer, DefaultFoodImageSerializer, MinimalSingleFoodSerializer, \ + UserFoodCommentSerializer +from apps.food.api.v1_2.serializers.main_serializers import HappyHourSerializer, HappyHourLocationSerializer +from apps.food.models import Menu, SingleFood, Allergene, HappyHour, HappyHourLocation, FoodImage, UserFoodRating, \ + UserFoodComment from rest_framework import generics from rest_framework.decorators import permission_classes, api_view, authentication_classes from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework import views, status from rest_framework.response import Response -from rest_framework.authentication import TokenAuthentication from rest_framework.exceptions import ValidationError @@ -128,6 +129,15 @@ class ApiMenusLocations(views.APIView): return Response(results, status=status.HTTP_200_OK) +@permission_classes((AllowAny,)) +class ApiMealComments(generics.ListAPIView): + serializer_class = UserFoodCommentSerializer + + def get_queryset(self): + food_id = self.kwargs['pk'] + return UserFoodComment.objects.filter(food_id=food_id) + + @permission_classes((AllowAny,)) class ApiHappyHours(generics.ListAPIView): serializer_class = HappyHourSerializer @@ -209,18 +219,3 @@ class ApiFoodImagesDefault(views.APIView): default_image = {'image': request.build_absolute_uri(static('img/food/default.jpg'))} results = DefaultFoodImageSerializer(default_image, many=False).data return Response(results, status=status.HTTP_200_OK) - - -@authentication_classes((TokenAuthentication,)) -@permission_classes((IsAuthenticated,)) -class ApiFoodRatingUpload(generics.CreateAPIView): - serializer_class = UserFoodRatingSerializer - queryset = UserFoodRating.objects.all() - - def get_serializer_context(self): - context = super(ApiFoodRatingUpload, self).get_serializer_context() - context.update({ - "food_id": self.kwargs['pk'], - # extra data - }) - return context diff --git a/ofu_app/apps/food/api/v1_2/views/user_views.py b/ofu_app/apps/food/api/v1_2/views/user_views.py new file mode 100644 index 0000000..51e9fb4 --- /dev/null +++ b/ofu_app/apps/food/api/v1_2/views/user_views.py @@ -0,0 +1,59 @@ +from rest_framework import generics +from rest_framework.decorators import permission_classes, api_view, authentication_classes +from rest_framework.permissions import IsAuthenticated, AllowAny +from rest_framework.authentication import TokenAuthentication, SessionAuthentication +from rest_framework.parsers import FormParser, MultiPartParser + +from apps.food.models import UserFoodRating, UserFoodImage, UserFoodComment, FoodImage +from apps.food.api.v1_2.serializers.user_serializers import UserFoodRatingSerializer, UserFoodImageSerializer, \ + UserFoodCommentSerializer + + +@authentication_classes((TokenAuthentication, SessionAuthentication)) +@permission_classes((IsAuthenticated,)) +class ApiFoodRatingUpload(generics.CreateAPIView): + serializer_class = UserFoodRatingSerializer + queryset = UserFoodRating.objects.all() + + def get_serializer_context(self): + context = super(ApiFoodRatingUpload, self).get_serializer_context() + context.update({ + "food_id": self.kwargs['pk'], + }) + return context + + +@authentication_classes((TokenAuthentication, SessionAuthentication)) +@permission_classes((IsAuthenticated,)) +class ApiUserFoodCommentUpload(generics.CreateAPIView): + serializer_class = UserFoodCommentSerializer + queryset = UserFoodComment.objects.all() + + def get_serializer_context(self): + context = super(ApiUserFoodCommentUpload, self).get_serializer_context() + context.update({ + "food_id": self.kwargs['pk'], + }) + return context + + +@authentication_classes((TokenAuthentication, SessionAuthentication)) +@permission_classes((IsAuthenticated,)) +class ApiFoodImageUpload(generics.CreateAPIView): + serializer_class = UserFoodImageSerializer + queryset = FoodImage.objects.all() + + def get_serializer_context(self): + context = super(ApiFoodImageUpload, self).get_serializer_context() + context.update({ + "food_id": self.kwargs['pk'], + }) + return context +# +# @authentication_classes((TokenAuthentication,)) +# @permission_classes((IsAuthenticated,)) +# class ApiFoodImageUpload(generics.CreateAPIView): +# serializer_class = UserFoodImageSerializer +# queryset = UserFoodImage.objects.all() +# +# diff --git a/ofu_app/apps/food/migrations/0013_auto_20180330_1045.py b/ofu_app/apps/food/migrations/0013_auto_20180330_1045.py new file mode 100644 index 0000000..7b40158 --- /dev/null +++ b/ofu_app/apps/food/migrations/0013_auto_20180330_1045.py @@ -0,0 +1,24 @@ +# Generated by Django 2.0.1 on 2018-03-30 10:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0012_auto_20180326_2343'), + ] + + operations = [ + migrations.RenameField( + model_name='userfoodcomment', + old_name='comment', + new_name='description', + ), + migrations.AddField( + model_name='userfoodcomment', + name='title', + field=models.CharField(default='Test', max_length=128), + preserve_default=False, + ), + ] diff --git a/ofu_app/apps/food/migrations/0014_singlefood_comments.py b/ofu_app/apps/food/migrations/0014_singlefood_comments.py new file mode 100644 index 0000000..b43e94e --- /dev/null +++ b/ofu_app/apps/food/migrations/0014_singlefood_comments.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-03-30 11:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0013_auto_20180330_1045'), + ] + + operations = [ + migrations.AddField( + model_name='singlefood', + name='comments', + field=models.ManyToManyField(blank=True, to='food.UserFoodComment'), + ), + ] diff --git a/ofu_app/apps/food/migrations/0015_auto_20180331_1427.py b/ofu_app/apps/food/migrations/0015_auto_20180331_1427.py new file mode 100644 index 0000000..11a9c44 --- /dev/null +++ b/ofu_app/apps/food/migrations/0015_auto_20180331_1427.py @@ -0,0 +1,23 @@ +# Generated by Django 2.0.1 on 2018-03-31 14:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0014_singlefood_comments'), + ] + + operations = [ + migrations.RemoveField( + model_name='foodimage', + name='thumb', + ), + migrations.AlterField( + model_name='foodimage', + name='image', + field=models.ImageField(default='NULL', upload_to='food/originals/%Y/%m/%W'), + preserve_default=False, + ), + ] diff --git a/ofu_app/apps/food/migrations/0016_auto_20180331_1446.py b/ofu_app/apps/food/migrations/0016_auto_20180331_1446.py new file mode 100644 index 0000000..baaf79c --- /dev/null +++ b/ofu_app/apps/food/migrations/0016_auto_20180331_1446.py @@ -0,0 +1,25 @@ +# Generated by Django 2.0.1 on 2018-03-31 14:46 + +import apps.food.models +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0015_auto_20180331_1427'), + ] + + operations = [ + migrations.AlterField( + model_name='foodimage', + name='image', + field=models.ImageField(upload_to=apps.food.models.image_path), + ), + migrations.AlterField( + model_name='singlefood', + name='image', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='food.FoodImage'), + ), + ] diff --git a/ofu_app/apps/food/migrations/0017_foodimage_thumb.py b/ofu_app/apps/food/migrations/0017_foodimage_thumb.py new file mode 100644 index 0000000..f126492 --- /dev/null +++ b/ofu_app/apps/food/migrations/0017_foodimage_thumb.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-03-31 15:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0016_auto_20180331_1446'), + ] + + operations = [ + migrations.AddField( + model_name='foodimage', + name='thumb', + field=models.ImageField(blank=True, null=True, upload_to='food/thumbs/%Y/%m/%W'), + ), + ] diff --git a/ofu_app/apps/food/migrations/0018_remove_foodimage_thumb.py b/ofu_app/apps/food/migrations/0018_remove_foodimage_thumb.py new file mode 100644 index 0000000..e205cce --- /dev/null +++ b/ofu_app/apps/food/migrations/0018_remove_foodimage_thumb.py @@ -0,0 +1,17 @@ +# Generated by Django 2.0.1 on 2018-03-31 15:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0017_foodimage_thumb'), + ] + + operations = [ + migrations.RemoveField( + model_name='foodimage', + name='thumb', + ), + ] diff --git a/ofu_app/apps/food/migrations/0019_foodimage_thumb.py b/ofu_app/apps/food/migrations/0019_foodimage_thumb.py new file mode 100644 index 0000000..d4fd788 --- /dev/null +++ b/ofu_app/apps/food/migrations/0019_foodimage_thumb.py @@ -0,0 +1,19 @@ +# Generated by Django 2.0.1 on 2018-03-31 16:09 + +import apps.food.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0018_remove_foodimage_thumb'), + ] + + operations = [ + migrations.AddField( + model_name='foodimage', + name='thumb', + field=models.ImageField(blank=True, null=True, upload_to=apps.food.models.thumb_path), + ), + ] diff --git a/ofu_app/apps/food/models.py b/ofu_app/apps/food/models.py index 2aa9453..6e74977 100644 --- a/ofu_app/apps/food/models.py +++ b/ofu_app/apps/food/models.py @@ -3,6 +3,8 @@ from __future__ import unicode_literals import os from io import BytesIO +import uuid +from _datetime import datetime from PIL import Image from django.conf import settings @@ -19,9 +21,22 @@ MAX_FOOD_PRICE_LENGTH = 10 MAX_FOOD_ALLERGENNAME_LENGTH = 256 MAX_HAPPY_HOUR_LOCATION_LENGTH = 256 MAX_HAPPY_HOUR_DESCRIPTION_LENGTH = 1024 +MAX_FOOD_COMMENT_TITLE_LENGTH = 128 MAX_FOOD_COMMENT_LENGTH = 2048 +def image_path(instance, filename): + extension = filename.split('.')[-1] + date = datetime.now().strftime('%Y/%m/%W') + return 'food/originals/{}/{}.{}'.format(date, uuid.uuid4(), extension) + + +def thumb_path(instance, filename): + extension = filename.split('.')[-1] + date = datetime.now().strftime('%Y/%m/%W') + return 'food/thumbs/{}/{}.{}'.format(date, uuid.uuid4(), 'jpg') + + # Create your models here. class Menu(models.Model): ERBA = 'ERBA' @@ -56,9 +71,10 @@ class SingleFood(models.Model): price_student = models.CharField(max_length=MAX_FOOD_PRICE_LENGTH, blank=True, null=True) price_employee = models.CharField(max_length=MAX_FOOD_PRICE_LENGTH, blank=True, null=True) price_guest = models.CharField(max_length=MAX_FOOD_PRICE_LENGTH, blank=True, null=True) - image = models.ForeignKey('FoodImage', on_delete=models.PROTECT, blank=True, null=True) + image = models.ForeignKey('FoodImage', on_delete=models.SET_NULL, blank=True, null=True) rating = models.FloatField(default=0) allergens = models.ManyToManyField("Allergene", blank=True) + comments = models.ManyToManyField('UserFoodComment', blank=True) def __str__(self): return "%s - Rating: %f - Student Price: %s" % (self.name, self.rating, self.price_student) @@ -125,25 +141,27 @@ class UserFoodComment(models.Model): id = models.AutoField(primary_key=True) user = models.ForeignKey(User, on_delete=models.PROTECT, unique=False) food = models.ForeignKey(SingleFood, on_delete=models.PROTECT) - comment = models.CharField(max_length=MAX_FOOD_COMMENT_LENGTH) + title = models.CharField(max_length=MAX_FOOD_COMMENT_TITLE_LENGTH, null=False, blank=False) + description = models.CharField(max_length=MAX_FOOD_COMMENT_LENGTH, null=False, blank=False) class Meta: unique_together = ('user', 'food') def __str__(self): - return "User: %s - Food: %s" % (self.user.username, self.food.name) + return "User: %s - Title: %s" % (self.user.username, self.title) class FoodImage(models.Model): id = models.AutoField(primary_key=True) - image = models.ImageField(upload_to='food/originals/%Y/%m/%W', blank=True, null=True) - thumb = models.ImageField(upload_to='food/thumbs/%Y/%m/%W', blank=True, null=True) + image = models.ImageField(upload_to=image_path, blank=False, null=False) + thumb = models.ImageField(upload_to=thumb_path, blank=True, null=True) - def save(self, force_update=False, force_insert=False, thumb_size=(640, 480)): + def save(self, *args, **kwargs): image = Image.open(self.image) if image.mode not in ('L', 'RGB'): image = image.convert('RGB') + thumb_size = (128, 128) image.thumbnail(thumb_size, Image.ANTIALIAS) # save the thumbnail to memory @@ -156,12 +174,17 @@ class FoodImage(models.Model): temp_handle.read(), content_type='image/jpg') - self.thumb.save('%s_thumbnail.%s' % (self.id, 'jpg'), suf, save=False) - # save the image object - self.image.name = "%s_original.%s" % (self.id, 'jpg') - super(FoodImage, self).save(force_update, force_insert) + # self.thumb.save('%s_thumbnail.%s' % (self.id, 'jpg'), suf, save=False) + self.thumb.save(name='', content=suf, save=False) - def delete(self, using=None, keep_parents=False): - os.remove(os.path.join(settings.MEDIA_ROOT, self.image.name)) - os.remove(os.path.join(settings.MEDIA_ROOT, self.thumb.name)) - super(FoodImage, self).delete() + # save the image object + super(FoodImage, self).save(*args, **kwargs) + + # + # def delete(self, using=None, keep_parents=False): + # os.remove(os.path.join(settings.MEDIA_ROOT, self.image.name)) + # os.remove(os.path.join(settings.MEDIA_ROOT, self.thumb.name)) + # super(FoodImage, self).delete() + + def __str__(self): + return "Image: %s" % (str(self.image)) From c6e0418a3421d50a3f3beb542bcb675e998e5ce9 Mon Sep 17 00:00:00 2001 From: michigg Date: Sat, 31 Mar 2018 22:59:26 +0200 Subject: [PATCH 16/20] Implement djoser --- ofu_app/core/settings.py | 22 +++++++++++++++++++++- ofu_app/core/urls.py | 4 +++- ofu_app/requirements.txt | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ofu_app/core/settings.py b/ofu_app/core/settings.py index 7ad5c41..64e121f 100755 --- a/ofu_app/core/settings.py +++ b/ofu_app/core/settings.py @@ -43,6 +43,7 @@ INSTALLED_APPS = [ 'apps.registration', 'rest_framework', 'rest_framework.authtoken', + 'djoser', 'analytical', 'corsheaders', ] @@ -50,9 +51,14 @@ INSTALLED_APPS = [ SITE_ID = 1 REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework.authentication.BasicAuthentication', + 'rest_framework.authentication.SessionAuthentication', + 'rest_framework.authentication.TokenAuthentication', + ), 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', - 'rest_framework.authentication.TokenAuthentication' + 'rest_framework.authentication.TokenAuthentication', ], } MIDDLEWARE = [ @@ -232,3 +238,17 @@ CORS_ORIGIN_ALLOW_ALL = False CORS_ORIGIN_WHITELIST = ( 'localhost:3000', ) + +DJOSER = { + 'SEND_ACTIVATION_EMAIL': True, + 'PASSWORD_RESET_CONFIRM_URL': '/#/password-reset/confirm/{uid}/{token}', + 'PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND': True, + # re_new_password + 'PASSWORD_RESET_CONFIRM_RETYPE': True, + 'SET_PASSWORD_RETYPE': True, + 'ACTIVATION_URL': '/#/activation/{uid}/{token}', +} + +# TODO: env vars +DOMAIN = 'localhost:3000' +SITE_NAME = 'BaStA' diff --git a/ofu_app/core/urls.py b/ofu_app/core/urls.py index 75d6b51..c48cc98 100755 --- a/ofu_app/core/urls.py +++ b/ofu_app/core/urls.py @@ -13,6 +13,7 @@ Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ + from core import views from django.conf.urls import url, include from django.contrib import admin @@ -59,5 +60,6 @@ urlpatterns = [ # -- Third Party APIs url(r'^api/auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^api/token-auth/', token_auth_views.obtain_auth_token), + url(r'^api/token-auth/', include('djoser.urls')), + url(r'^api/token-auth/', include('djoser.urls.authtoken')), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/ofu_app/requirements.txt b/ofu_app/requirements.txt index b5750cc..5f14e65 100644 --- a/ofu_app/requirements.txt +++ b/ofu_app/requirements.txt @@ -11,4 +11,4 @@ beautifulsoup4==4.6.0 xmltodict==0.11.0 coverage==3.6 django-cors-headers - +djoser==1.1.5 \ No newline at end of file From df7649c3e6d1649a84e5c078101cb98fb5558ff1 Mon Sep 17 00:00:00 2001 From: michigg Date: Sat, 31 Mar 2018 23:00:07 +0200 Subject: [PATCH 17/20] Update comment, image, rating endpoints --- ofu_app/apps/registration/api/serializers.py | 6 ++-- ofu_app/apps/registration/api/urls.py | 6 ++-- ofu_app/apps/registration/api/views.py | 33 ++++++++++++++++++-- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/ofu_app/apps/registration/api/serializers.py b/ofu_app/apps/registration/api/serializers.py index 76ca69f..c901e9b 100644 --- a/ofu_app/apps/registration/api/serializers.py +++ b/ofu_app/apps/registration/api/serializers.py @@ -1,6 +1,7 @@ from rest_framework import serializers from django.contrib.auth.models import User from apps.food.models import UserFoodRating, UserFoodImage, UserFoodComment, SingleFood, FoodImage +from apps.food.api.v1_2.serializers.main_serializers import MinimalSingleFoodSerializer class FoodImageSerializer(serializers.HyperlinkedModelSerializer): @@ -11,10 +12,11 @@ class FoodImageSerializer(serializers.HyperlinkedModelSerializer): class UserFoodImageSerializer(serializers.HyperlinkedModelSerializer): image = FoodImageSerializer(many=False, read_only=True) + food = MinimalSingleFoodSerializer(many=False, read_only=True) class Meta: model = UserFoodImage - fields = ('id', 'image') + fields = ('id', 'food', 'image') class SingleFoodSerializer(serializers.HyperlinkedModelSerializer): @@ -44,7 +46,7 @@ class UserCommentsSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = UserFoodComment - fields = ('id', 'food', 'comment') + fields = ('id', 'food', 'description', 'title') class UserInformationSerializer(serializers.HyperlinkedModelSerializer): diff --git a/ofu_app/apps/registration/api/urls.py b/ofu_app/apps/registration/api/urls.py index 9b1b857..22f901c 100644 --- a/ofu_app/apps/registration/api/urls.py +++ b/ofu_app/apps/registration/api/urls.py @@ -20,7 +20,7 @@ from apps.food.models import Menu urlpatterns = [ # API Version 1.1 url(r'^account/$', api_views.UserInformations.as_view(), name='api-v1_1-user-information'), - url(r'^account/food/rating/$', api_views.UserRatings.as_view(), name='api-v1_1-user-rating'), - url(r'^account/food/pic/$', api_views.UserImages.as_view(), name='api-v1_1-user-image'), - url(r'^account/food/comment/$', api_views.UserComments.as_view(), name='api-v1_1-user-comment'), + url(r'^account/food/ratings/$', api_views.UserRatings.as_view(), name='api-v1_1-user-rating'), + url(r'^account/food/images/$', api_views.UserImages.as_view(), name='api-v1_1-user-image'), + url(r'^account/food/comments/$', api_views.UserComments.as_view(), name='api-v1_1-user-comment'), ] diff --git a/ofu_app/apps/registration/api/views.py b/ofu_app/apps/registration/api/views.py index 7dcb322..322c2ca 100644 --- a/ofu_app/apps/registration/api/views.py +++ b/ofu_app/apps/registration/api/views.py @@ -23,7 +23,16 @@ class UserRatings(generics.ListAPIView): def get_queryset(self): user = self.request.user - return UserFoodRating.objects.filter(user=user).order_by('food__name') + food_id = self.request.query_params.get('food_id') + queryset = UserFoodRating.objects.filter(user=user).order_by('food__name') + if food_id: + try: + queryset = queryset.filter(food_id=food_id) + except ValueError as e: + # TODO: return Exception + return [] + + return queryset @permission_classes((IsAuthenticated,)) @@ -32,7 +41,16 @@ class UserImages(generics.ListAPIView): def get_queryset(self): user = self.request.user - return UserFoodImage.objects.filter(user=user).order_by('food__name') + food_id = self.request.query_params.get('food_id') + queryset = UserFoodImage.objects.filter(user=user).order_by('food__name') + if food_id: + try: + queryset = queryset.filter(food_id=food_id) + except ValueError as e: + # TODO: return Exception + return [] + + return queryset @permission_classes((IsAuthenticated,)) @@ -41,4 +59,13 @@ class UserComments(generics.ListAPIView): def get_queryset(self): user = self.request.user - return UserFoodComment.objects.filter(user=user).order_by('food__name') + food_id = self.request.query_params.get('food_id') + queryset = UserFoodComment.objects.filter(user=user).order_by('food__name') + if food_id: + try: + queryset = queryset.filter(food_id=food_id) + except ValueError as e: + # TODO: return Exception + return [] + + return queryset From e9bc6da951dfa0c97ba73ceaa6b0f094bf77b9ab Mon Sep 17 00:00:00 2001 From: michigg Date: Sun, 1 Apr 2018 12:59:41 +0200 Subject: [PATCH 18/20] Refractor settings, Extract env variables --- ofu_app/core/settings.py | 159 ++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 84 deletions(-) diff --git a/ofu_app/core/settings.py b/ofu_app/core/settings.py index 64e121f..2714e4f 100755 --- a/ofu_app/core/settings.py +++ b/ofu_app/core/settings.py @@ -13,21 +13,81 @@ https://docs.djangoproject.com/en/1.11/ref/settings/ import os import datetime -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +DOMAIN = os.environ['DOMAIN'] + +SITE_NAME = os.environ['SITE_NAME'] +SITE_ID = 1 + +ADMINS = os.environ['ADMINS'].split() + BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = os.environ['SECRET_KEY'] -# SECURITY WARNING: don't run with debug turned on in production! DEBUG = bool(os.environ.get('DEBUG', False)) + ALLOWED_HOSTS = os.environ['ALLOWED_HOSTS'].split() -# Application definition +# Sign Up E-Mail authentication +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = os.environ['EMAIL_HOST'] +EMAIL_HOST_USER = os.environ['EMAIL_HOST_USER'] +EMAIL_HOST_PASSWORD = os.environ['EMAIL_HOST_PASSWORD'] +EMAIL_PORT = os.environ['EMAIL_PORT'] +EMAIL_USE_TLS = True +# TODO: more account with same email are possible? +ACCOUNT_EMAIL_UNIQUE = True +ACCOUNT_EMAIL_CONFIRMATION_REQUIRED = True + +# Setup support for proxy headers +USE_X_FORWARDED_HOST = True +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') + +# Media files should be stored here +MEDIA_ROOT = os.path.join(BASE_DIR, "media") +MEDIA_URL = '/media/' + +# monitoring +PIWIK_DOMAIN_PATH = os.environ['PIWIK_DOMAIN_PATH'] +PIWIK_SITE_ID = os.environ['PIWIK_SITE_ID'] + +LOGIN_REDIRECT_URL = 'home' + +# Internationalization +# https://docs.djangoproject.com/en/1.11/topics/i18n/ + +LANGUAGE_CODE = 'de' + +TIME_ZONE = 'Europe/Berlin' + +USE_I18N = True + +USE_L10N = False + +USE_TZ = True + +DATE_FORMAT = "l, d. F Y" +DATETIME_FORMAT = "l, d. F Y" +TIME_FORMAT = "H:i" + +ROOT_URLCONF = 'core.urls' +WSGI_APPLICATION = 'core.wsgi.application' + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, "static_files") +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "static"), +] + +# CORS +CORS_ORIGIN_ALLOW_ALL = False + +CORS_ORIGIN_WHITELIST = ( + 'localhost:3000', +) + +# Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', @@ -48,8 +108,6 @@ INSTALLED_APPS = [ 'corsheaders', ] -SITE_ID = 1 - REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', @@ -61,6 +119,14 @@ REST_FRAMEWORK = { 'rest_framework.authentication.TokenAuthentication', ], } +DJOSER = { + 'SEND_ACTIVATION_EMAIL': True, + 'ACTIVATION_URL': os.environ['ACTIVATION_URL'], + 'SET_PASSWORD_RETYPE': True, + 'PASSWORD_RESET_CONFIRM_RETYPE': True, + 'PASSWORD_RESET_CONFIRM_URL': os.environ['PASSWORD_RESET_CONFIRM_URL'], + 'PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND': True, +} MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', @@ -83,7 +149,6 @@ MIDDLEWARE_CLASSES = ( 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) -ROOT_URLCONF = 'core.urls' TEMPLATES = [ { 'BACKEND': 'django_jinja.backend.Jinja2', @@ -110,11 +175,8 @@ TEMPLATES = [ }, ] -WSGI_APPLICATION = 'core.wsgi.application' - # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases - DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', @@ -132,7 +194,6 @@ DATABASES = { # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators - AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', @@ -148,58 +209,9 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] -# Internationalization -# https://docs.djangoproject.com/en/1.11/topics/i18n/ - -LANGUAGE_CODE = 'de' - -TIME_ZONE = 'Europe/Berlin' - -USE_I18N = True - -USE_L10N = False - -USE_TZ = True - -DATE_FORMAT = "l, d. F Y" -DATETIME_FORMAT = "l, d. F Y" -TIME_FORMAT = "H:i" - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ -STATIC_URL = '/static/' -STATIC_ROOT = os.path.join(BASE_DIR, "static_files") -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, "static"), -] - -# Setup support for proxy headers -USE_X_FORWARDED_HOST = True -SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - -# FORCE_SCRIPT_NAME = "app" -# Media files should be stored here -MEDIA_ROOT = os.path.join(BASE_DIR, "media") -MEDIA_URL = '/media/' - -# monitoring -PIWIK_DOMAIN_PATH = 'mg-server.ddns.net/piwik' -PIWIK_SITE_ID = '1' - -LOGIN_REDIRECT_URL = 'home' - -# Sign Up E-Mail authentication -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = 'smtp.gmail.com' -EMAIL_HOST_USER = 'signup.basta@gmail.com' -EMAIL_HOST_PASSWORD = '1\SL^QzlSuP<`8gkP4Fd' -EMAIL_PORT = '587' -EMAIL_USE_TLS = True - -ACCOUNT_EMAIL_UNIQUE = True -ACCOUNT_EMAIL_CONFIRMATION_REQUIRED = True - LOGGING = { 'version': 1, 'disable_existing_loggers': False, @@ -231,24 +243,3 @@ LOGGING = { }, }, } - -ADMINS = [('Michael Götz', 'mgoetz1995@gmail.com')] -CORS_ORIGIN_ALLOW_ALL = False - -CORS_ORIGIN_WHITELIST = ( - 'localhost:3000', -) - -DJOSER = { - 'SEND_ACTIVATION_EMAIL': True, - 'PASSWORD_RESET_CONFIRM_URL': '/#/password-reset/confirm/{uid}/{token}', - 'PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND': True, - # re_new_password - 'PASSWORD_RESET_CONFIRM_RETYPE': True, - 'SET_PASSWORD_RETYPE': True, - 'ACTIVATION_URL': '/#/activation/{uid}/{token}', -} - -# TODO: env vars -DOMAIN = 'localhost:3000' -SITE_NAME = 'BaStA' From 213496fa3ece2e05409da13531db00e43ec5114d Mon Sep 17 00:00:00 2001 From: michigg Date: Sun, 1 Apr 2018 17:35:55 +0200 Subject: [PATCH 19/20] Add logging, Refractor importer --- .../management/commands/delete_lectures.py | 13 ++++ .../donar/management/commands/delete_rooms.py | 13 ++++ .../migrations/0005_auto_20180401_1136.py | 18 +++++ .../migrations/0006_auto_20180401_1139.py | 28 ++++++++ .../migrations/0007_auto_20180401_1140.py | 18 +++++ .../migrations/0008_auto_20180401_1142.py | 28 ++++++++ .../migrations/0009_auto_20180401_1143.py | 33 +++++++++ ofu_app/apps/donar/models.py | 4 +- .../apps/donar/utils/migrate_data_lectures.py | 67 +++++++++++-------- .../apps/donar/utils/migrate_data_rooms.py | 27 ++++++-- ofu_app/apps/events/utils/migrate_data.py | 67 ++++++++----------- ofu_app/core/settings.py | 4 ++ 12 files changed, 247 insertions(+), 73 deletions(-) create mode 100644 ofu_app/apps/donar/management/commands/delete_lectures.py create mode 100644 ofu_app/apps/donar/management/commands/delete_rooms.py create mode 100644 ofu_app/apps/donar/migrations/0005_auto_20180401_1136.py create mode 100644 ofu_app/apps/donar/migrations/0006_auto_20180401_1139.py create mode 100644 ofu_app/apps/donar/migrations/0007_auto_20180401_1140.py create mode 100644 ofu_app/apps/donar/migrations/0008_auto_20180401_1142.py create mode 100644 ofu_app/apps/donar/migrations/0009_auto_20180401_1143.py diff --git a/ofu_app/apps/donar/management/commands/delete_lectures.py b/ofu_app/apps/donar/management/commands/delete_lectures.py new file mode 100644 index 0000000..444ff9a --- /dev/null +++ b/ofu_app/apps/donar/management/commands/delete_lectures.py @@ -0,0 +1,13 @@ +from django.core.management.base import BaseCommand, CommandError +from apps.donar.models import Room +from apps.donar.utils import migrate_data_lectures + + +class Command(BaseCommand): + help = "Imports Lectures from UnivIS PRG. Requires Room import" + + def add_arguments(self, parser): + pass + + def handle(self, *args, **options): + migrate_data_lectures.delete() diff --git a/ofu_app/apps/donar/management/commands/delete_rooms.py b/ofu_app/apps/donar/management/commands/delete_rooms.py new file mode 100644 index 0000000..b26763a --- /dev/null +++ b/ofu_app/apps/donar/management/commands/delete_rooms.py @@ -0,0 +1,13 @@ +from django.core.management.base import BaseCommand, CommandError +from apps.donar.models import Room +from apps.donar.utils import migrate_data_rooms + + +class Command(BaseCommand): + help = "Imports Rooms from Univis PRG" + + def add_arguments(self, parser): + pass + + def handle(self, *args, **options): + migrate_data_rooms.delete() diff --git a/ofu_app/apps/donar/migrations/0005_auto_20180401_1136.py b/ofu_app/apps/donar/migrations/0005_auto_20180401_1136.py new file mode 100644 index 0000000..5d72ed0 --- /dev/null +++ b/ofu_app/apps/donar/migrations/0005_auto_20180401_1136.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-04-01 11:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('donar', '0004_auto_20180117_0137'), + ] + + operations = [ + migrations.AlterField( + model_name='lecture', + name='short', + field=models.CharField(max_length=256), + ), + ] diff --git a/ofu_app/apps/donar/migrations/0006_auto_20180401_1139.py b/ofu_app/apps/donar/migrations/0006_auto_20180401_1139.py new file mode 100644 index 0000000..38385a7 --- /dev/null +++ b/ofu_app/apps/donar/migrations/0006_auto_20180401_1139.py @@ -0,0 +1,28 @@ +# Generated by Django 2.0.1 on 2018-04-01 11:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('donar', '0005_auto_20180401_1136'), + ] + + operations = [ + migrations.AlterField( + model_name='lecture', + name='lecturer_id', + field=models.CharField(max_length=512), + ), + migrations.AlterField( + model_name='lecture', + name='univis_id', + field=models.CharField(max_length=512, unique=True), + ), + migrations.AlterField( + model_name='lecture', + name='univis_ref', + field=models.CharField(max_length=512, unique=True), + ), + ] diff --git a/ofu_app/apps/donar/migrations/0007_auto_20180401_1140.py b/ofu_app/apps/donar/migrations/0007_auto_20180401_1140.py new file mode 100644 index 0000000..f8f72c7 --- /dev/null +++ b/ofu_app/apps/donar/migrations/0007_auto_20180401_1140.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-04-01 11:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('donar', '0006_auto_20180401_1139'), + ] + + operations = [ + migrations.AlterField( + model_name='lecture', + name='name', + field=models.CharField(max_length=512), + ), + ] diff --git a/ofu_app/apps/donar/migrations/0008_auto_20180401_1142.py b/ofu_app/apps/donar/migrations/0008_auto_20180401_1142.py new file mode 100644 index 0000000..f19cd75 --- /dev/null +++ b/ofu_app/apps/donar/migrations/0008_auto_20180401_1142.py @@ -0,0 +1,28 @@ +# Generated by Django 2.0.1 on 2018-04-01 11:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('donar', '0007_auto_20180401_1140'), + ] + + operations = [ + migrations.AlterField( + model_name='lecture', + name='lecturer_id', + field=models.CharField(max_length=1024), + ), + migrations.AlterField( + model_name='lecture', + name='univis_id', + field=models.CharField(max_length=1024, unique=True), + ), + migrations.AlterField( + model_name='lecture', + name='univis_ref', + field=models.CharField(max_length=1024, unique=True), + ), + ] diff --git a/ofu_app/apps/donar/migrations/0009_auto_20180401_1143.py b/ofu_app/apps/donar/migrations/0009_auto_20180401_1143.py new file mode 100644 index 0000000..b65e3cd --- /dev/null +++ b/ofu_app/apps/donar/migrations/0009_auto_20180401_1143.py @@ -0,0 +1,33 @@ +# Generated by Django 2.0.1 on 2018-04-01 11:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('donar', '0008_auto_20180401_1142'), + ] + + operations = [ + migrations.AlterField( + model_name='lecture', + name='lecturer_id', + field=models.CharField(max_length=256), + ), + migrations.AlterField( + model_name='lecture', + name='short', + field=models.CharField(max_length=512), + ), + migrations.AlterField( + model_name='lecture', + name='univis_id', + field=models.CharField(max_length=256, unique=True), + ), + migrations.AlterField( + model_name='lecture', + name='univis_ref', + field=models.CharField(max_length=256, unique=True), + ), + ] diff --git a/ofu_app/apps/donar/models.py b/ofu_app/apps/donar/models.py index 6450cc5..484e5da 100644 --- a/ofu_app/apps/donar/models.py +++ b/ofu_app/apps/donar/models.py @@ -11,8 +11,8 @@ MAX_COORDS_NAME_LENGTH = 256 MAX_COORDS_LENGTH = 256 MAX_LECTURE_IDS_LENGTH = 256 -MAX_LECTURE_SHORT_LENGTH = 128 -MAX_LECTURE_NAME_LENGTH = 256 +MAX_LECTURE_SHORT_LENGTH = 512 +MAX_LECTURE_NAME_LENGTH = 512 MAX_LECTURE_TYPE_LENGTH = 64 diff --git a/ofu_app/apps/donar/utils/migrate_data_lectures.py b/ofu_app/apps/donar/utils/migrate_data_lectures.py index 6b85e57..15fce8e 100644 --- a/ofu_app/apps/donar/utils/migrate_data_lectures.py +++ b/ofu_app/apps/donar/utils/migrate_data_lectures.py @@ -4,6 +4,9 @@ import json from pprint import pprint from django.db.utils import IntegrityError from apps.donar.utils.parser import univis_lectures_parser +import logging + +logger = logging.getLogger(__name__) # CONFIG Fakultaet FAKULTAET_GuK = "Fakult%E4t%20Geistes-%20und%20Kulturwissenschaften" @@ -32,38 +35,35 @@ def writeUnivisLectureTermsInDB(lecture, lecture_obj): if type(lecture['terms']['term']) == list: for term in lecture['terms']['term']: try: - term_obj = Lecture_Terms.objects.create() starttime = "00:00" + term_obj = Lecture_Terms.objects.create(starttime=starttime) if 'starttime' in term: starttime = term['starttime'] term_obj.starttime = datetime.strptime(starttime, "%H:%M") + term_obj.save() if 'room' in term: room_id = term['room']['UnivISRef']['@key'] - term_obj.room = [Room.objects.get(key=room_id)] - term_obj.save() + term_obj.room.add(Room.objects.get(key=room_id)) lecture_obj.term.add(term_obj) except IntegrityError as err: - print("ROOM_ID: " + str(room_id)) - print(err.args) + logger.exception(err) else: try: - term_obj = Lecture_Terms.objects.create() univis_starttime = "00:00" + term_obj = Lecture_Terms.objects.create(starttime=univis_starttime) if 'starttime' in lecture['terms']['term']: univis_starttime = lecture['terms']['term']['starttime'] term_obj.starttime = datetime.strptime(univis_starttime, '%H:%M') + term_obj.save() if 'room' in lecture['terms']['term']: room_id = lecture['terms']['term']['room']['UnivISRef']['@key'] - pprint("Room: " + room_id) Room.objects.get(key=room_id) - term_obj.room = [Room.objects.get(key=room_id)] - + term_obj.room.add(Room.objects.get(key=room_id)) term_obj.save() lecture_obj.term.add(term_obj) except IntegrityError as err: - print("ROOM_ID: " + str(room_id)) - print(err.args) + logger.exception(err) def writeUnivisLectureDataInDB(data): @@ -91,43 +91,56 @@ def writeUnivisLectureDataInDB(data): lecture_type = lecture['type'] if 'dozs' in lecture: lecturer_id = dict(lecture['dozs']['doz']['UnivISRef'])['@key'] - print("Lecture: " + name) lecture_obj = Lecture.objects.create(univis_ref=key, univis_id=univis_id, name=name, short=short, type=lecture_type, lecturer_id=lecturer_id) writeUnivisLectureTermsInDB(lecture, lecture_obj) lecture_obj.save() + logger.info("Lecture: {}".format(lecture_obj.short)) except IntegrityError as err: - print(err.args) + logger.warning('Lecture already exists') + # logger.exception(err) return def showStatus(status: str): - print(status) - pprint("Lectures: " + str(Lecture.objects.count())) - pprint("Lecture Terms: " + str(Lecture_Terms.objects.count())) - pprint("Room: " + str(Room.objects.count())) + return "\nStatus: {status}\n\tLectures: {lectures}\n\tLecture Terms: {lecture_terms}\n\tRoom: {room}".format( + status=status, + lectures=Lecture.objects.count(), + lecture_terms=Lecture_Terms.objects.count(), + room=Room.objects.count() + ) + + +def delete(): + lectures = Lecture.objects.all() + logger.info("Deleted following Lectures:") + for lecture in lectures: + logger.info("Lecture: {name}".format( + name=lecture.name) + ) + lecture.delete() def main(): # get food jsons - showStatus("Start with:") + logger.info(showStatus("Start SoWi:")) writeUnivisLectureDataInDB(univis_lectures_parser.parsePage(univis_lectures(FAKULTAET_SoWi))) - pprint("----------------------------------------------------------------------------------------") + # pprint("----------------------------------------------------------------------------------------") - showStatus("After SoWi:") + logger.info(showStatus("Start GuK:")) writeUnivisLectureDataInDB(univis_lectures_parser.parsePage(univis_lectures(FAKULTAET_GuK))) - pprint("----------------------------------------------------------------------------------------") + # pprint("----------------------------------------------------------------------------------------") - showStatus("After GuK:") + logger.info(showStatus("Start HuWi:")) writeUnivisLectureDataInDB(univis_lectures_parser.parsePage(univis_lectures(FAKULTAET_HuWi))) - pprint("----------------------------------------------------------------------------------------") + # pprint("----------------------------------------------------------------------------------------") - showStatus("After HuWi:") + logger.info(showStatus("Start WIAI:")) writeUnivisLectureDataInDB(univis_lectures_parser.parsePage(univis_lectures(FAKULTAET_WIAI))) - pprint("----------------------------------------------------------------------------------------") - - showStatus("After WIAI:") + # pprint("----------------------------------------------------------------------------------------") + + logger.info(showStatus("Finished:")) if __name__ == '__main__': diff --git a/ofu_app/apps/donar/utils/migrate_data_rooms.py b/ofu_app/apps/donar/utils/migrate_data_rooms.py index 7957c82..f5ba439 100644 --- a/ofu_app/apps/donar/utils/migrate_data_rooms.py +++ b/ofu_app/apps/donar/utils/migrate_data_rooms.py @@ -6,6 +6,10 @@ from apps.donar.models import Room, Lecture_Terms, Lecture from apps.donar.utils.parser import univis_rooms_parser from apps.donar.utils.parser import univis_lectures_parser +import logging + +logger = logging.getLogger(__name__) + # CONFIG Fakultaet FAKULTAET_GuK = "Fakult%E4t%20Geistes-%20und%20Kulturwissenschaften" FAKULTAET_SoWi = "Fakult%E4t%20Sozial-%20und%20Wirtschaftswissenschaften" @@ -73,15 +77,28 @@ def writeUnivisRoomDataInDB(data): if 'description' in room: description = room['description'] - Room.objects.create(key=key, address=address, building_key=building_key, floor=floor, name=name, - orgname=orgname, short=short, size=size, description=description) + room = Room.objects.create(key=key, address=address, building_key=building_key, floor=floor, name=name, + orgname=orgname, short=short, size=size, description=description) + room.save() + logger.info('ROOM: {}'.format(room.short)) except IntegrityError as err: - pprint(err.args) + logger.warning('Room already exists') + + +def delete(): + rooms = Room.objects.all() + logger.info("Deleted following Rooms:") + for room in rooms: + logger.info("Room: {name}".format( + name=room.short) + ) + room.delete() def main(): # get food jsons - pprint("Begin: Room: " + str(Room.objects.count())) + logger.info("Start:\nRoom: {}".format(Room.objects.count())) + writeUnivisRoomDataInDB(univis_rooms_parser.parsePage(univis_rooms(FAKULTAET_GuK))) writeUnivisRoomDataInDB(univis_rooms_parser.parsePage(univis_rooms(FAKULTAET_SoWi))) writeUnivisRoomDataInDB(univis_rooms_parser.parsePage(univis_rooms(FAKULTAET_HuWi))) @@ -102,7 +119,7 @@ def main(): writeUnivisRoomDataInDB(univis_rooms_parser.parsePage(univis_rooms_loc("d"))) writeUnivisRoomDataInDB(univis_rooms_parser.parsePage(univis_rooms_loc("x"))) - pprint("Now: Room: " + str(Room.objects.count())) + logger.info("Finished:\nRoom: {}".format(Room.objects.count())) if __name__ == '__main__': diff --git a/ofu_app/apps/events/utils/migrate_data.py b/ofu_app/apps/events/utils/migrate_data.py index b1f462a..685816c 100644 --- a/ofu_app/apps/events/utils/migrate_data.py +++ b/ofu_app/apps/events/utils/migrate_data.py @@ -7,6 +7,9 @@ from apps.events.utils.parser import univis_eventpage_parser from apps.events.utils.parser import fekide_eventpage_parser from apps.events.models import Event, Location +import logging + +logger = logging.getLogger(__name__) UNIVIS_CATEGORY = 'Univis' @@ -20,32 +23,17 @@ UNIVIS_RPG_WIAI = "http://univis.uni-bamberg.de/prg?search=events&department=Fak def writeFekideDataInDB(data): for date in data['dates']: for event in date['events']: - try: - Location.objects.create(name=event['location']) - except IntegrityError: - # print("Location %s already exists." % event['location']) - pass + location, _ = Location.objects.get_or_create(name=event['location']) + location.save() - try: - event_obj, new = Event.objects.get_or_create(date=datetime.strptime(date['date'], "%d.%m.%Y"), - title=event['title']) - if new: - event_obj.category = event['category'] - event_obj.link = event['link'] - event_obj.time = datetime.strptime(str(event['time']).split()[1], "%H:%M") - event_obj.locations.add(Location.objects.get(name=event['location'])) - event_obj.save() - Event.objects.filter(title="").delete() - else: - print("Event %s already exists. Start Update" % str(event_obj.title)) - event_obj.category = event['category'] - event_obj.link = event['link'] - event_obj.time = datetime.strptime(str(event['time']).split()[1], "%H:%M") - event_obj.locations.add(Location.objects.get(name=event['location'])) - event_obj.save() - except IntegrityError: - # ignored - pass + event_obj, _ = Event.objects.get_or_create(date=datetime.strptime(date['date'], "%d.%m.%Y"), + title=event['title']) + event_obj.category = event['category'] + event_obj.link = event['link'] + event_obj.time = datetime.strptime(str(event['time']).split()[1], "%H:%M") + event_obj.locations.add(Location.objects.get(name=event['location'])) + event_obj.save() + logger.info('CREATED - Event: {}'.format(event_obj.title)) def deleteUnivisObjects(): @@ -62,15 +50,13 @@ def writeUnivisLocationsInDB(rooms): for room in rooms: if '@key' in room and 'short' in room: try: - Location.objects.create(key=room['@key'], name=room['short']) - except IntegrityError: - print("Possible Duplicate! Start DB refresh") - try: - Location.objects.get(name=room['short']).key = room['@key'] - except Exception as harderr: - print("Failed to refresh object" + harderr.args) + location, _ = Location.objects.get_or_create(key=room['@key'], name=room['short']) + location.key = room['@key'] + location.name = room['short'] + location.save() + logger.info('CREATE - Location: {}'.format(location.name)) except Exception as err: - print(err.args) + logger.critical(err.args) def getLocationIDs(event): @@ -110,21 +96,24 @@ def writeUnivisEventsInDB(events: list): event_obj.orgname = event['orgname'] try: event_obj.save() + logger.info(event_obj.title) except IntegrityError: # TODO: Update DB Object if duplicate detected - print("Found Duplicate!") + logger.info("Found Duplicate!") except Exception as err: - print(err.args) + logger.exception(err.args) Event.objects.filter(title="").delete() def write_out_db_objects(): - pprint("Event: " + str(Event.objects.count())) - pprint("Location: " + str(Location.objects.count())) + return "\n\tEvent: {event}\n\tLocation: {location}".format( + event=Event.objects.count(), + location=Location.objects.count(), + ) def main(): - print("Aktueller Stand:") + logger.info("Aktueller Stand:") write_out_db_objects() # deleteUnivisObjects() @@ -139,7 +128,7 @@ def main(): writeFekideDataInDB(fekide_eventpage_parser.parsePage()) - print("Neuer Stand:") + logger.info("Neuer Stand:") write_out_db_objects() diff --git a/ofu_app/core/settings.py b/ofu_app/core/settings.py index 2714e4f..c05af6c 100755 --- a/ofu_app/core/settings.py +++ b/ofu_app/core/settings.py @@ -241,5 +241,9 @@ LOGGING = { 'handlers': ['console', 'file', 'mail_admins'], 'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'), }, + 'apps.donar.utils': { + 'handlers': ['console', 'file', 'mail_admins'], + 'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'), + }, }, } From 98e6486883b09f5eb565bbfb66f050cff9719a63 Mon Sep 17 00:00:00 2001 From: michigg Date: Tue, 3 Apr 2018 12:53:38 +0200 Subject: [PATCH 20/20] Add logging --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 6d265e6..1572a35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ WORKDIR /app EXPOSE 80 VOLUME ["/app/data"] VOLUME ["/app/media"] +VOLUME ["/app/log"] ENTRYPOINT ["python3", "manage.py"] ADD ["ofu_app", "/app"] CMD ["runserver", "0.0.0.0:80"]