lots of cleanup and refactoring
This commit is contained in:
parent
2e313f6be4
commit
a3da7c2ffd
20
cookbook/migrations/0009_auto_20191114_1800.py
Normal file
20
cookbook/migrations/0009_auto_20191114_1800.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Generated by Django 2.2.7 on 2019-11-14 17:00
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0008_auto_20191114_1046'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='recipe',
|
||||
name='created_by',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
@ -61,7 +61,7 @@ class Recipe(models.Model):
|
||||
file_path = models.CharField(max_length=512, default="")
|
||||
link = models.CharField(max_length=512, default="")
|
||||
keywords = models.ManyToManyField(Keyword, blank=True)
|
||||
created_by = models.IntegerField(default=0)
|
||||
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
|
@ -7,7 +7,7 @@ from .models import *
|
||||
|
||||
|
||||
class RecipeTable(tables.Table):
|
||||
id = tables.LinkColumn('edit_recipe', args=[A('id')])
|
||||
id = tables.LinkColumn('view_recipe', args=[A('id')])
|
||||
name = tables.TemplateColumn(
|
||||
"<a href='#' onClick='openRecipe({{record.id}})'>{{record.name}}</a>")
|
||||
all_tags = tables.Column(
|
||||
|
@ -19,6 +19,9 @@
|
||||
<div id="ingredients-table"></div>
|
||||
<input type="hidden" id="ingredients_data_input" name="ingredients">
|
||||
<input type="submit" value="Submit" class="btn btn-success">
|
||||
{% if view_url %}
|
||||
<a href="{{ view_url }}" class="btn btn-info">{% trans 'View' %} <i class="far fa-eye"></i></a>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
<script>
|
||||
|
@ -13,22 +13,19 @@
|
||||
|
||||
<h3>{% trans 'Edit' %} {{ title }}</h3>
|
||||
|
||||
{% if form.Meta.model|get_class == 'Storage' %} <!-- TODO make one include for this text block -->
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading"><i class="far fa-exclamation-triangle"></i> {% trans 'Security Warning' %}</h4>
|
||||
<p>{% blocktrans %}
|
||||
The <b>Password and Token</b> field are stored as <b>plain text</b> inside the database.
|
||||
This is necessary because they are needed to make API requests, but it also increases the risk of someone stealing it. <br/>
|
||||
To limit the possible damage use read only tokens or accounts if available or create separate accounts with limited access (only to recipes).
|
||||
{% endblocktrans %}</p>
|
||||
</div>
|
||||
{% if form.Meta.model|get_class == 'Storage' %}
|
||||
{% include 'include/storage_backend_warning.html' %}
|
||||
{% endif %}
|
||||
|
||||
<form action="." method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<input type="submit" value="Submit" class="btn btn-success">
|
||||
<a href="{% url 'redirect_delete' form.instance|get_class|lower form.instance.pk %}" class="btn btn-danger">{% trans 'Delete' %}</a>
|
||||
<a href="{% url 'redirect_delete' form.instance|get_class|lower form.instance.pk %}"
|
||||
class="btn btn-danger">{% trans 'Delete' %}</a>
|
||||
{% if view_url %}
|
||||
<a href="{{ view_url }}" class="btn btn-info">{% trans 'View' %} <i class="far fa-eye"></i></a>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
@ -23,7 +23,6 @@
|
||||
|
||||
{% render_table table %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
@ -13,15 +13,8 @@
|
||||
|
||||
<h3>{% trans 'New' %} {{ title }} </h3>
|
||||
|
||||
{% if form.Meta.model|get_class == 'Storage' %} <!-- TODO make one include for this text block -->
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading"><i class="far fa-exclamation-triangle"></i> {% trans 'Security Warning' %}</h4>
|
||||
<p>{% blocktrans %}
|
||||
The <b>Password and Token</b> field are stored as <b>plain text</b> inside the database.
|
||||
This is necessary because they are needed to make API requests, but it also increases the risk of someone stealing it. <br/>
|
||||
To limit the possible damage use read only tokens or accounts if available or create separate accounts with limited access (only to recipes).
|
||||
{% endblocktrans %}</p>
|
||||
</div>
|
||||
{% if form.Meta.model|get_class == 'Storage' %}
|
||||
{% include 'include/storage_backend_warning.html' %}
|
||||
{% endif %}
|
||||
|
||||
<form action="." method="post">
|
||||
|
@ -1,10 +1,10 @@
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
{% load django_tables2 %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
<div class="table-container">
|
||||
{% block table %}
|
||||
<table {% render_attrs table.attrs class="table" %}>
|
||||
|
74
cookbook/templates/include/recipe_open_modal.html
Normal file
74
cookbook/templates/include/recipe_open_modal.html
Normal file
@ -0,0 +1,74 @@
|
||||
{% load i18n %}
|
||||
|
||||
<style>
|
||||
.loader {
|
||||
border: 16px solid #f3f3f3; /* Light grey */
|
||||
border-top: 16px solid #3498db; /* Blue */
|
||||
border-radius: 50%;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_recipe">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% trans 'Recipe' %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center">
|
||||
<div class="loader" id="div_loader"></div>
|
||||
<a href="" id="a_recipe_open" target="_blank" onclick="afterClick()" style="font-size: 250%"></a>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{% trans 'Close' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
function openRecipe(id) {
|
||||
var link = $('#a_recipe_open');
|
||||
link.hide();
|
||||
|
||||
var url = "{% url 'api_get_file_link' recipe_id=12345 %}".replace(/12345/, id);
|
||||
|
||||
link.text("{% trans 'Open Recipe' %}");
|
||||
$('#modal_recipe').modal('show');
|
||||
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function () {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
window.open(this.responseText);
|
||||
$('#modal_recipe').modal('hide');
|
||||
//link.attr("href", this.responseText);
|
||||
//link.show();
|
||||
$('#div_loader').hide();
|
||||
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function afterClick() {
|
||||
$('#modal_recipe').modal('hide');
|
||||
return true;
|
||||
}
|
||||
</script>
|
12
cookbook/templates/include/storage_backend_warning.html
Normal file
12
cookbook/templates/include/storage_backend_warning.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading"><i class="far fa-exclamation-triangle"></i> {% trans 'Security Warning' %}</h4>
|
||||
<p>{% blocktrans %}
|
||||
The <b>Password and Token</b> field are stored as <b>plain text</b> inside the database.
|
||||
This is necessary because they are needed to make API requests, but it also increases the risk of
|
||||
someone stealing it. <br/>
|
||||
To limit the possible damage use read only tokens or accounts if available or create separate accounts
|
||||
with limited access (only to recipes).
|
||||
{% endblocktrans %}</p>
|
||||
</div>
|
@ -42,75 +42,6 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<style>
|
||||
.loader {
|
||||
border: 16px solid #f3f3f3; /* Light grey */
|
||||
border-top: 16px solid #3498db; /* Blue */
|
||||
border-radius: 50%;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_recipe">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% trans 'Recipe' %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center">
|
||||
<div class="loader" id="div_loader"></div>
|
||||
<a href="" id="a_recipe_open" target="_blank" onclick="afterClick()" style="font-size: 250%"></a>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{% trans 'Close' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
function openRecipe(id) {
|
||||
var link = $('#a_recipe_open');
|
||||
link.hide();
|
||||
|
||||
var url = "{% url 'api_get_file_link' recipe_id=12345 %}".replace(/12345/, id);
|
||||
|
||||
link.text("{% trans 'Open Recipe' %}");
|
||||
$('#modal_recipe').modal('show');
|
||||
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function () {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
window.open(this.responseText);
|
||||
//link.attr("href", this.responseText);
|
||||
//link.show();
|
||||
$('#div_loader').hide();
|
||||
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function afterClick() {
|
||||
$('#modal_recipe').modal('hide');
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
{% include 'include/recipe_open_modal.html' %}
|
||||
|
||||
{% endblock %}
|
@ -8,26 +8,40 @@
|
||||
{% block content %}
|
||||
|
||||
<h3>{{ recipe.name }} <a href="{% url 'edit_recipe' recipe.pk %}"><i class="fas fa-pencil-alt"></i></a></h3>
|
||||
{% if ingredients %}
|
||||
<small>{% trans 'by' %} {{ recipe.created_by.username }}</small><br/><br/>
|
||||
{% else %}
|
||||
<small>{% trans 'in' %} <a
|
||||
href="{% url 'edit_storage' recipe.storage.pk %}">{{ recipe.storage.name }}</a></small><br/><br/>
|
||||
{% endif %}
|
||||
|
||||
{% if recipe.all_tags %}
|
||||
{{ recipe.all_tags }}
|
||||
<br/>
|
||||
{% endif %}
|
||||
<br/>
|
||||
<div class="card" style="width: 18rem;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans 'Ingredients' %}</h5>
|
||||
|
||||
{% if ingredients %}
|
||||
<div class="card" style="width: 18rem;">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans 'Ingredients' %}</h5>
|
||||
|
||||
|
||||
{% for i in ingredients %}
|
||||
{{ i.amount }} {{ i.unit }} {{ i.ingredient.name }} <br/>
|
||||
{% endfor %}
|
||||
{% for i in ingredients %}
|
||||
{{ i.amount }} {{ i.unit }} {{ i.ingredient.name }} <br/>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
{{ recipe.instructions | markdown | safe }}
|
||||
|
||||
{{ recipe.instructions | markdown | safe }}
|
||||
{% else %}
|
||||
{% trans 'This is an external recipe.' %}
|
||||
<a href='#' onClick='openRecipe({{ recipe.id }})'>{% trans 'Open recipe' %} <i
|
||||
class="fas fa-external-link-alt"></i></a>
|
||||
{% endif %}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
@ -37,11 +51,9 @@
|
||||
<form method="POST" class="post-form">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<input type="submit" value="Submit" class="btn btn-success">
|
||||
<input type="submit" value="{% trans 'Comment' %}" class="btn btn-success">
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
{% for c in comments %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@ -52,4 +64,7 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if not ingredients %}
|
||||
{% include 'include/recipe_open_modal.html' %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -42,7 +42,7 @@ def internal_recipe_update(request, pk):
|
||||
else:
|
||||
form = InternalRecipeForm(instance=recipe_instance)
|
||||
|
||||
return render(request, 'forms/edit_internal_recipe.html', {'form': form})
|
||||
return render(request, 'forms/edit_internal_recipe.html', {'form': form, 'view_url': reverse('view_recipe', args=[pk])})
|
||||
|
||||
|
||||
class SyncUpdate(LoginRequiredMixin, UpdateView):
|
||||
@ -128,6 +128,7 @@ class RecipeUpdate(LoginRequiredMixin, UpdateView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(RecipeUpdate, self).get_context_data(**kwargs)
|
||||
context['title'] = _("Recipe")
|
||||
context['view_url'] = reverse('view_recipe', args=[self.object.pk])
|
||||
return context
|
||||
|
||||
|
||||
|
@ -13,7 +13,7 @@ from cookbook.tables import RecipeTable
|
||||
|
||||
def index(request):
|
||||
if request.user.is_authenticated:
|
||||
f = RecipeFilter(request.GET, queryset=Recipe.objects.all())
|
||||
f = RecipeFilter(request.GET, queryset=Recipe.objects.all().order_by('name'))
|
||||
|
||||
table = RecipeTable(f.qs)
|
||||
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
||||
|
Loading…
Reference in New Issue
Block a user