Squashed commit of the following:
commit 707d862e01a7497a1f22879d314b865a35e0e85b
Author: smilerz <smilerz@gmail.com>
Date: Wed Apr 14 10:35:00 2021 -0500
works now
commit 3942a445ed4f2ccec57de25eacd86ea4e4dd6bdb
Author: smilerz <smilerz@gmail.com>
Date: Wed Apr 14 10:25:24 2021 -0500
updated serializer and api
commit 10dc746eb175c7f805a8a8ffa7ce49977a7ce97e
Author: smilerz <smilerz@gmail.com>
Date: Wed Apr 14 10:20:19 2021 -0500
fixed bookmarklet
commit 9779104902d3be0258c95cd2eeebcba0d5d48892
Merge: bb8262c 0cb3928
Author: smilerz <smilerz@gmail.com>
Date: Wed Apr 14 09:56:27 2021 -0500
Merge branch 'bookmarklet' into json_import
commit 0cb39284bb835ffc6cfee3e4306aadc4a64a25be
Author: smilerz <smilerz@gmail.com>
Date: Wed Apr 14 09:42:53 2021 -0500
retrieve bookmarklet ID from get
commit e89e0218de684d40b2e2bfb6ba833891206c828e
Author: smilerz <smilerz@gmail.com>
Date: Wed Apr 14 09:29:33 2021 -0500
Revert "fixed broken tab"
This reverts commit ca0a1aede3cc6cb3912bc1fe30c0aa22e3f481a6.
commit bb8262ccabb93c56fbc18c407d5a0653b8b3ca79
Merge: b1e73aa 35a7f62
Author: smilerz <smilerz@gmail.com>
Date: Sun Apr 11 20:35:57 2021 -0500
Merge branch 'main_fork' into json_import
This commit is contained in:
parent
2c5348fcb4
commit
faf458e8ef
@ -223,15 +223,15 @@ class ImportLogAdmin(admin.ModelAdmin):
|
||||
admin.site.register(ImportLog, ImportLogAdmin)
|
||||
|
||||
|
||||
class BookmarkletImportAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'url', 'created_by', 'created_at',)
|
||||
|
||||
|
||||
admin.site.register(BookmarkletImport, BookmarkletImportAdmin)
|
||||
|
||||
|
||||
class TelegramBotAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'name', 'created_by',)
|
||||
|
||||
|
||||
admin.site.register(TelegramBot, TelegramBotAdmin)
|
||||
|
||||
|
||||
class BookmarkletImportAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'url', 'created_by', 'created_at',)
|
||||
|
||||
|
||||
admin.site.register(BookmarkletImport, BookmarkletImportAdmin)
|
||||
|
@ -61,6 +61,7 @@ with scopes_disabled():
|
||||
model = Recipe
|
||||
fields = ['name', 'keywords', 'foods', 'internal']
|
||||
|
||||
|
||||
class FoodFilter(django_filters.FilterSet):
|
||||
name = django_filters.CharFilter(lookup_expr='icontains')
|
||||
|
||||
@ -68,6 +69,7 @@ with scopes_disabled():
|
||||
model = Food
|
||||
fields = ['name']
|
||||
|
||||
|
||||
class ShoppingListFilter(django_filters.FilterSet):
|
||||
|
||||
def __init__(self, data=None, *args, **kwargs):
|
||||
|
@ -73,9 +73,11 @@ def get_recipe_from_source(text, url, space):
|
||||
html_data = []
|
||||
images = []
|
||||
|
||||
# text = normalize_string(text)
|
||||
try:
|
||||
parse_list.append(remove_graph(json.loads(text)))
|
||||
if not url and 'url' in parse_list[0]:
|
||||
url = parse_list[0]['url']
|
||||
scrape = text_scraper("<script type='application/ld+json'>" + text + "</script>", url=url)
|
||||
|
||||
except JSONDecodeError:
|
||||
soup = BeautifulSoup(text, "html.parser")
|
||||
@ -83,6 +85,8 @@ def get_recipe_from_source(text, url, space):
|
||||
images += get_images_from_source(soup, url)
|
||||
for el in soup.find_all('script', type='application/ld+json'):
|
||||
el = remove_graph(el)
|
||||
if not url and 'url' in el:
|
||||
url = el['url']
|
||||
if type(el) == list:
|
||||
for le in el:
|
||||
parse_list.append(le)
|
||||
@ -95,15 +99,6 @@ def get_recipe_from_source(text, url, space):
|
||||
parse_list.append(le)
|
||||
elif type(el) == dict:
|
||||
parse_list.append(el)
|
||||
|
||||
# if a url was not provided, try to find one in the first document
|
||||
if not url and len(parse_list) > 0:
|
||||
if 'url' in parse_list[0]:
|
||||
url = parse_list[0]['url']
|
||||
|
||||
if type(text) == dict:
|
||||
scrape = text_scraper("<script type='application/ld+json'>" + text + "</script>", url=url)
|
||||
elif type(text) == str:
|
||||
scrape = text_scraper(text, url=url)
|
||||
|
||||
recipe_json = helper.get_from_scraper(scrape, space)
|
||||
|
@ -39,9 +39,9 @@ def get_from_scraper(scrape, space):
|
||||
pass
|
||||
|
||||
try:
|
||||
recipe_json['image'] = scrape.image()
|
||||
except AttributeError:
|
||||
pass
|
||||
recipe_json['image'] = parse_image(scrape.image()) or ''
|
||||
except (AttributeError, TypeError):
|
||||
recipe_json['image'] = ''
|
||||
|
||||
keywords = []
|
||||
try:
|
||||
@ -282,8 +282,8 @@ def parse_keywords(keyword_json, space):
|
||||
# keywords as list
|
||||
for kw in keyword_json:
|
||||
kw = normalize_string(kw)
|
||||
if len(kw) != 0:
|
||||
if k := Keyword.objects.filter(name=kw, space=space).first():
|
||||
if len(k) != 0:
|
||||
keywords.append({'id': str(k.id), 'text': str(k)})
|
||||
else:
|
||||
keywords.append({'id': random.randrange(1111111, 9999999, 1), 'text': kw})
|
||||
|
@ -30,7 +30,7 @@ def text_scraper(text, url=None):
|
||||
url=None
|
||||
):
|
||||
self.wild_mode = False
|
||||
self.exception_handling = _exception_handling
|
||||
self.exception_handling = None
|
||||
self.meta_http_equiv = False
|
||||
self.soup = BeautifulSoup(page_data, "html.parser")
|
||||
self.url = url
|
||||
|
@ -14,8 +14,8 @@ from cookbook.models import (Comment, CookLog, Food, Ingredient, Keyword,
|
||||
RecipeBook, RecipeBookEntry, RecipeImport,
|
||||
ShareLink, ShoppingList, ShoppingListEntry,
|
||||
ShoppingListRecipe, Step, Storage, Sync, SyncLog,
|
||||
Unit, UserPreference, ViewLog, SupermarketCategory,
|
||||
Supermarket, SupermarketCategoryRelation, ImportLog, BookmarkletImport)
|
||||
Unit, UserPreference, ViewLog, SupermarketCategory, Supermarket,
|
||||
SupermarketCategoryRelation, ImportLog, BookmarkletImport)
|
||||
from cookbook.templatetags.custom_tags import markdown
|
||||
|
||||
|
||||
@ -488,6 +488,7 @@ class BookmarkletImportSerializer(serializers.ModelSerializer):
|
||||
fields = ('id', 'url', 'html', 'created_by', 'created_at')
|
||||
read_only_fields = ('created_by', 'space')
|
||||
|
||||
|
||||
# Export/Import Serializers
|
||||
|
||||
class KeywordExportSerializer(KeywordSerializer):
|
||||
|
@ -1,385 +0,0 @@
|
||||
<!--I PROBLABLY DON'T NEED THIS??-->
|
||||
{% extends "base.html" %}
|
||||
{% load crispy_forms_filters %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{% trans 'Import Recipe' %}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{% include 'include/vue_base.html' %}
|
||||
|
||||
<script src="{% static 'js/vue-multiselect.min.js' %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'css/vue-multiselect.min.css' %}">
|
||||
<script src="{% static 'js/vue-jstree.js' %}"></script>
|
||||
<style>
|
||||
.tree-anchor {
|
||||
width:95%;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div id="app">
|
||||
<div v-if="!parsed">
|
||||
<h2>{% trans 'Import From Source' %}</h2>
|
||||
<div class="input-group input-group-lg">
|
||||
<textarea class="form-control" v-model="html_recipe" rows="12" style="font-size: 12px"></textarea>
|
||||
</div>
|
||||
<small class="text-muted">Simply paste a web page source or JSON document into this textarea and click import.</small>
|
||||
<br>
|
||||
<button @click="loadRecipe()" class="btn btn-success" type="button"
|
||||
id="id_btn_import"><i class="fas fa-code"></i>{% trans 'Import' %}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div v-if="loading" class="text-center">
|
||||
<br/>
|
||||
<i class="fas fa-spinner fa-spin fa-8x"></i>
|
||||
</div>
|
||||
|
||||
<template v-if="recipe_data !== undefined">
|
||||
<p>this is the recipe form
|
||||
</template>
|
||||
<div v-if="recipe_tree !== undefined" id="manage_tree">
|
||||
<v-jstree :data="recipe_tree"
|
||||
whole-row
|
||||
collapse:true
|
||||
draggable
|
||||
@item-click="itemClick"
|
||||
@item-drag-start="itemDragStart"
|
||||
@item-drag-end="itemDragEnd"
|
||||
@item-drop-before = "itemDropBefore"
|
||||
@item-drop="itemDrop">
|
||||
|
||||
<template scope="_">
|
||||
<div class="container-fluid" >
|
||||
<div @click.ctrl="customItemClickWithCtrl">
|
||||
<div class="row clearfix" style="width:80%; cursor: grab;" >
|
||||
<i :class="_.vm.themeIconClasses" role="presentation" v-if="!_.model.loading"></i>
|
||||
{% verbatim %}
|
||||
[[_.model.name]]
|
||||
{% endverbatim %}
|
||||
<button style="border: 0px; background-color: transparent; cursor: pointer;"
|
||||
@click="deleteNode(_.vm, _.model, $event)"><i class="fa fa-remove"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-jstree>
|
||||
</div>
|
||||
<template v-if="error !== undefined">
|
||||
<p>something terrible happened
|
||||
</template>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
|
||||
<script src="{% url 'javascript-catalog' %}"></script>
|
||||
<script type="application/javascript">
|
||||
let csrftoken = Cookies.get('csrftoken');
|
||||
Vue.http.headers.common['X-CSRFToken'] = csrftoken;
|
||||
|
||||
//Vue.component('vue-multiselect', window.VueMultiselect.default)
|
||||
|
||||
let app = new Vue({
|
||||
components: {
|
||||
Multiselect: window.VueMultiselect.default
|
||||
},
|
||||
delimiters: ['[[', ']]'],
|
||||
el: '#app',
|
||||
data: {
|
||||
html_recipe: '',
|
||||
keywords: [],
|
||||
keywords_loading: false,
|
||||
units: [],
|
||||
units_loading: false,
|
||||
ingredients: [],
|
||||
ingredients_loading: false,
|
||||
recipe_data: undefined,
|
||||
recipe_tree: [],
|
||||
error: undefined,
|
||||
loading: false,
|
||||
all_keywords: false,
|
||||
importing_recipe: false,
|
||||
parsed: false,
|
||||
searchText: '',
|
||||
editingItem: {},
|
||||
editingNode: null,
|
||||
itemEvents: {
|
||||
mouseover: function () {
|
||||
console.log('mouseover')
|
||||
},
|
||||
contextmenu: function () {
|
||||
console.log(arguments[2])
|
||||
arguments[2].preventDefault()
|
||||
console.log('contextmenu')
|
||||
}
|
||||
},
|
||||
},
|
||||
directives: {
|
||||
tabindex: {
|
||||
inserted(el) {
|
||||
el.setAttribute('tabindex', 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
this.searchKeywords('')
|
||||
this.searchUnits('')
|
||||
this.searchIngredients('')
|
||||
|
||||
},
|
||||
methods: {
|
||||
makeToast: function (title, message, variant = null) {
|
||||
//TODO remove duplicate function in favor of central one
|
||||
this.$bvToast.toast(message, {
|
||||
title: title,
|
||||
variant: variant,
|
||||
toaster: 'b-toaster-top-center',
|
||||
solid: true
|
||||
})
|
||||
},
|
||||
loadRecipe: function () {
|
||||
this.recipe_data = undefined
|
||||
this.recipe_tree = undefined
|
||||
this.error = undefined
|
||||
this.parsed = true
|
||||
this.loading = true
|
||||
this.$http.post("{% url 'api_manual_recipe_from_json' %}", {'html_text': this.html_recipe}, {emulateJSON: true}).then((response) => {
|
||||
console.log(response.data)
|
||||
this.recipe_data = response.data['recipe_data'];
|
||||
this.recipe_tree = response.data['recipe_tree'];
|
||||
this.loading = false
|
||||
}).catch((err) => {
|
||||
this.error = err.data
|
||||
this.loading = false
|
||||
this.parsed = false
|
||||
console.log(err)
|
||||
this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
importRecipe: function () {
|
||||
if (this.importing_recipe) {
|
||||
this.makeToast(gettext('Error'), gettext('Already importing the selected recipe, please wait!'), 'danger')
|
||||
return;
|
||||
}
|
||||
this.importing_recipe = true
|
||||
this.$set(this.recipe_data, 'all_keywords', this.all_keywords)
|
||||
this.$http.post(`{% url 'data_import_url' %}`, this.recipe_data).then((response) => {
|
||||
window.location.href = response.data
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
this.makeToast(gettext('Error'), gettext('An error occurred while trying to import this recipe!') + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
deleteIngredient: function (i) {
|
||||
this.recipe_data.recipeIngredient = this.recipe_data.recipeIngredient.filter(item => item !== i)
|
||||
},
|
||||
addIngredient: function (i) {
|
||||
this.recipe_data.recipeIngredient.push({
|
||||
unit: {id: Math.random() * 1000, text: '{{ request.user.userpreference.default_unit }}'},
|
||||
amount: 0,
|
||||
ingredient: {id: Math.random() * 1000, text: ''}
|
||||
})
|
||||
},
|
||||
addIngredientType: function (tag, index) {
|
||||
index = index.replace('ingredient_', '')
|
||||
let new_ingredient = this.recipe_data.recipeIngredient[index]
|
||||
new_ingredient.ingredient = {'id': Math.random() * 1000, 'text': tag}
|
||||
this.ingredients.push(new_ingredient.ingredient)
|
||||
this.recipe_data.recipeIngredient[index] = new_ingredient
|
||||
},
|
||||
addUnitType: function (tag, index) {
|
||||
index = index.replace('unit_', '')
|
||||
let new_unit = this.recipe_data.recipeIngredient[index]
|
||||
new_unit.unit = {'id': Math.random() * 1000, 'text': tag}
|
||||
this.units.push(new_unit.unit)
|
||||
this.recipe_data.recipeIngredient[index] = new_unit
|
||||
},
|
||||
addKeyword: function (tag) {
|
||||
let new_keyword = {'text':tag,'id':null}
|
||||
this.recipe_data.keywords.push(new_keyword)
|
||||
},
|
||||
openUnitSelect: function (id) {
|
||||
let index = id.replace('unit_', '')
|
||||
if (this.recipe_data.recipeIngredient[index].unit !== null) {
|
||||
this.$set(app.$refs.unit[index].$data, 'search', this.recipe_data.recipeIngredient[index].unit.text)
|
||||
}
|
||||
},
|
||||
openIngredientSelect: function (id) {
|
||||
let index = id.replace('ingredient_', '')
|
||||
this.$set(this.$refs.ingredient[index].$data, 'search', this.recipe_data.recipeIngredient[index].ingredient.text)
|
||||
},
|
||||
searchKeywords: function (query) {
|
||||
this.keywords_loading = true
|
||||
this.$http.get("{% url 'dal_keyword' %}" + '?q=' + query).then((response) => {
|
||||
this.keywords = response.data.results;
|
||||
this.keywords_loading = false
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
searchUnits: function (query) {
|
||||
this.units_loading = true
|
||||
this.$http.get("{% url 'dal_unit' %}" + '?q=' + query).then((response) => {
|
||||
this.units = response.data.results;
|
||||
if (this.recipe_data !== undefined) {
|
||||
for (let x of Array.from(this.recipe_data.recipeIngredient)) {
|
||||
if (x.unit !== null && x.unit.text !== '') {
|
||||
this.units = this.units.filter(item => item.text !== x.unit.text)
|
||||
this.units.push(x.unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.units_loading = false
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
searchIngredients: function (query) {
|
||||
this.ingredients_loading = true
|
||||
this.$http.get("{% url 'dal_food' %}" + '?q=' + query).then((response) => {
|
||||
this.ingredients = response.data.results
|
||||
if (this.recipe_data !== undefined) {
|
||||
for (let x of Array.from(this.recipe_data.recipeIngredient)) {
|
||||
if (x.ingredient.text !== '') {
|
||||
this.ingredients = this.ingredients.filter(item => item.text !== x.ingredient.text)
|
||||
this.ingredients.push(x.ingredient)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.ingredients_loading = false
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
this.makeToast(gettext('Error'), gettext('There was an error loading a resource!') + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
itemClick (node) {
|
||||
this.editingNode = node
|
||||
this.editingItem = node.model
|
||||
console.log(node.model.text + ' clicked !')
|
||||
},
|
||||
itemDragStart (node) {
|
||||
console.log(node.model.text + ' drag start !')
|
||||
},
|
||||
itemDragEnd (node) {
|
||||
console.log(node.model.text + ' drag end !')
|
||||
},
|
||||
itemDropBefore (node, item, draggedItem , e) {
|
||||
if (!draggedItem) {
|
||||
item.addChild({
|
||||
text: "newNode",
|
||||
value: "newNode"
|
||||
})
|
||||
}
|
||||
},
|
||||
itemDrop (node, item, draggedItem , e) {
|
||||
var sortBy = function(attr,rev) {
|
||||
if (rev == undefined) {
|
||||
rev = 1;
|
||||
} else {
|
||||
rev = (rev) ? 1 : -1;
|
||||
}
|
||||
return function (a, b) {
|
||||
a = a[attr];
|
||||
b = b[attr];
|
||||
if (a < b) {
|
||||
return rev * -1;
|
||||
}
|
||||
if (a > b) {
|
||||
return rev * 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
item.children.sort(sortBy('text', true))
|
||||
this.$refs.tree.handleRecursionNodeChildren(draggedItem, function (childrenItem) {
|
||||
childrenItem.selected = item.selected
|
||||
})
|
||||
console.log(node.model.text + ' drop !')
|
||||
},
|
||||
inputKeyUp: function () {
|
||||
var text = this.searchText
|
||||
const patt = new RegExp(text);
|
||||
this.$refs.tree.handleRecursionNodeChilds(this.$refs.tree, function (node) {
|
||||
if (text !== '' && node.model !== undefined) {
|
||||
const str = node.model.text
|
||||
if (patt.test(str)) {
|
||||
node.$el.querySelector('.tree-anchor').style.color = 'red'
|
||||
} else {
|
||||
node.$el.querySelector('.tree-anchor').style.color = '#000'
|
||||
} // or other operations
|
||||
} else {
|
||||
node.$el.querySelector('.tree-anchor').style.color = '#000'
|
||||
}
|
||||
})
|
||||
},
|
||||
addChildNode: function () {
|
||||
if (this.editingItem.id !== undefined) {
|
||||
this.editingItem.addChild({
|
||||
text: "newNode",
|
||||
value: "newNode"
|
||||
})
|
||||
}
|
||||
},
|
||||
removeNode: function () {
|
||||
if (this.editingItem.id !== undefined) {
|
||||
var index = this.editingNode.parentItem.indexOf(this.editingItem)
|
||||
this.editingNode.parentItem.splice(index, 1)
|
||||
}
|
||||
},
|
||||
addBeforeNode: function () {
|
||||
if (this.editingItem.id !== undefined) {
|
||||
this.editingItem.addBefore({
|
||||
text: "newNode",
|
||||
value: "newNode"
|
||||
}, this.editingNode)
|
||||
}
|
||||
},
|
||||
addAfterNode: function () {
|
||||
if (this.editingItem.id !== undefined) {
|
||||
this.editingItem.addAfter({
|
||||
text: "newNode",
|
||||
value: "newNode"
|
||||
}, this.editingNode)
|
||||
}
|
||||
},
|
||||
openChildren: function () {
|
||||
if (this.editingItem.id !== undefined) {
|
||||
this.editingItem.openChildren()
|
||||
}
|
||||
},
|
||||
closeChildren: function () {
|
||||
if (this.editingItem.id !== undefined) {
|
||||
this.editingItem.closeChildren()
|
||||
}
|
||||
},
|
||||
refreshNode: function () {
|
||||
this.asyncData = [
|
||||
this.$refs.tree2.initializeLoading()
|
||||
]
|
||||
this.$refs.tree2.handleAsyncLoad(this.asyncData, this.$refs.tree2)
|
||||
},
|
||||
customItemClick: function (node ,item, e) {
|
||||
e.stopPropagation()
|
||||
var index = node.parentItem.indexOf(item)
|
||||
node.parentItem.splice(index, 1)
|
||||
},
|
||||
customItemClickWithCtrl: function () {
|
||||
console.log('click + ctrl')
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
@ -1,7 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load custom_tags %}
|
||||
|
||||
{% block title %}{% trans 'URL Import' %}{% endblock %}
|
||||
|
||||
@ -21,15 +20,9 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="app">
|
||||
<div class="row px-3" style="justify-content:space-between;">
|
||||
<h2> {% trans 'Import' %} </h2>
|
||||
<a class="btn btn-outline-info btn-sm"
|
||||
style="height:50%"
|
||||
href="{% bookmarklet request %}"
|
||||
title="{% trans 'Drag me to your bookmarks to import recipes from anywhere' %}">
|
||||
<img src="{% static 'assets/favicon-16x16.png' %}">{% trans 'Bookmark Me!' %} </a>
|
||||
</div>
|
||||
<nav class="nav nav-pills flex-sm-row" style="margin-bottom:10px">
|
||||
<a class="nav-link active" href="#nav-url" data-toggle="tab" role="tab" aria-controls="nav-url" aria-selected="true" @click="mode='url'">URL</a>
|
||||
<a class="nav-link" href="#nav-app" data-toggle="tab" role="tab" aria-controls="nav-app" @click="mode='app'">App</a>
|
||||
@ -605,6 +598,7 @@
|
||||
<script type="application/javascript">
|
||||
let csrftoken = Cookies.get('csrftoken');
|
||||
Vue.http.headers.common['X-CSRFToken'] = csrftoken;
|
||||
|
||||
Vue.component('vue-multiselect', window.VueMultiselect.default)
|
||||
|
||||
let app = new Vue({
|
||||
@ -625,7 +619,7 @@
|
||||
recipe_data: undefined,
|
||||
error: undefined,
|
||||
loading: false,
|
||||
preview: undefined,
|
||||
preview: false,
|
||||
preview_type: 'json',
|
||||
all_keywords: false,
|
||||
importing_recipe: false,
|
||||
@ -729,6 +723,35 @@
|
||||
this.makeToast(gettext('Error'), gettext('There was an error deleting bookmarklet!') + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
loadBookmarklet: function(id_bkmk) {
|
||||
let uri = window.location.search.substring(1);
|
||||
let params = new URLSearchParams(uri);
|
||||
q = params.get("id")
|
||||
console.log(q)
|
||||
this.error = undefined
|
||||
this.loading = true
|
||||
this.$http.get("{% url 'api:bookmarkletimport-list' %}?id=" + id_bkmk ).then((response) => {
|
||||
console.log(response.data)
|
||||
this.automatic = false
|
||||
this.source_data = response.data[0]['html']
|
||||
this.remote_url = response.data[0]['url']
|
||||
this.loadRecipe()
|
||||
}).catch((err) => {
|
||||
this.error = err.data
|
||||
this.loading = false
|
||||
console.log(err)
|
||||
this.makeToast(gettext('Error'), gettext('There was an error loading bookmarklet!') + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
deleteBookmarklet: function(id_bkmk) {
|
||||
this.error = undefined
|
||||
this.$http.delete("{% url 'api:bookmarkletimport-list' %}" + id_bkmk +"/").then((response) => {
|
||||
}).catch((err) => {
|
||||
this.error = err.data
|
||||
console.log(err)
|
||||
this.makeToast(gettext('Error'), gettext('There was an error deleting bookmarklet!') + err.bodyText, 'danger')
|
||||
})
|
||||
},
|
||||
showRecipe: function() {
|
||||
this.preview = false
|
||||
this.recipe_data = this.recipe_json
|
||||
|
@ -1,5 +1,4 @@
|
||||
import bleach
|
||||
import re
|
||||
import markdown as md
|
||||
from bleach_allowlist import markdown_attrs, markdown_tags
|
||||
from cookbook.helper.mdx_attributes import MarkdownFormatExtension
|
||||
@ -7,10 +6,8 @@ from cookbook.helper.mdx_urlize import UrlizeExtension
|
||||
from cookbook.models import Space, get_model_name
|
||||
from django import template
|
||||
from django.db.models import Avg
|
||||
from django.templatetags.static import static
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from recipes import settings
|
||||
from rest_framework.authtoken.models import Token
|
||||
from gettext import gettext as _
|
||||
|
||||
register = template.Library()
|
||||
|
@ -76,8 +76,7 @@ def test_add(arg, request, u1_s2):
|
||||
print(r.content)
|
||||
assert r.status_code == arg[1]
|
||||
if r.status_code == 201:
|
||||
# changed to name - when multiple tests run DB isn't cleared between tests
|
||||
assert response['name'] == 'test'
|
||||
assert response['id'] == 1
|
||||
r = c.get(reverse(DETAIL_URL, args={response['id']}))
|
||||
assert r.status_code == 200
|
||||
r = u1_s2.get(reverse(DETAIL_URL, args={response['id']}))
|
||||
|
@ -1705,7 +1705,7 @@ MADAME_DESSERT = {
|
||||
"servings": 6,
|
||||
"prepTime": 0,
|
||||
"cookTime": 20,
|
||||
"image": "https://madamedessert.de/wp-content/uploads/2020/02/Madame-Dessert_Schokopudding-Schokoladenpudding-mit-echter-Schokolade-0238-scaled.jpg",
|
||||
"image": "https://assets.madamedessert.de/wp-content/uploads/2020/02/25163328/Madame-Dessert_Schokopudding-Schokoladenpudding-mit-echter-Schokolade-0238-scaled.jpg",
|
||||
"keywords": [
|
||||
{
|
||||
"id": 7588432,
|
||||
@ -1795,7 +1795,7 @@ MADAME_DESSERT = {
|
||||
"original": "1 TL Vanilleextrakt"
|
||||
},
|
||||
{
|
||||
"amount": 125,
|
||||
"amount": 150,
|
||||
"unit": {
|
||||
"text": "g",
|
||||
"id": 24254
|
||||
@ -1805,7 +1805,7 @@ MADAME_DESSERT = {
|
||||
"id": 42645
|
||||
},
|
||||
"note": "",
|
||||
"original": "125 g Zucker"
|
||||
"original": "150 g Zucker"
|
||||
},
|
||||
{
|
||||
"amount": 30,
|
||||
|
File diff suppressed because one or more lines are too long
@ -3,8 +3,7 @@ import pytest
|
||||
|
||||
from django.urls import reverse
|
||||
|
||||
from ._recipes import (
|
||||
ALLRECIPES, AMERICAS_TEST_KITCHEN, CHEF_KOCH, COOKPAD,
|
||||
from ._recipes import (ALLRECIPES, AMERICAS_TEST_KITCHEN, CHEF_KOCH, COOKPAD,
|
||||
COOKS_COUNTRY, DELISH, FOOD_NETWORK, GIALLOZAFFERANO, JOURNAL_DES_FEMMES,
|
||||
MADAME_DESSERT, MARMITON, TASTE_OF_HOME, TUDOGOSTOSO)
|
||||
|
||||
|
@ -16,7 +16,6 @@ from django.http import FileResponse, HttpResponse, JsonResponse, HttpResponseRe
|
||||
from django.shortcuts import redirect, render, get_object_or_404
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from icalendar import Calendar, Event
|
||||
|
||||
from rest_framework import decorators, viewsets
|
||||
@ -36,7 +35,7 @@ from cookbook.helper.ingredient_parser import parse
|
||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest,
|
||||
CustomIsOwner, CustomIsShare,
|
||||
CustomIsShared, CustomIsUser,
|
||||
group_required)
|
||||
group_required, share_link_valid)
|
||||
from cookbook.helper.recipe_html_import import get_recipe_from_source
|
||||
from cookbook.helper.recipe_url_import import get_from_scraper
|
||||
from cookbook.models import (CookLog, Food, Ingredient, Keyword, MealPlan,
|
||||
@ -58,9 +57,9 @@ from cookbook.serializer import (FoodSerializer, IngredientSerializer,
|
||||
StorageSerializer, SyncLogSerializer,
|
||||
SyncSerializer, UnitSerializer,
|
||||
UserNameSerializer, UserPreferenceSerializer,
|
||||
ViewLogSerializer, CookLogSerializer,
|
||||
RecipeBookEntrySerializer, RecipeOverviewSerializer,
|
||||
SupermarketSerializer, ImportLogSerializer, BookmarkletImportSerializer)
|
||||
ViewLogSerializer, CookLogSerializer, RecipeBookEntrySerializer,
|
||||
RecipeOverviewSerializer, SupermarketSerializer, ImportLogSerializer,
|
||||
BookmarkletImportSerializer)
|
||||
from recipes.settings import DEMO
|
||||
|
||||
|
||||
|
@ -94,7 +94,9 @@ def batch_edit(request):
|
||||
msg = ngettext(
|
||||
'Batch edit done. %(count)d recipe was updated.',
|
||||
'Batch edit done. %(count)d Recipes where updated.',
|
||||
count) % {'count': count, }
|
||||
count) % {
|
||||
'count': count,
|
||||
}
|
||||
messages.add_message(request, messages.SUCCESS, msg)
|
||||
|
||||
return redirect('data_batch_edit')
|
||||
@ -190,13 +192,12 @@ def import_url(request):
|
||||
return HttpResponse(reverse('view_recipe', args=[recipe.pk]))
|
||||
|
||||
if 'id' in request.GET:
|
||||
context = {'bookmarklet': 25}
|
||||
context = {'bookmarklet': request.GET.get('id', '')}
|
||||
else:
|
||||
context = {}
|
||||
|
||||
return render(request, 'url_import.html', context)
|
||||
|
||||
|
||||
class Object(object):
|
||||
pass
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user