mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
comments
This commit is contained in:
46
README.md
46
README.md
@@ -1,15 +1,18 @@
|
|||||||
# Recipies
|
# 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.
|
Recipes is a Django application that allows 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.
|
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
|
## Usage
|
||||||
Most things should be straight forward but there are some more complicated things.
|
Most things should be straight forward but there are some more complicated things.
|
||||||
##### General
|
##### General
|
||||||
Create Categories and Keywords under the `New` tab. You can have a simple look at most Tables under the `List` Tab.
|
Different kinds of objects, like tags or storage backends, can be viewed under the lists tab. This is also were you create
|
||||||
Management options for your Data are under `Manage Data`
|
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
|
##### Storage Backends
|
||||||
Currently only dropbox is supported as a storage backend. To add a new Dropbox go to `New >> Storage Backend` and enter
|
Currently only dropbox is supported as a storage backend. To add a new Dropbox go to `Lists >> Storage Backend` and add a new backend.
|
||||||
a name (just a display name for you to identify it) and an API access Token for the account you want to use.
|
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)
|
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.
|
with the button on the top right.
|
||||||
##### Adding Synced Path's
|
##### 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
|
##### Syncing Data
|
||||||
To sync the recipes app with the storage backends press `Sync now` under `Manage Data >> Configure Sync`.
|
To sync the recipes app with the storage backends press `Sync now` under `Manage Data >> Configure Sync`.
|
||||||
##### Import Recipes
|
##### 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.
|
modifying them or import one by one, adding Category and Tags while importing.
|
||||||
##### Batch Edit
|
##### Batch Edit
|
||||||
If you have many uncategorized and untagged recipes you may want to edit them all at once. For this go to
|
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 category and tags.
|
`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).
|
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.
|
> Currently the only option is word contains, maybe some more SQL like operators will be added later.
|
||||||
|
|
||||||
## Installation
|
## 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)
|
### Docker-Compose
|
||||||
on deploying django applications.
|
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:
|
To start developing:
|
||||||
1. Clone the repository using your preferred method
|
1. Clone the repository using your preferred method
|
||||||
2. Install requirements from `requirements.txt` either globally or in a virtual environment
|
2. Install requirements from `requirements.txt` either globally or in a virtual environment
|
||||||
3. Copy `secret_settings.template` to `secret_settings.py`
|
3. Run migrations with `manage.py migrate`
|
||||||
4. Configure preferred database backend in `secret_settings.py`, default is sqlite
|
4. Create a first user with `manage.py createsuperuser`
|
||||||
5. Run migrations with `manage.py migrate`
|
5. Start development server with `manage.py runserver`
|
||||||
6. Create a first user with `manage.py createsuperuser`
|
|
||||||
7. Start development server with `manage.py runserver`
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Pull Requests and ideas are welcome, feel free to contribute in any way.
|
Pull Requests and ideas are welcome, feel free to contribute in any way.
|
||||||
|
|||||||
@@ -46,6 +46,19 @@ class InternalRecipeForm(forms.ModelForm):
|
|||||||
widgets = {'keywords': MultiSelectWidget}
|
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 KeywordForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Keyword
|
model = Keyword
|
||||||
|
|||||||
27
cookbook/migrations/0006_comment.py
Normal file
27
cookbook/migrations/0006_comment.py
Normal file
@@ -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')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
@@ -77,6 +78,14 @@ class RecipeIngredients(models.Model):
|
|||||||
ingredient = models.ForeignKey(Ingredients, models.PROTECT)
|
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):
|
class RecipeImport(models.Model):
|
||||||
name = models.CharField(max_length=128)
|
name = models.CharField(max_length=128)
|
||||||
storage = models.ForeignKey(Storage, on_delete=models.PROTECT)
|
storage = models.ForeignKey(Storage, on_delete=models.PROTECT)
|
||||||
|
|||||||
@@ -29,4 +29,27 @@
|
|||||||
|
|
||||||
{{ recipe.instructions | markdown | safe }}
|
{{ recipe.instructions | markdown | safe }}
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<h5>{% trans 'Comments' %}</h5>
|
||||||
|
|
||||||
|
<form method="POST" class="post-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
<input type="submit" value="Submit" class="btn btn-success">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% for c in comments %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<small class="card-title">{{ c.updated_at }} {% trans 'by' %} {{ c.created_by.username }}</small> <br/>
|
||||||
|
{{ c.text }}
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
|
from django.urls import reverse
|
||||||
from django_tables2 import RequestConfig
|
from django_tables2 import RequestConfig
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from cookbook.filters import RecipeFilter
|
from cookbook.filters import RecipeFilter
|
||||||
from cookbook.forms import *
|
from cookbook.forms import *
|
||||||
@@ -23,8 +27,26 @@ def index(request):
|
|||||||
def recipe_view(request, pk):
|
def recipe_view(request, pk):
|
||||||
recipe = get_object_or_404(Recipe, pk=pk)
|
recipe = get_object_or_404(Recipe, pk=pk)
|
||||||
ingredients = RecipeIngredients.objects.filter(recipe=recipe)
|
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):
|
def test(request):
|
||||||
|
|||||||
Reference in New Issue
Block a user