recipe stuff

This commit is contained in:
vabene1111 2021-01-12 20:51:28 +01:00
parent 816ced83b5
commit 24ed6a1cd2
12 changed files with 175 additions and 31 deletions

View File

@ -4,6 +4,7 @@ source venv/bin/activate
echo "Updating database"
python manage.py migrate
python manage.py collectstatic --noinput
python manage.py collectstatic_js_reverse
echo "Done"
chmod -R 755 /opt/recipes/mediafiles

View File

@ -0,0 +1,18 @@
<!--
As there is apparently no good way to pass django named URLs to Vue/Webpack we will pack the urls we need into
this object and load it in all the templates where we load Vue apps
Reason for not using other alternatives
## django-js-reverse
bad performance because the 25kb or so path file needs to be loaded before any other request can be made
or all paths need to be printed in template which is apparently not recommended for CSP reasons (although this here
might do the same)
-->
<script type="application/javascript">
window.DJANGO_URLS = {
'edit_storage'
}
</script>

View File

@ -16,8 +16,15 @@
{% block script %}
<script src="{% url 'javascript-catalog' %}"></script>
{% if debug %}
<script src="{% url 'js_reverse' %}"></script>
{% else %}
<script src="{% static 'django_js_reverse/js/reverse.js' %}"></script>
{% endif %}
<script type="application/javascript">
window.RECIPE_ID = 5;
</script>
{% render_bundle 'chunk-vendors' %}

View File

@ -24,6 +24,10 @@ SECRET_KEY = os.getenv('SECRET_KEY') if os.getenv('SECRET_KEY') else 'INSECURE_S
DEBUG = bool(int(os.getenv('DEBUG', True)))
INTERNAL_IPS = [
'127.0.0.1',
]
# allow djangos wsgi server to server mediafiles
GUNICORN_MEDIA = bool(int(os.getenv('GUNICORN_MEDIA', True)))
@ -74,6 +78,7 @@ INSTALLED_APPS = [
'rest_framework.authtoken',
'django_cleanup.apps.CleanupConfig',
'webpack_loader',
'django_js_reverse',
'cookbook.apps.CookbookConfig',
]

View File

@ -20,6 +20,7 @@ from django.contrib import admin
from django.urls import include, path
from django.views.i18n import JavaScriptCatalog
from django.views.static import serve
from django_js_reverse import views as reverse_views
urlpatterns = [
path('', include('cookbook.urls')),
@ -31,6 +32,7 @@ urlpatterns = [
JavaScriptCatalog.as_view(domain='django'),
name='javascript-catalog'
),
url(r'^jsreverse.json$', reverse_views.urls_js, name='js_reverse'),
]
if settings.GUNICORN_MEDIA or settings.DEBUG:

View File

@ -29,3 +29,4 @@ microdata==0.7.1
django-random-queryset==0.1.3
Jinja2==2.11.2
django-webpack-loader==0.7.0
django-js-reverse==0.9.1

View File

@ -1,6 +1,7 @@
<template>
<div id="app" v-if="!loading">
<h1>{{ recipe.name }}</h1>
<recipe-context-menu v-bind:recipe="recipe"></recipe-context-menu>
<img v-bind:src="recipe.image">
@ -17,31 +18,23 @@ import {BootstrapVue} from 'bootstrap-vue'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import {makeToast} from "@/utils/utils.js";
const _ = window.gettext
import {apiLoadRecipe} from "@/utils/api";
import Step from "@/components/Step";
import RecipeContextMenu from "@/components/RecipeContextMenu";
import {GettextMixin, ToastMixin} from "@/utils/utils";
Vue.use(BootstrapVue)
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
servings: 1
}
})
import {apiLoadRecipe} from "@/utils/django";
export default {
name: 'RecipeView',
store: store,
mixins: [
GettextMixin,
ToastMixin,
],
components: {
Step
Step,
RecipeContextMenu,
},
data() {
return {

View File

@ -0,0 +1,64 @@
<template>
<div>
{{ resolveDjangoUrl('api:recipe-detail', 5) }}
<div class="col col-md-4 d-print-none" style="text-align: right">
<div class="dropdown">
<a class="btn shadow-none" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v"></i>
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" :href="resolveDjangoUrl('edit_recipe', recipe.id)"><i
class="fas fa-pencil-alt fa-fw"></i> {{ _('Edit') }}</a>
<button class="dropdown-item" onclick="$('#bookmarkModal').modal({'show':true})">
<i class="fas fa-bookmark fa-fw"></i> {{ _('Add to Book') }}
</button>
<a class="dropdown-item" :href="recipe.name" v-if="true"> <!--TODO implement -->
<i class="fas fa-shopping-cart fa-fw"></i> {{ _('Add to Shopping') }} </a>
<a class="dropdown-item" :href="resolveDjangoUrl('new_meal_plan', recipe.id)"><i
class="fas fa-calendar fa-fw"></i> {{ _('Add to Plan') }}</a>
<!--
<button class="dropdown-item" :onclick="openCookLogModal(recipe.id)"><i
class="fas fa-clipboard-list fa-fw"></i> {{ _('Log Cooking') }}
</button>
-->
<button class="dropdown-item" onclick="window.print()"><i
class="fas fa-print fa-fw"></i> {{ _('Print') }}
</button>
<a class="dropdown-item" :href="resolveDjangoUrl('view_export', recipe.id)" target="_blank"
rel="noopener noreferrer"><i class="fas fa-file-export fa-fw"></i> {{ _('Export') }}</a>
<a class="dropdown-item" :href="resolveDjangoUrl('new_share_link', recipe.id)" target="_blank"
rel="noopener noreferrer" v-if="recipe.internal"><i class="fas fa-share-alt fa-fw"></i> {{
_('Share')
}}</a>
</div>
</div>
</div>
</div>
</template>
<script>
import {GettextMixin, ResolveUrlMixin} from "@/utils/utils";
export default {
name: 'RecipeContextMenu',
mixins: [
ResolveUrlMixin,
GettextMixin
],
props: {
recipe: Object,
}
}
</script>

View File

@ -0,0 +1,12 @@
import axios from "axios";
import {makeToast} from "@/utils/utils";
import {resolveDjangoUrl} from "@/utils/utils";
export function apiLoadRecipe(recipe_id) {
return axios.get(resolveDjangoUrl('api:recipe-detail', recipe_id)).then((response) => {
return response.data
}).catch((err) => {
console.log(err)
makeToast('Error', 'There was an error loading a resource!', 'danger')
})
}

View File

@ -1,12 +0,0 @@
import axios from "axios";
import {makeToast} from "@/utils/utils";
export function apiLoadRecipe(recipe_id) {
return axios.get(`/api/recipe/${recipe_id}`).then((response) => {
return response.data
}).catch((err) => {
console.log(err)
makeToast('Error', 'There was an error loading a resource!', 'danger')
})
}

View File

@ -1,4 +1,15 @@
import { BToast } from 'bootstrap-vue'
/*
* Utility functions to call bootstrap toasts
* */
import {BToast} from 'bootstrap-vue'
export const ToastMixin = {
methods: {
makeToast: function (title, message, variant = null) {
return makeToast(title, message, variant)
}
}
}
export function makeToast(title, message, variant = null) {
let toaster = new BToast()
@ -8,4 +19,46 @@ export function makeToast(title, message, variant = null) {
toaster: 'b-toaster-top-center',
solid: true
})
}
/*
* Utility functions to use djangos gettext
* */
export const GettextMixin = {
methods: {
/**
* uses djangos javascript gettext implementation to localize text
* @param {string} param string to translate
*/
_: function (param) {
return djangoGettext(param)
}
}
}
export function djangoGettext(param) {
return window.gettext(param)
}
/*
* Utility function to use djangos named urls
* */
// uses https://github.com/ierror/django-js-reverse#use-the-urls-in-javascript
export const ResolveUrlMixin = {
methods: {
/**
* Returns path of a django named URL
* @param {string} url name of url
* @param {*} params tuple of params to pass to django named url
*/
resolveDjangoUrl: function (url, params) {
return resolveDjangoUrl(url, params)
}
}
}
export function resolveDjangoUrl(url, params) {
return window.Urls[url](params)
}

View File

@ -1 +1 @@
{"status":"done","publicPath":"http://localhost:8080/","error":"ModuleError","message":"Module Error (from ./node_modules/eslint-loader/index.js):\n\nF:\\Developement\\Django\\recipes\\vue\\src\\apps\\RecipeView\\RecipeView.vue\n 47:11 error 'root_element' is not defined no-undef\n\n✖ 1 problem (1 error, 0 warnings)\n","chunks":{"chunk-vendors":[{"name":"js/chunk-vendors.js","publicPath":"http://localhost:8080/js/chunk-vendors.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\chunk-vendors.js"}],"recipe_view":[{"name":"js/recipe_view.js","publicPath":"http://localhost:8080/js/recipe_view.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\recipe_view.js"},{"name":"recipe_view.85b0fba40931a99bbc77.hot-update.js","publicPath":"http://localhost:8080/recipe_view.85b0fba40931a99bbc77.hot-update.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\recipe_view.85b0fba40931a99bbc77.hot-update.js"}]}}
{"status":"done","publicPath":"http://localhost:8080/","chunks":{"chunk-vendors":[{"name":"js/chunk-vendors.js","publicPath":"http://localhost:8080/js/chunk-vendors.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\chunk-vendors.js"}],"recipe_view":[{"name":"js/recipe_view.js","publicPath":"http://localhost:8080/js/recipe_view.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\recipe_view.js"},{"name":"recipe_view.298e10642301889fe8ed.hot-update.js","publicPath":"http://localhost:8080/recipe_view.298e10642301889fe8ed.hot-update.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\recipe_view.298e10642301889fe8ed.hot-update.js"}]},"error":"ModuleError","message":"Module Error (from ./node_modules/vue-loader/lib/loaders/templateLoader.js):\n(Emitted value instead of an instance of Error) \n\n Errors compiling template:\n\n href=\"{% url 'view_export' %}?r={{ recipe.pk }}\": Interpolation inside attributes has been removed. Use v-bind or the colon shorthand instead. For example, instead of <div id=\"{{ val }}\">, use <div :id=\"val\">.\n\n 34 | </button>\n 35 | \n 36 | <a class=\"dropdown-item\" href=\"{% url 'view_export' %}?r={{ recipe.pk }}\" target=\"_blank\"\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n 37 | rel=\"noopener noreferrer\"><i class=\"fas fa-file-export fa-fw\"></i> {% trans 'Export' %}</a>\n 38 | {% if recipe.internal %}\n"}