From 9a22c378623af35d44174df0155259abc2fbcacb Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Thu, 14 Nov 2019 10:06:51 +0100 Subject: [PATCH] comments --- README.md | 46 ++++++++++++++++++----------- cookbook/forms.py | 13 ++++++++ cookbook/migrations/0006_comment.py | 27 +++++++++++++++++ cookbook/models.py | 9 ++++++ cookbook/templates/recipe_view.html | 23 +++++++++++++++ cookbook/views/views.py | 24 ++++++++++++++- 6 files changed, 124 insertions(+), 18 deletions(-) create mode 100644 cookbook/migrations/0006_comment.py diff --git a/README.md b/README.md index a066adfa5..1ff1df91a 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,18 @@ # Recipies -Recipes is a Django application that allows categorization and tagging of arbitrary numbers of recipes (or in fact any other file) in a storage backend. -Currently the only supported storage backend is dropbox, but this can easily be changed as the system is modular and already has fields to support different backends. +Recipes is a Django application that allows tagging of arbitrary numbers of recipes (or in fact any other file) in a storage backend. +It also allows the easy creation of recipes directly on the page. +Currently the only supported storage backend is dropbox, but this can easily be changed as the system is modular and +already has fields to support different backends. ## Usage Most things should be straight forward but there are some more complicated things. ##### General -Create Categories and Keywords under the `New` tab. You can have a simple look at most Tables under the `List` Tab. -Management options for your Data are under `Manage Data` +Different kinds of objects, like tags or storage backends, can be viewed under the lists tab. This is also were you create +new objects by pressing the plus button. +Management options for your data, like batch edits and import logs, can be found under `Manage Data`. ##### Storage Backends -Currently only dropbox is supported as a storage backend. To add a new Dropbox go to `New >> Storage Backend` and enter -a name (just a display name for you to identify it) and an API access Token for the account you want to use. +Currently only dropbox is supported as a storage backend. To add a new Dropbox go to `Lists >> Storage Backend` and add a new backend. +Enter a name (just a display name for you to identify it) and an API access Token for the account you want to use. You can obtain the API token on [Dropboxes API explorer](https://dropbox.github.io/dropbox-api-v2-explorer/#auth_token/from_oauth1) with the button on the top right. ##### Adding Synced Path's @@ -18,28 +21,37 @@ Then enter the path you want to monitor starting at the storage root (e.g. `/Fol ##### Syncing Data To sync the recipes app with the storage backends press `Sync now` under `Manage Data >> Configure Sync`. ##### Import Recipes -All files found by the sync can be found under `List >> New Recipes`. There you can either import all at once without +All files found by the sync can be found under `Manage Data >> Import recipes`. There you can either import all at once without modifying them or import one by one, adding Category and Tags while importing. ##### Batch Edit -If you have many uncategorized and untagged recipes you may want to edit them all at once. For this go to -`Manage Data >> Batch Edit`. Enter a word which should be contained in the recipe name and select category and tags. +If you have many untagged recipes you may want to edit them all at once. For this go to +`Manage Data >> Batch Edit`. Enter a word which should be contained in the recipe name and select the tags you want to apply. When clicking submit every recipe containing the word will be updated (tags are added). > Currently the only option is word contains, maybe some more SQL like operators will be added later. ## Installation -If you want to *install* the application for usage use a tutorial of your choice -(for example this one http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html) -on deploying django applications. + +### Docker-Compose +A docker-compose file is included in the repository. It is made for setups already running an nginx-reverse proxy network with +lets encrypt companion. Copy `.env.template` to `.env` and fill in the missing values accordingly. +Now simply start the containers and run the `update.sh` script which will apply all migrations and collect static files. +Create a default user by executing into the container with `docker-compose exec web_recipes sh` and run `python3 manage.py createsuperuser`. + +### Manual +Copy `.env.template` to `.env` and fill in the missing values accordingly. +You can leave out the docker specific variables (VIRTUAL_HOST, LETSENCRYPT_HOST, LETSENCRYPT_EMAIL). +Make sure all variables are available to whatever servers your application. + +Otherwise simply follow the instructions for any django based deployment +(for example this one http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html). To start developing: 1. Clone the repository using your preferred method 2. Install requirements from `requirements.txt` either globally or in a virtual environment -3. Copy `secret_settings.template` to `secret_settings.py` -4. Configure preferred database backend in `secret_settings.py`, default is sqlite -5. Run migrations with `manage.py migrate` -6. Create a first user with `manage.py createsuperuser` -7. Start development server with `manage.py runserver` +3. Run migrations with `manage.py migrate` +4. Create a first user with `manage.py createsuperuser` +5. Start development server with `manage.py runserver` ## Contributing Pull Requests and ideas are welcome, feel free to contribute in any way. diff --git a/cookbook/forms.py b/cookbook/forms.py index f5b149480..bf906c91a 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -46,6 +46,19 @@ class InternalRecipeForm(forms.ModelForm): widgets = {'keywords': MultiSelectWidget} +class CommentForm(forms.ModelForm): + class Meta: + model = Comment + fields = ('text', ) + + labels = { + 'text': _('Add your comment: '), + } + widgets = { + 'text': forms.Textarea(attrs={'rows': 2, 'cols': 15}), + } + + class KeywordForm(forms.ModelForm): class Meta: model = Keyword diff --git a/cookbook/migrations/0006_comment.py b/cookbook/migrations/0006_comment.py new file mode 100644 index 000000000..cad0be517 --- /dev/null +++ b/cookbook/migrations/0006_comment.py @@ -0,0 +1,27 @@ +# Generated by Django 2.2.7 on 2019-11-14 08:49 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('cookbook', '0005_recipeingredients_amount'), + ] + + operations = [ + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('recipe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.Recipe')), + ], + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index f5d6c0ac4..924b78612 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -1,3 +1,4 @@ +from django.contrib.auth.models import User from django.db import models @@ -77,6 +78,14 @@ class RecipeIngredients(models.Model): ingredient = models.ForeignKey(Ingredients, models.PROTECT) +class Comment(models.Model): + recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE) + text = models.TextField() + created_by = models.ForeignKey(User, on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class RecipeImport(models.Model): name = models.CharField(max_length=128) storage = models.ForeignKey(Storage, on_delete=models.PROTECT) diff --git a/cookbook/templates/recipe_view.html b/cookbook/templates/recipe_view.html index 8be5a7a96..ea1c9d216 100644 --- a/cookbook/templates/recipe_view.html +++ b/cookbook/templates/recipe_view.html @@ -29,4 +29,27 @@ {{ recipe.instructions | markdown | safe }} +
+
+ +
{% trans 'Comments' %}
+ +
+ {% csrf_token %} + {{ form|crispy }} + +
+ + + + {% for c in comments %} +
+
+ {{ c.updated_at }} {% trans 'by' %} {{ c.created_by.username }}
+ {{ c.text }} +
+
+
+ {% endfor %} + {% endblock %} \ No newline at end of file diff --git a/cookbook/views/views.py b/cookbook/views/views.py index 96085b199..2060025cb 100644 --- a/cookbook/views/views.py +++ b/cookbook/views/views.py @@ -1,6 +1,10 @@ +from django.contrib import messages from django.contrib.auth.decorators import login_required +from django.http import HttpResponseRedirect from django.shortcuts import render, get_object_or_404 +from django.urls import reverse from django_tables2 import RequestConfig +from django.utils.translation import gettext as _ from cookbook.filters import RecipeFilter from cookbook.forms import * @@ -23,8 +27,26 @@ def index(request): def recipe_view(request, pk): recipe = get_object_or_404(Recipe, pk=pk) ingredients = RecipeIngredients.objects.filter(recipe=recipe) + comments = Comment.objects.filter(recipe=recipe) - return render(request, 'recipe_view.html', {'recipe': recipe, 'ingredients': ingredients}) + if request.method == "POST": + form = CommentForm(request.POST) + if form.is_valid(): + comment = Comment() + comment.recipe = recipe + comment.text = form.cleaned_data['text'] + comment.created_by = request.user + + comment.save() + + messages.add_message(request, messages.SUCCESS, _('Comment saved!')) + return HttpResponseRedirect(reverse('view_recipe', args=[pk])) + else: + messages.add_message(request, messages.ERROR, _('There was an error saving this comment!')) + else: + form = CommentForm() + + return render(request, 'recipe_view.html', {'recipe': recipe, 'ingredients': ingredients, 'comments': comments, 'form': form}) def test(request):