diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c3e29eb..9b9949b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt python3 manage.py collectstatic --noinput - python3 manage.py collectstatic_js_reverse --noinput + python3 manage.py collectstatic_js_reverse - name: Django Testing project run: | python3 manage.py test diff --git a/cookbook/migrations/0099_auto_20210113_1518.py b/cookbook/migrations/0099_auto_20210113_1518.py new file mode 100644 index 00000000..189dfced --- /dev/null +++ b/cookbook/migrations/0099_auto_20210113_1518.py @@ -0,0 +1,19 @@ +# Generated by Django 3.1.5 on 2021-01-13 14:18 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('cookbook', '0098_auto_20210113_1320'), + ] + + operations = [ + migrations.AlterField( + model_name='cooklog', + name='created_at', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index 3c976330..eeab73fa 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -7,6 +7,7 @@ from django.contrib import auth from django.contrib.auth.models import Group, User from django.core.validators import MinLengthValidator from django.db import models +from django.utils import timezone from django.utils.translation import gettext as _ from django_random_queryset import RandomManager @@ -443,7 +444,7 @@ class InviteLink(models.Model): class CookLog(models.Model): recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE) created_by = models.ForeignKey(User, on_delete=models.CASCADE) - created_at = models.DateTimeField(auto_now_add=True) + created_at = models.DateTimeField(default=timezone.now) rating = models.IntegerField(null=True) servings = models.IntegerField(default=0) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 7f39e56d..5772131f 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -314,9 +314,14 @@ class ShareLinkSerializer(serializers.ModelSerializer): class CookLogSerializer(serializers.ModelSerializer): + def create(self, validated_data): # TODO make mixin + validated_data['created_by'] = self.context['request'].user + return super().create(validated_data) + class Meta: model = CookLog fields = '__all__' + read_only_fields = ('id', 'created_by') class ViewLogSerializer(serializers.ModelSerializer): diff --git a/cookbook/urls.py b/cookbook/urls.py index 26b6b9e8..0b1b2083 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -22,7 +22,6 @@ router.register(r'sync-log', api.SyncLogViewSet) router.register(r'keyword', api.KeywordViewSet) router.register(r'unit', api.UnitViewSet) router.register(r'food', api.FoodViewSet) - router.register(r'step', api.StepViewSet) router.register(r'recipe', api.RecipeViewSet) router.register(r'ingredient', api.IngredientViewSet) @@ -32,6 +31,7 @@ router.register(r'shopping-list', api.ShoppingListViewSet) router.register(r'shopping-list-entry', api.ShoppingListEntryViewSet) router.register(r'shopping-list-recipe', api.ShoppingListRecipeViewSet) router.register(r'view-log', api.ViewLogViewSet) +router.register(r'cook-log', api.CookLogViewSet) urlpatterns = [ path('', views.index, name='index'), @@ -47,61 +47,29 @@ urlpatterns = [ path('settings/', views.user_settings, name='view_settings'), path('history/', views.history, name='view_history'), path('offline/', views.offline, name='view_offline'), - path( - 'service-worker.js', ( - TemplateView.as_view( - template_name="service-worker.js", - content_type='application/javascript', - ) - ), - name='service_worker' - ), + path('service-worker.js', (TemplateView.as_view(template_name="service-worker.js", content_type='application/javascript', )), name='service_worker'), path('test/', views.test, name='view_test'), path('import/', import_export.import_recipe, name='view_import'), path('export/', import_export.export_recipe, name='view_export'), path('view/recipe/', views.recipe_view, name='view_recipe'), - path( - 'view/recipe//', - views.recipe_view, - name='view_recipe' - ), + path('view/recipe//', views.recipe_view, name='view_recipe'), - path( - 'new/recipe-import//', - new.create_new_external_recipe, - name='new_recipe_import' - ), + path('new/recipe-import//', new.create_new_external_recipe, name='new_recipe_import'), path('new/share-link//', new.share_link, name='new_share_link'), path('edit/recipe//', edit.switch_recipe, name='edit_recipe'), # for internal use only - path( - 'edit/recipe/internal//', - edit.internal_recipe_update, - name='edit_internal_recipe' - ), - path( - 'edit/recipe/external//', - edit.ExternalRecipeUpdate.as_view(), - name='edit_external_recipe' - ), - path( - 'edit/recipe/convert//', - edit.convert_recipe, - name='edit_convert_recipe' - ), + path('edit/recipe/internal//', edit.internal_recipe_update, name='edit_internal_recipe'), + path('edit/recipe/external//', edit.ExternalRecipeUpdate.as_view(), name='edit_external_recipe'), + path('edit/recipe/convert//', edit.convert_recipe, name='edit_convert_recipe'), path('edit/storage//', edit.edit_storage, name='edit_storage'), path('edit/ingredient/', edit.edit_ingredients, name='edit_food'), - path( - 'delete/recipe-source//', - delete.delete_recipe_source, - name='delete_recipe_source' - ), + path('delete/recipe-source//', delete.delete_recipe_source, name='delete_recipe_source'), # TODO move to generic "new" view path('data/sync', data.sync, name='data_sync'), @@ -111,51 +79,25 @@ urlpatterns = [ path('data/statistics', data.statistics, name='data_stats'), path('data/import/url', data.import_url, name='data_import_url'), - path( - 'api/get_external_file_link//', - api.get_external_file_link, - name='api_get_external_file_link' - ), - path( - 'api/get_recipe_file//', - api.get_recipe_file, - name='api_get_recipe_file' - ), + path('api/get_external_file_link//', api.get_external_file_link, name='api_get_external_file_link'), + path('api/get_recipe_file//', api.get_recipe_file, name='api_get_recipe_file'), path('api/sync_all/', api.sync_all, name='api_sync'), - path( - 'api/log_cooking//', - api.log_cooking, - name='api_log_cooking' - ), - path( - 'api/plan-ical///', - api.get_plan_ical, - name='api_get_plan_ical' - ), - path( - 'api/recipe-from-url/', api.recipe_from_url, name='api_recipe_from_url' - ), + path('api/log_cooking//', api.log_cooking, name='api_log_cooking'), + path('api/plan-ical///', api.get_plan_ical, name='api_get_plan_ical'), + path('api/recipe-from-url/', api.recipe_from_url, name='api_recipe_from_url'), path('api/backup/', api.get_backup, name='api_backup'), - path( - 'dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword' - ), + path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'), path('dal/food/', dal.IngredientsAutocomplete.as_view(), name='dal_food'), path('dal/unit/', dal.UnitAutocomplete.as_view(), name='dal_unit'), path('docs/markdown/', views.markdown_info, name='docs_markdown'), path('docs/api/', views.api_info, name='docs_api'), - path('openapi', get_schema_view( - title="Django Recipes", - version=VERSION_NUMBER - ), name='openapi-schema'), + path('openapi', get_schema_view(title="Django Recipes", version=VERSION_NUMBER), name='openapi-schema'), path('api/', include((router.urls, 'api'))), - path( - 'api-auth/', - include('rest_framework.urls', namespace='rest_framework') - ), + path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), ] diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 05a46d98..7ce7f1f5 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -49,7 +49,7 @@ from cookbook.serializer import (FoodSerializer, IngredientSerializer, StorageSerializer, SyncLogSerializer, SyncSerializer, UnitSerializer, UserNameSerializer, UserPreferenceSerializer, - ViewLogSerializer) + ViewLogSerializer, CookLogSerializer) class UserNameViewSet(viewsets.ReadOnlyModelViewSet): @@ -329,6 +329,15 @@ class ViewLogViewSet(viewsets.ModelViewSet): return queryset +class CookLogViewSet(viewsets.ModelViewSet): + queryset = CookLog.objects.all() + serializer_class = CookLogSerializer + permission_classes = [CustomIsOwner] + + def get_queryset(self): + queryset = ViewLog.objects.filter(created_by=self.request.user).all()[:5] + return queryset + # -------------- non django rest api views -------------------- def get_recipe_provider(recipe): diff --git a/vue/package.json b/vue/package.json index 15258400..df317a88 100644 --- a/vue/package.json +++ b/vue/package.json @@ -11,6 +11,7 @@ "axios": "^0.21.1", "bootstrap-vue": "^2.21.2", "core-js": "^3.6.5", + "moment": "^2.29.1", "vue": "^2.6.11", "vue-template-compiler": "^2.6.12", "vuex": "^3.6.0" diff --git a/vue/src/apps/RecipeView/RecipeView.vue b/vue/src/apps/RecipeView/RecipeView.vue index 29577fde..02d90c32 100644 --- a/vue/src/apps/RecipeView/RecipeView.vue +++ b/vue/src/apps/RecipeView/RecipeView.vue @@ -1,5 +1,6 @@