improvements and fixes

This commit is contained in:
Unknown
2018-06-01 15:53:06 +02:00
parent 4871b6194c
commit fb852b35a6
14 changed files with 91 additions and 42 deletions

View File

@ -5,3 +5,8 @@ from .models import *
admin.site.register(Recipe) admin.site.register(Recipe)
admin.site.register(Keyword) admin.site.register(Keyword)
admin.site.register(Category) admin.site.register(Category)
admin.site.register(Sync)
admin.site.register(SyncLog)
admin.site.register(RecipeImport)
admin.site.register(Storage)

View File

@ -6,7 +6,8 @@ from cookbook.models import Recipe, Keyword
class RecipeFilter(django_filters.FilterSet): class RecipeFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='contains') name = django_filters.CharFilter(lookup_expr='contains')
keywords = django_filters.ModelMultipleChoiceFilter(queryset=Keyword.objects.all(), widget=MultiSelectWidget, method='filter_keywords') keywords = django_filters.ModelMultipleChoiceFilter(queryset=Keyword.objects.all(), widget=MultiSelectWidget,
method='filter_keywords')
@staticmethod @staticmethod
def filter_keywords(queryset, name, value): def filter_keywords(queryset, name, value):
@ -19,3 +20,14 @@ class RecipeFilter(django_filters.FilterSet):
class Meta: class Meta:
model = Recipe model = Recipe
fields = ['name', 'category', 'keywords'] fields = ['name', 'category', 'keywords']
class QuickRecipeFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='contains')
category = django_filters.CharFilter(lookup_expr='contains')
keywords = django_filters.ModelMultipleChoiceFilter(queryset=Keyword.objects.all(), widget=MultiSelectWidget,
method='filter_keywords')
class Meta:
model = Recipe
fields = ['name', 'category', 'keywords']

View File

@ -1,7 +1,8 @@
from django.utils.translation import gettext as _
from django import forms from django import forms
from .models import *
from django.forms import widgets from django.forms import widgets
from django.utils.translation import gettext as _
from .models import *
class MultiSelectWidget(widgets.SelectMultiple): class MultiSelectWidget(widgets.SelectMultiple):
@ -44,8 +45,10 @@ class KeywordForm(forms.ModelForm):
class StorageForm(forms.ModelForm): class StorageForm(forms.ModelForm):
username = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'new-password'}), required=False) username = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'new-password'}), required=False)
password = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'new-password', 'type': 'password'}), required=False) password = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'new-password', 'type': 'password'}),
token = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'new-password', 'type': 'password'}), required=False) required=False)
token = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'new-password', 'type': 'password'}),
required=False)
class Meta: class Meta:
model = Storage model = Storage
@ -61,10 +64,8 @@ class SyncForm(forms.ModelForm):
class BatchEditForm(forms.Form): class BatchEditForm(forms.Form):
search = forms.CharField(label=_('Search String')) search = forms.CharField(label=_('Search String'))
category = forms.ModelChoiceField(queryset=Category.objects.all().order_by('id'), required=False) category = forms.ModelChoiceField(queryset=Category.objects.all().order_by('id'), required=False)
keywords = forms.ModelMultipleChoiceField(queryset=Keyword.objects.all().order_by('id'), required=False) keywords = forms.ModelMultipleChoiceField(queryset=Keyword.objects.all().order_by('id'), required=False,
widget=MultiSelectWidget)
class Media:
js = ('custom/js/form_multiselect.js',)
class ImportRecipeForm(forms.ModelForm): class ImportRecipeForm(forms.ModelForm):

View File

@ -23,6 +23,9 @@ class Sync(models.Model):
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.path
class SyncLog(models.Model): class SyncLog(models.Model):
sync = models.ForeignKey(Sync, on_delete=models.CASCADE) sync = models.ForeignKey(Sync, on_delete=models.CASCADE)
@ -79,3 +82,6 @@ class RecipeImport(models.Model):
storage = models.ForeignKey(Storage, on_delete=models.PROTECT) storage = models.ForeignKey(Storage, on_delete=models.PROTECT)
path = models.CharField(max_length=512, default="") path = models.CharField(max_length=512, default="")
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name

View File

@ -93,9 +93,9 @@
{% trans 'Manage Data' %} {% trans 'Manage Data' %}
</a> </a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item" href="{% url 'batch_monitor' %}"><i <a class="dropdown-item" href="{% url 'data_sync' %}"><i
class="fas fa-sync-alt"></i> {% trans 'Configure Sync' %}</a> class="fas fa-sync-alt"></i> {% trans 'Configure Sync' %}</a>
<a class="dropdown-item" href="{% url 'batch_edit' %}"><i <a class="dropdown-item" href="{% url 'data_batch_edit' %}"><i
class="fas fa-edit"></i> {% trans 'Batch Edit' %}</a> class="fas fa-edit"></i> {% trans 'Batch Edit' %}</a>
</div> </div>
</li> </li>

View File

@ -24,7 +24,7 @@
</div> </div>
<br/> <br/>
<a href="{% url 'batch_sync_wait' %}" class="btn btn-warning">{% trans 'Sync Now!' %}</a> <a href="{% url 'data_sync_wait' %}" class="btn btn-warning">{% trans 'Sync Now!' %}</a>
<br/><br/> <br/><br/>
{% render_table monitored_paths %} {% render_table monitored_paths %}

View File

@ -15,11 +15,18 @@
<br/> <br/>
<div class="text-center"> <div class="text-center">
<i class="fas fa-sync fa-spin fa-10x"></i> <i class="fas fa-sync fa-spin fa-10x"></i>
<br/>
<br/>
<br/>
<div class="alert alert-success" role="alert">
{% trans 'This can take a few minutes, depending on the number of recipes in sync, please wait.' %}
</div>
</div> </div>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
window.location.href = "http://192.168.178.27:8000/cookbook/api/sync_all" window.location.href = "{% url 'api_sync' %}"
}); });
</script> </script>

View File

@ -18,7 +18,7 @@
<br/> <br/>
{% if table.Meta.model|get_class == 'RecipeImport' %} {% if table.Meta.model|get_class == 'RecipeImport' %}
<a href="{% url 'batch_import_all' %}" class="btn btn-warning">{% trans 'Import all' %}</a> <a href="{% url 'data_batch_import' %}" class="btn btn-warning">{% trans 'Import all' %}</a>
<br/> <br/>
<br/> <br/>
{% endif %} {% endif %}

View File

@ -16,10 +16,8 @@
{% if filter %} {% if filter %}
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<i class="fas fa-search"></i> {% trans "Search" %} <input type="text" class="form-control"> <i class="fas fa-search"></i> {% trans "Search" %}
<a data-toggle="collapse" href="#collapse_search" role="button" aria-expanded="false" aria-controls="collapse_search">{% trans 'Advanced Search' %}</a>
</div> </div>
<div class="collapse" id="collapse_search">
<div class="card-body"> <div class="card-body">
<form action="" method="get" id="search_form"> <form action="" method="get" id="search_form">
{{ filter.form|crispy }} {{ filter.form|crispy }}
@ -27,7 +25,7 @@
<a href="#" onclick="window.location = window.location.pathname;" <a href="#" onclick="window.location = window.location.pathname;"
class="btn btn-warning">{% trans 'Reset' %}</a> class="btn btn-warning">{% trans 'Reset' %}</a>
</form> </form>
</div>
</div> </div>
</div> </div>
{% endif %} {% endif %}

View File

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans 'Stats' %}{% endblock %}
{% block content %}
<h3>
{% trans 'Statistics' %}
</h3>
{% endblock %}

View File

@ -36,10 +36,11 @@ urlpatterns = [
path('delete/import/<int:pk>/', edit.ImportDelete.as_view(), name='delete_import'), path('delete/import/<int:pk>/', edit.ImportDelete.as_view(), name='delete_import'),
path('delete/storage/<int:pk>/', edit.StorageDelete.as_view(), name='delete_storage'), path('delete/storage/<int:pk>/', edit.StorageDelete.as_view(), name='delete_storage'),
path('batch/sync', batch.batch_monitor, name='batch_monitor'), # TODO move to generic "new" view path('data/sync', data.sync, name='data_sync'), # TODO move to generic "new" view
path('batch/edit', batch.batch_edit, name='batch_edit'), path('data/batch/edit', data.batch_edit, name='data_batch_edit'),
path('batch/import/all', batch.batch_import_all, name='batch_import_all'), path('data/batch/import', data.batch_import, name='data_batch_import'),
path('batch/sync/wait', batch.sync_wait, name='batch_sync_wait'), path('data/sync/wait', data.sync_wait, name='data_sync_wait'),
path('data/statistics', data.statistics, name='data_stats'),
path('api/get_file_link/<int:recipe_id>/', api.get_file_link, name='api_get_file_link'), path('api/get_file_link/<int:recipe_id>/', api.get_file_link, name='api_get_file_link'),
path('api/sync_all/', api.sync_all, name='api_sync'), path('api/sync_all/', api.sync_all, name='api_sync'),

View File

@ -1,6 +1,6 @@
from cookbook.views.views import * from cookbook.views.views import *
from cookbook.views.api import * from cookbook.views.api import *
from cookbook.views.batch import * from cookbook.views.data import *
from cookbook.views.edit import * from cookbook.views.edit import *
from cookbook.views.new import * from cookbook.views.new import *
from cookbook.views.lists import * from cookbook.views.lists import *

View File

@ -3,16 +3,16 @@ from datetime import datetime
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.utils.translation import ngettext
from django_tables2 import RequestConfig from django_tables2 import RequestConfig
from cookbook.forms import SyncForm, BatchEditForm, RecipeImport from cookbook.forms import SyncForm, BatchEditForm, RecipeImport
from cookbook.models import Recipe, Category, Sync from cookbook.models import Recipe, Sync
from cookbook.tables import SyncTable from cookbook.tables import SyncTable
from django.utils.translation import gettext as _, ngettext
@login_required @login_required
def batch_monitor(request): def sync(request):
if request.method == "POST": if request.method == "POST":
form = SyncForm(request.POST) form = SyncForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -21,7 +21,7 @@ def batch_monitor(request):
new_path.storage = form.cleaned_data['storage'] new_path.storage = form.cleaned_data['storage']
new_path.last_checked = datetime.now() new_path.last_checked = datetime.now()
new_path.save() new_path.save()
return redirect('batch_monitor') return redirect('data_sync')
else: else:
form = SyncForm() form = SyncForm()
@ -37,7 +37,7 @@ def sync_wait(request):
@login_required @login_required
def batch_import_all(request): def batch_import(request):
imports = RecipeImport.objects.all() imports = RecipeImport.objects.all()
for new_recipe in imports: for new_recipe in imports:
recipe = Recipe(name=new_recipe.name, path=new_recipe.path, storage=new_recipe.storage) recipe = Recipe(name=new_recipe.name, path=new_recipe.path, storage=new_recipe.storage)
@ -54,17 +54,17 @@ def batch_edit(request):
if form.is_valid(): if form.is_valid():
word = form.cleaned_data['search'] word = form.cleaned_data['search']
category = form.cleaned_data['category'] category = form.cleaned_data['category']
keyword = form.cleaned_data['keyword'] keywords = form.cleaned_data['keywords']
recipes = Recipe.objects.filter(name__contains=word) recipes = Recipe.objects.filter(name__contains=word)
count = 0 count = 0
for recipe in recipes: for recipe in recipes:
edit = False edit = False
if category is not None: if category is not None:
recipe.category = Category.objects.get(name=category) recipe.category = category
edit = True edit = True
if keyword.__sizeof__() > 0: if keywords.__sizeof__() > 0:
recipe.keywords.add(*list(keyword)) recipe.keywords.add(*list(keywords))
edit = True edit = True
if edit: if edit:
count = count + 1 count = count + 1
@ -79,8 +79,13 @@ def batch_edit(request):
} }
messages.add_message(request, messages.SUCCESS, msg) messages.add_message(request, messages.SUCCESS, msg)
return redirect('batch_edit') return redirect('data_batch_edit')
else: else:
form = BatchEditForm() form = BatchEditForm()
return render(request, 'batch/edit.html', {'form': form}) return render(request, 'batch/edit.html', {'form': form})
@login_required
def statistics(request):
return render(request, 'index.html')

View File

@ -142,7 +142,7 @@ class ImportDelete(LoginRequiredMixin, DeleteView):
class MonitorDelete(LoginRequiredMixin, DeleteView): class MonitorDelete(LoginRequiredMixin, DeleteView):
template_name = "generic\delete_template.html" template_name = "generic\delete_template.html"
model = Sync model = Sync
success_url = reverse_lazy('batch_monitor') success_url = reverse_lazy('data_sync')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(MonitorDelete, self).get_context_data(**kwargs) context = super(MonitorDelete, self).get_context_data(**kwargs)