import log working
This commit is contained in:
@ -7,7 +7,7 @@ from .models import (Comment, CookLog, Food, Ingredient, InviteLink, Keyword,
|
|||||||
RecipeBook, RecipeBookEntry, RecipeImport, ShareLink,
|
RecipeBook, RecipeBookEntry, RecipeImport, ShareLink,
|
||||||
ShoppingList, ShoppingListEntry, ShoppingListRecipe,
|
ShoppingList, ShoppingListEntry, ShoppingListRecipe,
|
||||||
Space, Step, Storage, Sync, SyncLog, Unit, UserPreference,
|
Space, Step, Storage, Sync, SyncLog, Unit, UserPreference,
|
||||||
ViewLog, Supermarket, SupermarketCategory, SupermarketCategoryRelation)
|
ViewLog, Supermarket, SupermarketCategory, SupermarketCategoryRelation, ImportLog)
|
||||||
|
|
||||||
|
|
||||||
class CustomUserAdmin(UserAdmin):
|
class CustomUserAdmin(UserAdmin):
|
||||||
@ -213,3 +213,10 @@ class NutritionInformationAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
|
|
||||||
admin.site.register(NutritionInformation, NutritionInformationAdmin)
|
admin.site.register(NutritionInformation, NutritionInformationAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class ImportLogAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('id', 'type', 'running', 'created_by', 'created_at',)
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(ImportLog, ImportLogAdmin)
|
||||||
|
@ -20,14 +20,14 @@ class Integration:
|
|||||||
keyword = None
|
keyword = None
|
||||||
files = None
|
files = None
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request, export_type):
|
||||||
"""
|
"""
|
||||||
Integration for importing and exporting recipes
|
Integration for importing and exporting recipes
|
||||||
:param request: request context of import session (used to link user to created objects)
|
:param request: request context of import session (used to link user to created objects)
|
||||||
"""
|
"""
|
||||||
self.request = request
|
self.request = request
|
||||||
self.keyword = Keyword.objects.create(
|
self.keyword = Keyword.objects.create(
|
||||||
name=f'Import {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}.{datetime.datetime.now().strftime("%S")}',
|
name=f'Import {export_type} {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}.{datetime.datetime.now().strftime("%S")}',
|
||||||
description=f'Imported by {request.user.get_user_name()} at {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}',
|
description=f'Imported by {request.user.get_user_name()} at {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}',
|
||||||
icon='📥',
|
icon='📥',
|
||||||
space=request.space
|
space=request.space
|
||||||
@ -77,10 +77,11 @@ class Integration:
|
|||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def do_import(self, files):
|
def do_import(self, files, il):
|
||||||
"""
|
"""
|
||||||
Imports given files
|
Imports given files
|
||||||
:param files: List of in memory files
|
:param files: List of in memory files
|
||||||
|
:param il: Import Log object to refresh while running
|
||||||
:return: HttpResponseRedirect to the recipe search showing all imported recipes
|
:return: HttpResponseRedirect to the recipe search showing all imported recipes
|
||||||
"""
|
"""
|
||||||
with scope(space=self.request.space):
|
with scope(space=self.request.space):
|
||||||
@ -94,20 +95,26 @@ class Integration:
|
|||||||
if self.import_file_name_filter(z):
|
if self.import_file_name_filter(z):
|
||||||
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
||||||
recipe.keywords.add(self.keyword)
|
recipe.keywords.add(self.keyword)
|
||||||
|
il.msg += f'{recipe.pk} - {recipe.name} \n'
|
||||||
if duplicate := self.is_duplicate(recipe):
|
if duplicate := self.is_duplicate(recipe):
|
||||||
ignored_recipes.append(duplicate)
|
ignored_recipes.append(duplicate)
|
||||||
import_zip.close()
|
import_zip.close()
|
||||||
else:
|
else:
|
||||||
recipe = self.get_recipe_from_file(f['file'])
|
recipe = self.get_recipe_from_file(f['file'])
|
||||||
recipe.keywords.add(self.keyword)
|
recipe.keywords.add(self.keyword)
|
||||||
|
il.msg += f'{recipe.pk} - {recipe.name} \n'
|
||||||
if duplicate := self.is_duplicate(recipe):
|
if duplicate := self.is_duplicate(recipe):
|
||||||
ignored_recipes.append(duplicate)
|
ignored_recipes.append(duplicate)
|
||||||
except BadZipFile:
|
except BadZipFile:
|
||||||
messages.add_message(self.request, messages.ERROR, _('Importer expected a .zip file. Did you choose the correct importer type for your data ?'))
|
il.msg += 'ERROR ' + _('Importer expected a .zip file. Did you choose the correct importer type for your data ?') + '\n'
|
||||||
|
|
||||||
if len(ignored_recipes) > 0:
|
if len(ignored_recipes) > 0:
|
||||||
messages.add_message(self.request, messages.WARNING, _('The following recipes were ignored because they already existed:') + ' ' + ', '.join(ignored_recipes))
|
il.msg += _('The following recipes were ignored because they already existed:') + ' ' + ', '.join(ignored_recipes) + '\n'
|
||||||
return HttpResponseRedirect(reverse('view_search') + '?keywords=' + str(self.keyword.pk))
|
|
||||||
|
il.keyword = self.keyword
|
||||||
|
il.msg += (_('Imported %s recipes.') % Recipe.objects.filter(keywords=self.keyword).count()) + '\n'
|
||||||
|
il.running = False
|
||||||
|
il.save()
|
||||||
|
|
||||||
def is_duplicate(self, recipe):
|
def is_duplicate(self, recipe):
|
||||||
"""
|
"""
|
||||||
|
31
cookbook/migrations/0114_importlog.py
Normal file
31
cookbook/migrations/0114_importlog.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Generated by Django 3.1.7 on 2021-03-18 17:23
|
||||||
|
|
||||||
|
import cookbook.models
|
||||||
|
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', '0113_auto_20210317_2017'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ImportLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('type', models.CharField(max_length=32)),
|
||||||
|
('running', models.BooleanField(default=True)),
|
||||||
|
('msg', models.TextField(default='')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
('keyword', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cookbook.keyword')),
|
||||||
|
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
|
||||||
|
],
|
||||||
|
bases=(models.Model, cookbook.models.PermissionModelMixin),
|
||||||
|
),
|
||||||
|
]
|
@ -241,20 +241,6 @@ class SyncLog(models.Model, PermissionModelMixin):
|
|||||||
return f"{self.created_at}:{self.sync} - {self.status}"
|
return f"{self.created_at}:{self.sync} - {self.status}"
|
||||||
|
|
||||||
|
|
||||||
class ImportLog(models.Model, PermissionModelMixin):
|
|
||||||
type = models.CharField(max_length=32)
|
|
||||||
running = models.BooleanField(default=True)
|
|
||||||
msg = models.TextField(default="")
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
objects = ScopedManager(space='space')
|
|
||||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.created_at}:{self.type} - {self.msg}"
|
|
||||||
|
|
||||||
|
|
||||||
class Keyword(models.Model, PermissionModelMixin):
|
class Keyword(models.Model, PermissionModelMixin):
|
||||||
name = models.CharField(max_length=64)
|
name = models.CharField(max_length=64)
|
||||||
icon = models.CharField(max_length=16, blank=True, null=True)
|
icon = models.CharField(max_length=16, blank=True, null=True)
|
||||||
@ -655,3 +641,18 @@ class ViewLog(models.Model, PermissionModelMixin):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.recipe.name
|
return self.recipe.name
|
||||||
|
|
||||||
|
|
||||||
|
class ImportLog(models.Model, PermissionModelMixin):
|
||||||
|
type = models.CharField(max_length=32)
|
||||||
|
running = models.BooleanField(default=True)
|
||||||
|
msg = models.TextField(default="")
|
||||||
|
keyword = models.ForeignKey(Keyword, null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
objects = ScopedManager(space='space')
|
||||||
|
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.created_at}:{self.type}"
|
||||||
|
@ -14,22 +14,22 @@ from cookbook.integration.mealie import Mealie
|
|||||||
from cookbook.integration.nextcloud_cookbook import NextcloudCookbook
|
from cookbook.integration.nextcloud_cookbook import NextcloudCookbook
|
||||||
from cookbook.integration.paprika import Paprika
|
from cookbook.integration.paprika import Paprika
|
||||||
from cookbook.integration.safron import Safron
|
from cookbook.integration.safron import Safron
|
||||||
from cookbook.models import Recipe
|
from cookbook.models import Recipe, ImportLog
|
||||||
|
|
||||||
|
|
||||||
def get_integration(request, export_type):
|
def get_integration(request, export_type):
|
||||||
if export_type == ImportExportBase.DEFAULT:
|
if export_type == ImportExportBase.DEFAULT:
|
||||||
return Default(request)
|
return Default(request, export_type)
|
||||||
if export_type == ImportExportBase.PAPRIKA:
|
if export_type == ImportExportBase.PAPRIKA:
|
||||||
return Paprika(request)
|
return Paprika(request, export_type)
|
||||||
if export_type == ImportExportBase.NEXTCLOUD:
|
if export_type == ImportExportBase.NEXTCLOUD:
|
||||||
return NextcloudCookbook(request)
|
return NextcloudCookbook(request, export_type)
|
||||||
if export_type == ImportExportBase.MEALIE:
|
if export_type == ImportExportBase.MEALIE:
|
||||||
return Mealie(request)
|
return Mealie(request, export_type)
|
||||||
if export_type == ImportExportBase.CHOWDOWN:
|
if export_type == ImportExportBase.CHOWDOWN:
|
||||||
return Chowdown(request)
|
return Chowdown(request, export_type)
|
||||||
if export_type == ImportExportBase.SAFRON:
|
if export_type == ImportExportBase.SAFRON:
|
||||||
return Safron(request)
|
return Safron(request, export_type)
|
||||||
|
|
||||||
|
|
||||||
@group_required('user')
|
@group_required('user')
|
||||||
@ -39,10 +39,12 @@ def import_recipe(request):
|
|||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
try:
|
try:
|
||||||
integration = get_integration(request, form.cleaned_data['type'])
|
integration = get_integration(request, form.cleaned_data['type'])
|
||||||
|
|
||||||
|
il = ImportLog.objects.create(type=form.cleaned_data['type'], created_by=request.user, space=request.space)
|
||||||
files = []
|
files = []
|
||||||
for f in request.FILES.getlist('files'):
|
for f in request.FILES.getlist('files'):
|
||||||
files.append({'file': BytesIO(f.read()), 'name': f.name})
|
files.append({'file': BytesIO(f.read()), 'name': f.name})
|
||||||
t = threading.Thread(target=integration.do_import, args=[files])
|
t = threading.Thread(target=integration.do_import, args=[files, il])
|
||||||
t.setDaemon(True)
|
t.setDaemon(True)
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user