diff --git a/cookbook/admin.py b/cookbook/admin.py
index ed145623..d4cc533d 100644
--- a/cookbook/admin.py
+++ b/cookbook/admin.py
@@ -7,7 +7,7 @@ from .models import (Comment, CookLog, Food, Ingredient, InviteLink, Keyword,
RecipeBook, RecipeBookEntry, RecipeImport, ShareLink,
ShoppingList, ShoppingListEntry, ShoppingListRecipe,
Space, Step, Storage, Sync, SyncLog, Unit, UserPreference,
- ViewLog, Supermarket, SupermarketCategory, SupermarketCategoryRelation,
+ ViewLog, Supermarket, SupermarketCategory, SupermarketCategoryRelation,
ImportLog, TelegramBot, BookmarkletImport)
@@ -229,6 +229,7 @@ class BookmarkletImportAdmin(admin.ModelAdmin):
admin.site.register(BookmarkletImport, BookmarkletImportAdmin)
+
class TelegramBotAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'created_by',)
diff --git a/cookbook/serializer.py b/cookbook/serializer.py
index d9ae6a50..9da066cf 100644
--- a/cookbook/serializer.py
+++ b/cookbook/serializer.py
@@ -476,7 +476,7 @@ class BookmarkletImportSerializer(serializers.ModelSerializer):
class Meta:
model = BookmarkletImport
fields = ('id', 'url', 'html', 'created_by', 'created_at')
- read_only_fields = ('created_by',)
+ read_only_fields = ('created_by', 'space')
# Export/Import Serializers
diff --git a/cookbook/static/js/bookmarklet.js b/cookbook/static/js/bookmarklet.js
index 0d2e4f1b..f8a94725 100644
--- a/cookbook/static/js/bookmarklet.js
+++ b/cookbook/static/js/bookmarklet.js
@@ -18,28 +18,30 @@
}
function initBookmarklet() {
(window.bookmarkletTandoor = function() {
- var recipe = document.documentElement.innerHTML
- var form = document.createElement("form");
- var windowName = "ImportRecipe"
- form.setAttribute("method", "post");
- form.setAttribute("action", localStorage.getItem('importURL'));
- form.setAttribute("target",'importRecipe');
- var params = { 'recipe' : recipe,'url': window.location};
+ let recipe = document.documentElement.innerHTML
+ let windowName = "ImportRecipe"
+ let url = localStorage.getItem('importURL')
+ let redirect = localStorage.getItem('redirectURL')
+ let token = localStorage.getItem('token')
+ let params = { 'html' : recipe,'url': window.location.href};
+ console.log(window.location.href)
- for (var i in params) {
- if (params.hasOwnProperty(i)) {
- var input = document.createElement('input');
- input.type = 'hidden';
- input.name = i;
- input.value = params[i];
- form.appendChild(input);
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', url, true);
+ xhr.setRequestHeader('Content-Type', 'application/json');
+ xhr.setRequestHeader('Authorization', 'Token ' + token);
+
+ // listen for `onload` event
+ xhr.onload = () => {
+ // process response
+ if (xhr.readyState == 4 && xhr.status == 201) {
+ // parse JSON data
+ console.log(JSON.parse(xhr.response));
+ } else {
+ console.error('Error!');
}
- }
- document.body.appendChild(form);
- window.open('', windowName);
- form.target = windowName;
- form.submit();
- document.body.removeChild(form);
+ };
+ xhr.send(JSON.stringify(params));
}
)();
}
diff --git a/cookbook/templates/url_import.html b/cookbook/templates/url_import.html
index 63a819bc..6dd3ec33 100644
--- a/cookbook/templates/url_import.html
+++ b/cookbook/templates/url_import.html
@@ -26,7 +26,7 @@
{% trans 'Import' %}
{% trans 'Bookmark Me!' %}
diff --git a/cookbook/templatetags/custom_tags.py b/cookbook/templatetags/custom_tags.py
index ab53919b..12e525bf 100644
--- a/cookbook/templatetags/custom_tags.py
+++ b/cookbook/templatetags/custom_tags.py
@@ -10,6 +10,7 @@ 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()
@@ -111,20 +112,26 @@ def is_debug():
@register.simple_tag
-def bookmarklet(host, secure):
- if secure:
+def bookmarklet(request):
+ if request.is_secure():
prefix = "https://"
else:
prefix = "http://"
+ server = prefix + request.get_host()
+ # TODO is it safe to store the token in clear text in a bookmark?
+ if (api_token := Token.objects.filter(user=request.user).first()) is None:
+ api_token = Token.objects.create(user=request.user)
bookmark = "javascript: \
(function(){ \
if(window.bookmarkletTandoor!==undefined){ \
bookmarkletTandoor(); \
} else { \
- localStorage.setItem('importURL', '" + prefix + host + reverse('api_bookmarklet') + "'); \
+ localStorage.setItem('importURL', '" + server + reverse('api:bookmarkletimport-list') + "'); \
+ localStorage.setItem('redirectURL', '" + server + reverse('data_import_url') + "'); \
+ localStorage.setItem('token', '" + api_token.__str__() + "'); \
document.body.appendChild(document.createElement(\'script\')).src=\'" \
- + prefix + host + static('js/bookmarklet.js') + "? \
+ + server + static('js/bookmarklet.js') + "? \
r=\'+Math.floor(Math.random()*999999999);}})();"
- return re.sub(r"[\n\t]*", "", bookmark)
+ return re.sub(r"[\n\t\s]*", "", bookmark)
diff --git a/cookbook/views/api.py b/cookbook/views/api.py
index b7020dc5..f56d216a 100644
--- a/cookbook/views/api.py
+++ b/cookbook/views/api.py
@@ -51,8 +51,8 @@ from cookbook.serializer import (FoodSerializer, IngredientSerializer,
StorageSerializer, SyncLogSerializer,
SyncSerializer, UnitSerializer,
UserNameSerializer, UserPreferenceSerializer,
- ViewLogSerializer, CookLogSerializer,
- RecipeBookEntrySerializer, RecipeOverviewSerializer,
+ ViewLogSerializer, CookLogSerializer,
+ RecipeBookEntrySerializer, RecipeOverviewSerializer,
SupermarketSerializer, ImportLogSerializer, BookmarkletImportSerializer)
from recipes.settings import DEMO
from recipe_scrapers import scrape_me, WebsiteNotImplementedError, NoSchemaFoundInWildMode
diff --git a/cookbook/views/data.py b/cookbook/views/data.py
index 1820ac7c..77252b1a 100644
--- a/cookbook/views/data.py
+++ b/cookbook/views/data.py
@@ -94,8 +94,8 @@ def batch_edit(request):
'Batch edit done. %(count)d recipe was updated.',
'Batch edit done. %(count)d Recipes where updated.',
count) % {
- 'count': count,
- }
+ 'count': count,
+ }
messages.add_message(request, messages.SUCCESS, msg)
return redirect('data_batch_edit')
diff --git a/recipes/settings.py b/recipes/settings.py
index 85d56381..f2f9aa8b 100644
--- a/recipes/settings.py
+++ b/recipes/settings.py
@@ -14,6 +14,7 @@ import os
import random
import string
+from corsheaders.defaults import default_headers
from django.contrib import messages
from django.utils.translation import gettext_lazy as _
from dotenv import load_dotenv
@@ -76,6 +77,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'django.contrib.postgres',
'django_tables2',
+ 'corsheaders',
'django_filters',
'crispy_forms',
'emoji_picker',
@@ -97,6 +99,7 @@ SOCIALACCOUNT_PROVIDERS = ast.literal_eval(
os.getenv('SOCIALACCOUNT_PROVIDERS') if os.getenv('SOCIALACCOUNT_PROVIDERS') else '{}')
MIDDLEWARE = [
+ 'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -249,5 +252,17 @@ STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
TEST_RUNNER = "cookbook.helper.CustomTestRunner.CustomTestRunner"
-# future versions of django will make undeclared default django.db.models.BigAutoField which will force migrations on all models
-DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+
+# settings for cross site origin (CORS)
+# all origins allowed to support bookmarklet
+# all of this may or may not work with nginx or other web servers
+# TODO make this user configureable - enable or disable bookmarklets
+# TODO since token auth is enabled - this all should be https by default
+CORS_ORIGIN_ALLOW_ALL = True
+
+# django rest_framework requires authentication header
+#CORS_ALLOW_HEADERS = list(default_headers) + ['authentication',]
+
+# enable CORS only for bookmarklet api and only for posts, get and options
+CORS_URLS_REGEX = r'^/api/bookmarklet-import.*$'
+CORS_ALLOW_METHODS = ['GET', 'OPTIONS', 'POST']
diff --git a/requirements.txt b/requirements.txt
index 93bea96f..3e49f29a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -33,5 +33,6 @@ django-js-reverse==0.9.1
django-allauth==0.44.0
recipe-scrapers==12.2.1
django-scopes==1.2.0
-pytest==6.2.3
-pytest-django==4.2.0
+pytest==6.2.2
+pytest-django==4.1.0
+django-cors-headers==3.7.0