From e676b4bac365e1be1ab5cde41542156014fcc5d0 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Sun, 18 Apr 2021 14:05:19 +0200 Subject: [PATCH] added api pagination for recipes --- cookbook/helper/recipe_search.py | 4 +- cookbook/static/vue/js/recipe_search_view.js | 2 +- cookbook/views/api.py | 71 +++++++++++++++---- .../RecipeSearchView/RecipeSearchView.vue | 48 +++++++++---- 4 files changed, 95 insertions(+), 30 deletions(-) diff --git a/cookbook/helper/recipe_search.py b/cookbook/helper/recipe_search.py index 20988639..8e8d07f4 100644 --- a/cookbook/helper/recipe_search.py +++ b/cookbook/helper/recipe_search.py @@ -50,7 +50,7 @@ def search_recipes(queryset, params): if search_internal == 'true': queryset = queryset.filter(internal=True) - if search_limit: - queryset = queryset[:int(search_limit)] + # if search_limit: + # queryset = queryset[:int(search_limit)] return queryset diff --git a/cookbook/static/vue/js/recipe_search_view.js b/cookbook/static/vue/js/recipe_search_view.js index 05b57f5b..e69183b8 100644 --- a/cookbook/static/vue/js/recipe_search_view.js +++ b/cookbook/static/vue/js/recipe_search_view.js @@ -1 +1 @@ -(function(e){function t(t){for(var r,a,c=t[0],s=t[1],u=t[2],p=0,h=[];p0?n("div",e._l(e.recipe.keywords,(function(t){return n("small",{key:t.id,staticStyle:{padding:"2px"}},[n("b-badge",{attrs:{pill:"",variant:"light"}},[e._v(e._s(t.label))])],1)})),0):e._e()},i=[],o={name:"Keywords",props:{recipe:Object}},a=o,c=n("2877"),s=Object(c["a"])(a,r,i,!1,null,null,null);t["a"]=s.exports},9225:function(e,t,n){"use strict";n("159b"),n("d3b7"),n("ddb0"),n("466d"),n("ac1f");var r=n("a026"),i=n("a925");function o(){var e=n("49f8"),t={};return e.keys().forEach((function(n){var r=n.match(/([A-Za-z0-9-_]+)\./i);if(r&&r.length>1){var i=r[1];t[i]=e(n)}})),t}r["default"].use(i["a"]),t["a"]=new i["a"]({locale:Object({NODE_ENV:"production",BASE_URL:""}).VUE_APP_I18N_LOCALE||"en",fallbackLocale:Object({NODE_ENV:"production",BASE_URL:""}).VUE_APP_I18N_FALLBACK_LOCALE||"en",messages:o()})},a625:function(e){e.exports=JSON.parse('{"import_running":"Er wordt geïmporteerd, even geduld!","all_fields_optional":"Alle velden zijn optioneel en kunnen leeg gelaten worden.","convert_internal":"Zet om naar intern recept","Log_Recipe_Cooking":"Log Bereiding","External_Recipe_Image":"Externe Afbeelding Recept","Add_to_Book":"Voeg toe aan Boek","Add_to_Shopping":"Voeg toe aan Boodschappenlijst","Add_to_Plan":"Voeg toe aan Plan","Step_start_time":"Starttijd stap","Select_Book":"Selecteer Boek","Recipe_Image":"Afbeelding Recept","Import_finished":"Importeren gereed","View_Recipes":"Bekijk Recepten","Log_Cooking":"Log Bereiding","Proteins":"Proteïnes","Fats":"Vetten","Carbohydrates":"Koolhydraten","Calories":"Calorieën","Nutrition":"Voedingswaarde","Date":"Datum","Share":"Deel","Export":"Exporteer","Rating":"Waardering","Close":"Sluit","Add":"Voeg toe","Ingredients":"Ingrediënten","min":"min","Servings":"Porties","Waiting":"Wachten","Preparation":"Bereiding","Edit":"Bewerk","Open":"Open","Save":"Sla op","Step":"Stap","Search":"Zoeken","Import":"Importeer","Print":"Afdrukken","Information":"Informatie"}')},d76c:function(e,t,n){"use strict";var r=function(){var e=this,t=e.$createElement;e._self._c;return e._m(0)},i=[function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"row"},[n("div",{staticClass:"col",staticStyle:{"text-align":"center"}},[n("i",{staticClass:"fas fa-spinner fa-spin fa-10x"})])])}],o={name:"LoadingSpinner",props:{recipe:Object}},a=o,c=n("2877"),s=Object(c["a"])(a,r,i,!1,null,null,null);t["a"]=s.exports},edd4:function(e){e.exports=JSON.parse('{"import_running":"Import running, please wait!","all_fields_optional":"All fields are optional and can be left empty.","convert_internal":"Convert to internal recipe","show_only_internal":"Show only internal recipes","Log_Recipe_Cooking":"Log Recipe Cooking","External_Recipe_Image":"External Recipe Image","Add_to_Book":"Add to Book","Add_to_Shopping":"Add to Shopping","Add_to_Plan":"Add to Plan","Step_start_time":"Step start time","Select_Book":"Select Book","Recipe_Image":"Recipe Image","Import_finished":"Import finished","View_Recipes":"View Recipes","Log_Cooking":"Log Cooking","New_Recipe":"New Recipe","Url_Import":"Url Import","Reset_Search":"Reset Search","Keywords":"Keywords","Books":"Books","Proteins":"Proteins","Fats":"Fats","Carbohydrates":"Carbohydrates","Calories":"Calories","Nutrition":"Nutrition","Date":"Date","Share":"Share","Export":"Export","Rating":"Rating","Close":"Close","Add":"Add","Ingredients":"Ingredients","min":"min","Servings":"Servings","Waiting":"Waiting","Preparation":"Preparation","Edit":"Edit","Open":"Open","Save":"Save","Step":"Step","Search":"Search","Import":"Import","Print":"Print","or":"or","and":"and","Information":"Information"}')},fa7d:function(e,t,n){"use strict";n.d(t,"c",(function(){return o})),n.d(t,"f",(function(){return a})),n.d(t,"a",(function(){return c})),n.d(t,"e",(function(){return s})),n.d(t,"b",(function(){return u})),n.d(t,"g",(function(){return d})),n.d(t,"d",(function(){return h}));n("99af");var r=n("59e4");function i(e,t,n){var r=Math.floor(e),i=1,o=r+1,a=1;if(e!==r)while(i<=t&&a<=t){var c=(r+o)/(i+a);if(e===c){i+a<=t?(i+=a,r+=o,a=t+1):i>a?a=t+1:i=t+1;break}et&&(i=a,r=o),!n)return[0,r,i];var s=Math.floor(r/i);return[s,r-s*i,i]}var o={methods:{makeToast:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return a(e,t,n)}}};function a(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=new r["a"];i.$bvToast.toast(t,{title:e,variant:n,toaster:"b-toaster-top-center",solid:!0})}var c={methods:{_:function(e){return s(e)}}};function s(e){return window.gettext(e)}var u={methods:{resolveDjangoUrl:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return d(e,t)}}};function d(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return null!==t?window.Urls[e](t):window.Urls[e]()}function p(e){return window.USER_PREF[e]}function h(e,t){if(p("use_fractions")){var n="",r=i(e*t,9,!0);return r[0]>0&&(n+=r[0]),r[1]>0&&(n+=" ".concat(r[1],"").concat(r[2],"")),n}return b(e*t)}function b(e){var t=p("user_fractions")?p("user_fractions"):2;return+(Math.round(e+"e+".concat(t))+"e-".concat(t))}},fc0d:function(e,t,n){"use strict";var r=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("div",{staticClass:"dropdown"},[e._m(0),n("div",{staticClass:"dropdown-menu dropdown-menu-right",attrs:{"aria-labelledby":"dropdownMenuLink"}},[n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("edit_recipe",e.recipe.id)}},[n("i",{staticClass:"fas fa-pencil-alt fa-fw"}),e._v(" "+e._s(e.$t("Edit")))]),e.recipe.internal?e._e():n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("edit_convert_recipe",e.recipe.id)}},[n("i",{staticClass:"fas fa-exchange-alt fa-fw"}),e._v(" "+e._s(e.$t("convert_internal")))]),n("button",{staticClass:"dropdown-item",on:{click:function(t){return e.$bvModal.show("id_modal_add_book")}}},[n("i",{staticClass:"fas fa-bookmark fa-fw"}),e._v(" "+e._s(e.$t("Add_to_Book"))+" ")]),e.recipe.internal?n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("view_shopping")+"?r=["+e.recipe.id+","+e.servings_value+"]",target:"_blank",rel:"noopener noreferrer"}},[n("i",{staticClass:"fas fa-shopping-cart fa-fw"}),e._v(" "+e._s(e.$t("Add_to_Shopping"))+" ")]):e._e(),n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("new_meal_plan")+"?recipe="+e.recipe.id,target:"_blank",rel:"noopener noreferrer"}},[n("i",{staticClass:"fas fa-calendar fa-fw"}),e._v(" "+e._s(e.$t("Add_to_Plan"))+" ")]),n("button",{staticClass:"dropdown-item",on:{click:function(t){return e.$bvModal.show("id_modal_cook_log")}}},[n("i",{staticClass:"fas fa-clipboard-list fa-fw"}),e._v(" "+e._s(e.$t("Log_Cooking"))+" ")]),n("button",{staticClass:"dropdown-item",attrs:{onclick:"window.print()"}},[n("i",{staticClass:"fas fa-print fa-fw"}),e._v(" "+e._s(e.$t("Print"))+" ")]),n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("view_export")+"?r="+e.recipe.id,target:"_blank",rel:"noopener noreferrer"}},[n("i",{staticClass:"fas fa-file-export fa-fw"}),e._v(" "+e._s(e.$t("Export")))]),e.recipe.internal?n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("new_share_link",e.recipe.id),target:"_blank",rel:"noopener noreferrer"}},[n("i",{staticClass:"fas fa-share-alt fa-fw"}),e._v(" "+e._s(e.$t("Share")))]):e._e()])]),n("cook-log",{attrs:{recipe:e.recipe}})],1)},i=[function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("a",{staticClass:"btn shadow-none",attrs:{href:"#",role:"button",id:"dropdownMenuLink","data-toggle":"dropdown","aria-haspopup":"true","aria-expanded":"false"}},[n("i",{staticClass:"fas fa-ellipsis-v"})])}],o=(n("a9e3"),n("fa7d")),a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("b-modal",{staticClass:"modal",attrs:{id:"id_modal_cook_log",title:e.$t("Log_Recipe_Cooking"),"ok-title":e.$t("Save"),"cancel-title":e.$t("Close")},on:{ok:function(t){return e.logCook()}}},[n("p",[e._v(e._s(e.$t("all_fields_optional")))]),n("form",[n("label",{attrs:{for:"id_log_servings"}},[e._v(e._s(e.$t("Servings")))]),n("input",{directives:[{name:"model",rawName:"v-model",value:e.logObject.servings,expression:"logObject.servings"}],staticClass:"form-control",attrs:{type:"number",id:"id_log_servings"},domProps:{value:e.logObject.servings},on:{input:function(t){t.target.composing||e.$set(e.logObject,"servings",t.target.value)}}}),n("label",{staticStyle:{"margin-top":"2vh"}},[e._v(e._s(e.$t("Rating"))+" - "),n("span",{attrs:{id:"id_rating_show"}},[e._v(e._s(e.logObject.rating)+"/5")])]),n("b-form-rating",{model:{value:e.logObject.rating,callback:function(t){e.$set(e.logObject,"rating",t)},expression:"logObject.rating"}}),n("label",{staticStyle:{"margin-top":"2vh"},attrs:{for:"id_date"}},[e._v(e._s(e.$t("Date")))]),n("input",{directives:[{name:"model",rawName:"v-model",value:e.logObject.created_at,expression:"logObject.created_at"}],staticClass:"form-control",attrs:{type:"datetime-local",id:"id_date"},domProps:{value:e.logObject.created_at},on:{input:function(t){t.target.composing||e.$set(e.logObject,"created_at",t.target.value)}}})],1)])],1)},c=[],s=n("c1df"),u=n.n(s),d=n("a026"),p=n("5f5b"),h=n("7c15");d["default"].prototype.moment=u.a,d["default"].use(p["a"]);var b={name:"CookLog",props:{recipe:Object},data:function(){return{logObject:{recipe:this.recipe.id,servings:0,rating:0,created_at:u()().format("yyyy-MM-DDTHH:mm")}}},methods:{logCook:function(){Object(h["d"])(this.logObject)}}},f=b,l=n("2877"),j=Object(l["a"])(f,a,c,!1,null,null,null),O=j.exports,v={name:"RecipeContextMenu",mixins:[o["b"]],components:{CookLog:O},data:function(){return{servings_value:0}},props:{recipe:Object,servings:{type:Number,default:-1}},mounted:function(){this.servings_value=-1===this.servings?this.recipe.servings:this.servings}},g=v,y=Object(l["a"])(g,r,i,!1,null,null,null);t["a"]=y.exports}}); \ No newline at end of file +(function(e){function t(t){for(var r,a,c=t[0],s=t[1],u=t[2],p=0,h=[];p0?n("div",e._l(e.recipe.keywords,(function(t){return n("small",{key:t.id,staticStyle:{padding:"2px"}},[n("b-badge",{attrs:{pill:"",variant:"light"}},[e._v(e._s(t.label))])],1)})),0):e._e()},i=[],o={name:"Keywords",props:{recipe:Object}},a=o,c=n("2877"),s=Object(c["a"])(a,r,i,!1,null,null,null);t["a"]=s.exports},9225:function(e,t,n){"use strict";n("159b"),n("d3b7"),n("ddb0"),n("466d"),n("ac1f");var r=n("a026"),i=n("a925");function o(){var e=n("49f8"),t={};return e.keys().forEach((function(n){var r=n.match(/([A-Za-z0-9-_]+)\./i);if(r&&r.length>1){var i=r[1];t[i]=e(n)}})),t}r["default"].use(i["a"]),t["a"]=new i["a"]({locale:Object({NODE_ENV:"production",BASE_URL:""}).VUE_APP_I18N_LOCALE||"en",fallbackLocale:Object({NODE_ENV:"production",BASE_URL:""}).VUE_APP_I18N_FALLBACK_LOCALE||"en",messages:o()})},a625:function(e){e.exports=JSON.parse('{"import_running":"Er wordt geïmporteerd, even geduld!","all_fields_optional":"Alle velden zijn optioneel en kunnen leeg gelaten worden.","convert_internal":"Zet om naar intern recept","Log_Recipe_Cooking":"Log Bereiding","External_Recipe_Image":"Externe Afbeelding Recept","Add_to_Book":"Voeg toe aan Boek","Add_to_Shopping":"Voeg toe aan Boodschappenlijst","Add_to_Plan":"Voeg toe aan Plan","Step_start_time":"Starttijd stap","Select_Book":"Selecteer Boek","Recipe_Image":"Afbeelding Recept","Import_finished":"Importeren gereed","View_Recipes":"Bekijk Recepten","Log_Cooking":"Log Bereiding","Proteins":"Proteïnes","Fats":"Vetten","Carbohydrates":"Koolhydraten","Calories":"Calorieën","Nutrition":"Voedingswaarde","Date":"Datum","Share":"Deel","Export":"Exporteer","Rating":"Waardering","Close":"Sluit","Add":"Voeg toe","Ingredients":"Ingrediënten","min":"min","Servings":"Porties","Waiting":"Wachten","Preparation":"Bereiding","Edit":"Bewerk","Open":"Open","Save":"Sla op","Step":"Stap","Search":"Zoeken","Import":"Importeer","Print":"Afdrukken","Information":"Informatie"}')},d76c:function(e,t,n){"use strict";var r=function(){var e=this,t=e.$createElement;e._self._c;return e._m(0)},i=[function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"row"},[n("div",{staticClass:"col",staticStyle:{"text-align":"center"}},[n("i",{staticClass:"fas fa-spinner fa-spin fa-10x"})])])}],o={name:"LoadingSpinner",props:{recipe:Object}},a=o,c=n("2877"),s=Object(c["a"])(a,r,i,!1,null,null,null);t["a"]=s.exports},edd4:function(e){e.exports=JSON.parse('{"import_running":"Import running, please wait!","all_fields_optional":"All fields are optional and can be left empty.","convert_internal":"Convert to internal recipe","show_only_internal":"Show only internal recipes","Log_Recipe_Cooking":"Log Recipe Cooking","External_Recipe_Image":"External Recipe Image","Add_to_Book":"Add to Book","Add_to_Shopping":"Add to Shopping","Add_to_Plan":"Add to Plan","Step_start_time":"Step start time","Select_Book":"Select Book","Recipe_Image":"Recipe Image","Import_finished":"Import finished","View_Recipes":"View Recipes","Log_Cooking":"Log Cooking","New_Recipe":"New Recipe","Url_Import":"Url Import","Reset_Search":"Reset Search","Keywords":"Keywords","Books":"Books","Proteins":"Proteins","Fats":"Fats","Carbohydrates":"Carbohydrates","Calories":"Calories","Nutrition":"Nutrition","Date":"Date","Share":"Share","Export":"Export","Rating":"Rating","Close":"Close","Add":"Add","Ingredients":"Ingredients","min":"min","Servings":"Servings","Waiting":"Waiting","Preparation":"Preparation","Edit":"Edit","Open":"Open","Save":"Save","Step":"Step","Search":"Search","Import":"Import","Print":"Print","or":"or","and":"and","Information":"Information"}')},fa7d:function(e,t,n){"use strict";n.d(t,"c",(function(){return o})),n.d(t,"f",(function(){return a})),n.d(t,"a",(function(){return c})),n.d(t,"e",(function(){return s})),n.d(t,"b",(function(){return u})),n.d(t,"g",(function(){return d})),n.d(t,"d",(function(){return h}));n("99af");var r=n("59e4");function i(e,t,n){var r=Math.floor(e),i=1,o=r+1,a=1;if(e!==r)while(i<=t&&a<=t){var c=(r+o)/(i+a);if(e===c){i+a<=t?(i+=a,r+=o,a=t+1):i>a?a=t+1:i=t+1;break}et&&(i=a,r=o),!n)return[0,r,i];var s=Math.floor(r/i);return[s,r-s*i,i]}var o={methods:{makeToast:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return a(e,t,n)}}};function a(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=new r["a"];i.$bvToast.toast(t,{title:e,variant:n,toaster:"b-toaster-top-center",solid:!0})}var c={methods:{_:function(e){return s(e)}}};function s(e){return window.gettext(e)}var u={methods:{resolveDjangoUrl:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return d(e,t)}}};function d(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return null!==t?window.Urls[e](t):window.Urls[e]()}function p(e){return window.USER_PREF[e]}function h(e,t){if(p("use_fractions")){var n="",r=i(e*t,9,!0);return r[0]>0&&(n+=r[0]),r[1]>0&&(n+=" ".concat(r[1],"").concat(r[2],"")),n}return b(e*t)}function b(e){var t=p("user_fractions")?p("user_fractions"):2;return+(Math.round(e+"e+".concat(t))+"e-".concat(t))}},fc0d:function(e,t,n){"use strict";var r=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("div",{staticClass:"dropdown"},[e._m(0),n("div",{staticClass:"dropdown-menu dropdown-menu-right",attrs:{"aria-labelledby":"dropdownMenuLink"}},[n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("edit_recipe",e.recipe.id)}},[n("i",{staticClass:"fas fa-pencil-alt fa-fw"}),e._v(" "+e._s(e.$t("Edit")))]),e.recipe.internal?e._e():n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("edit_convert_recipe",e.recipe.id)}},[n("i",{staticClass:"fas fa-exchange-alt fa-fw"}),e._v(" "+e._s(e.$t("convert_internal")))]),n("button",{staticClass:"dropdown-item",on:{click:function(t){return e.$bvModal.show("id_modal_add_book")}}},[n("i",{staticClass:"fas fa-bookmark fa-fw"}),e._v(" "+e._s(e.$t("Add_to_Book"))+" ")]),e.recipe.internal?n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("view_shopping")+"?r=["+e.recipe.id+","+e.servings_value+"]",target:"_blank",rel:"noopener noreferrer"}},[n("i",{staticClass:"fas fa-shopping-cart fa-fw"}),e._v(" "+e._s(e.$t("Add_to_Shopping"))+" ")]):e._e(),n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("new_meal_plan")+"?recipe="+e.recipe.id,target:"_blank",rel:"noopener noreferrer"}},[n("i",{staticClass:"fas fa-calendar fa-fw"}),e._v(" "+e._s(e.$t("Add_to_Plan"))+" ")]),n("button",{staticClass:"dropdown-item",on:{click:function(t){return e.$bvModal.show("id_modal_cook_log")}}},[n("i",{staticClass:"fas fa-clipboard-list fa-fw"}),e._v(" "+e._s(e.$t("Log_Cooking"))+" ")]),n("button",{staticClass:"dropdown-item",attrs:{onclick:"window.print()"}},[n("i",{staticClass:"fas fa-print fa-fw"}),e._v(" "+e._s(e.$t("Print"))+" ")]),n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("view_export")+"?r="+e.recipe.id,target:"_blank",rel:"noopener noreferrer"}},[n("i",{staticClass:"fas fa-file-export fa-fw"}),e._v(" "+e._s(e.$t("Export")))]),e.recipe.internal?n("a",{staticClass:"dropdown-item",attrs:{href:e.resolveDjangoUrl("new_share_link",e.recipe.id),target:"_blank",rel:"noopener noreferrer"}},[n("i",{staticClass:"fas fa-share-alt fa-fw"}),e._v(" "+e._s(e.$t("Share")))]):e._e()])]),n("cook-log",{attrs:{recipe:e.recipe}})],1)},i=[function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("a",{staticClass:"btn shadow-none",attrs:{href:"#",role:"button",id:"dropdownMenuLink","data-toggle":"dropdown","aria-haspopup":"true","aria-expanded":"false"}},[n("i",{staticClass:"fas fa-ellipsis-v"})])}],o=(n("a9e3"),n("fa7d")),a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("b-modal",{staticClass:"modal",attrs:{id:"id_modal_cook_log",title:e.$t("Log_Recipe_Cooking"),"ok-title":e.$t("Save"),"cancel-title":e.$t("Close")},on:{ok:function(t){return e.logCook()}}},[n("p",[e._v(e._s(e.$t("all_fields_optional")))]),n("form",[n("label",{attrs:{for:"id_log_servings"}},[e._v(e._s(e.$t("Servings")))]),n("input",{directives:[{name:"model",rawName:"v-model",value:e.logObject.servings,expression:"logObject.servings"}],staticClass:"form-control",attrs:{type:"number",id:"id_log_servings"},domProps:{value:e.logObject.servings},on:{input:function(t){t.target.composing||e.$set(e.logObject,"servings",t.target.value)}}}),n("label",{staticStyle:{"margin-top":"2vh"}},[e._v(e._s(e.$t("Rating"))+" - "),n("span",{attrs:{id:"id_rating_show"}},[e._v(e._s(e.logObject.rating)+"/5")])]),n("b-form-rating",{model:{value:e.logObject.rating,callback:function(t){e.$set(e.logObject,"rating",t)},expression:"logObject.rating"}}),n("label",{staticStyle:{"margin-top":"2vh"},attrs:{for:"id_date"}},[e._v(e._s(e.$t("Date")))]),n("input",{directives:[{name:"model",rawName:"v-model",value:e.logObject.created_at,expression:"logObject.created_at"}],staticClass:"form-control",attrs:{type:"datetime-local",id:"id_date"},domProps:{value:e.logObject.created_at},on:{input:function(t){t.target.composing||e.$set(e.logObject,"created_at",t.target.value)}}})],1)])],1)},c=[],s=n("c1df"),u=n.n(s),d=n("a026"),p=n("5f5b"),h=n("7c15");d["default"].prototype.moment=u.a,d["default"].use(p["a"]);var b={name:"CookLog",props:{recipe:Object},data:function(){return{logObject:{recipe:this.recipe.id,servings:0,rating:0,created_at:u()().format("yyyy-MM-DDTHH:mm")}}},methods:{logCook:function(){Object(h["d"])(this.logObject)}}},f=b,l=n("2877"),j=Object(l["a"])(f,a,c,!1,null,null,null),O=j.exports,v={name:"RecipeContextMenu",mixins:[o["b"]],components:{CookLog:O},data:function(){return{servings_value:0}},props:{recipe:Object,servings:{type:Number,default:-1}},mounted:function(){this.servings_value=-1===this.servings?this.recipe.servings:this.servings}},g=v,y=Object(l["a"])(g,r,i,!1,null,null,null);t["a"]=y.exports}}); \ No newline at end of file diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 1f9b9521..76f147c3 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -4,6 +4,7 @@ import re import uuid import requests +import yaml from PIL import Image from annoying.decorators import ajax_request from annoying.functions import get_object_or_None @@ -19,8 +20,10 @@ from django.utils.translation import gettext as _ from icalendar import Calendar, Event from rest_framework import decorators, viewsets, status from rest_framework.exceptions import APIException, PermissionDenied, NotFound, MethodNotAllowed +from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination from rest_framework.parsers import MultiPartParser from rest_framework.response import Response +from rest_framework.schemas import AutoSchema from rest_framework.viewsets import ViewSetMixin from cookbook.helper.ingredient_parser import parse @@ -49,7 +52,8 @@ from cookbook.serializer import (FoodSerializer, IngredientSerializer, StorageSerializer, SyncLogSerializer, SyncSerializer, UnitSerializer, UserNameSerializer, UserPreferenceSerializer, - ViewLogSerializer, CookLogSerializer, RecipeBookEntrySerializer, RecipeOverviewSerializer, SupermarketSerializer, ImportLogSerializer) + ViewLogSerializer, CookLogSerializer, RecipeBookEntrySerializer, + RecipeOverviewSerializer, SupermarketSerializer, ImportLogSerializer) from recipes.settings import DEMO from recipe_scrapers import scrape_me, WebsiteNotImplementedError, NoSchemaFoundInWildMode @@ -248,7 +252,8 @@ class MealTypeViewSet(viewsets.ModelViewSet): permission_classes = [CustomIsOwner] def get_queryset(self): - queryset = self.queryset.order_by('order', 'id').filter(created_by=self.request.user).filter(space=self.request.space).all() + queryset = self.queryset.order_by('order', 'id').filter(created_by=self.request.user).filter( + space=self.request.space).all() return queryset @@ -270,29 +275,59 @@ class StepViewSet(viewsets.ModelViewSet): return self.queryset.filter(recipe__space=self.request.space) +class RecipePagination(PageNumberPagination): + page_size = 25 + page_size_query_param = 'page_size' + max_page_size = 100 + + +from rest_framework.schemas.openapi import AutoSchema, SchemaGenerator + + +class RecipeSchema(AutoSchema): + + def get_path_parameters(self, path, method): + parameters = super().get_path_parameters(path, method) + parameters.append( + { + "name": 'query', + "in": "path", + "required": True, + "description": 'description', + 'schema': { + 'type': 'string', # TODO: integer, pattern, ... + }, + } + ) + return parameters + + class RecipeViewSet(viewsets.ModelViewSet): """ - list: - optional parameters - - - **query**: search recipes for a string contained - in the recipe name (case in-sensitive) - - **limit**: limits the amount of returned results - """ + list: + optional parameters + - **query**: search recipes for a string contained in the recipe name (case in-sensitive) + - **limit**: limits the amount of returned results + """ queryset = Recipe.objects serializer_class = RecipeSerializer # TODO split read and write permission for meal plan guest permission_classes = [CustomIsShare | CustomIsGuest] + pagination_class = RecipePagination + + # schema = RecipeSchema + def get_queryset(self): share = self.request.query_params.get('share', None) if not (share and self.detail): self.queryset = self.queryset.filter(space=self.request.space) - return search_recipes(self.queryset, self.request.GET) + self.queryset = search_recipes(self.queryset, self.request.GET) + + return super().get_queryset() # TODO write extensive tests for permissions - def get_serializer_class(self): if self.action == 'list': return RecipeOverviewSerializer @@ -341,7 +376,9 @@ class ShoppingListRecipeViewSet(viewsets.ModelViewSet): permission_classes = [CustomIsOwner | CustomIsShared] def get_queryset(self): - return self.queryset.filter(Q(shoppinglist__created_by=self.request.user) | Q(shoppinglist__shared=self.request.user)).filter(shoppinglist__space=self.request.space).all() + return self.queryset.filter( + Q(shoppinglist__created_by=self.request.user) | Q(shoppinglist__shared=self.request.user)).filter( + shoppinglist__space=self.request.space).all() class ShoppingListEntryViewSet(viewsets.ModelViewSet): @@ -350,7 +387,9 @@ class ShoppingListEntryViewSet(viewsets.ModelViewSet): permission_classes = [CustomIsOwner | CustomIsShared] def get_queryset(self): - return self.queryset.filter(Q(shoppinglist__created_by=self.request.user) | Q(shoppinglist__shared=self.request.user)).filter(shoppinglist__space=self.request.space).all() + return self.queryset.filter( + Q(shoppinglist__created_by=self.request.user) | Q(shoppinglist__shared=self.request.user)).filter( + shoppinglist__space=self.request.space).all() class ShoppingListViewSet(viewsets.ModelViewSet): @@ -359,7 +398,8 @@ class ShoppingListViewSet(viewsets.ModelViewSet): permission_classes = [CustomIsOwner | CustomIsShared] def get_queryset(self): - return self.queryset.filter(Q(created_by=self.request.user) | Q(shared=self.request.user)).filter(space=self.request.space).distinct() + return self.queryset.filter(Q(created_by=self.request.user) | Q(shared=self.request.user)).filter( + space=self.request.space).distinct() def get_serializer_class(self): try: @@ -562,7 +602,8 @@ def recipe_from_url_old(request): url = request.POST['url'] headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36' # noqa: E501 + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36' + # noqa: E501 } try: response = requests.get(url, headers=headers) diff --git a/vue/src/apps/RecipeSearchView/RecipeSearchView.vue b/vue/src/apps/RecipeSearchView/RecipeSearchView.vue index ccf28bae..64a773fd 100644 --- a/vue/src/apps/RecipeSearchView/RecipeSearchView.vue +++ b/vue/src/apps/RecipeSearchView/RecipeSearchView.vue @@ -51,7 +51,6 @@ -
@@ -60,11 +59,12 @@ - - + + @@ -83,10 +83,11 @@ - - + + {{ $t('or') }} @@ -105,10 +106,11 @@ - - + + @@ -139,6 +141,21 @@
+ +
+
+ + + +
+
+ +
@@ -185,6 +202,8 @@ export default { advanced_search_visible: true, + pagination_count: 0, + pagination_page: 1, } }, @@ -213,10 +232,11 @@ export default { books_or: this.search_books_or, internal: this.search_internal, - limit: 20, + page: this.pagination_page, } }).then(result => { - this.recipes = result.data + this.recipes = result.data.results + this.pagination_count = result.data.count }) }, genericSelectChanged: function (obj) { @@ -230,6 +250,10 @@ export default { this.search_foods = [] this.search_books = [] this.refreshData() + }, + pageChange: function (page){ + this.pagination_page = page + this.refreshData() } } }