per user meal types
This commit is contained in:
parent
c714ff4dbe
commit
8aa24d4771
21
cookbook/migrations/0049_mealtype_created_by.py
Normal file
21
cookbook/migrations/0049_mealtype_created_by.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 3.0.7 on 2020-06-11 13:08
|
||||||
|
|
||||||
|
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', '0048_auto_20200602_1140'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='mealtype',
|
||||||
|
name='created_by',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
30
cookbook/migrations/0050_auto_20200611_1509.py
Normal file
30
cookbook/migrations/0050_auto_20200611_1509.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Generated by Django 3.0.7 on 2020-06-11 13:09
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_meal_types(apps, schema_editor):
|
||||||
|
MealPlan = apps.get_model('cookbook', 'MealPlan')
|
||||||
|
MealType = apps.get_model('cookbook', 'MealType')
|
||||||
|
User = apps.get_model('auth', 'User')
|
||||||
|
|
||||||
|
for u in User.objects.all():
|
||||||
|
for t in MealType.objects.filter(created_by=None).all():
|
||||||
|
user_type = MealType.objects.create(
|
||||||
|
name=t.name,
|
||||||
|
created_by=u,
|
||||||
|
)
|
||||||
|
MealPlan.objects.filter(Q(created_by=u) and Q(meal_type=t)).update(meal_type=user_type)
|
||||||
|
|
||||||
|
MealType.objects.filter(created_by=None).delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('cookbook', '0049_mealtype_created_by'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(migrate_meal_types),
|
||||||
|
]
|
21
cookbook/migrations/0051_auto_20200611_1518.py
Normal file
21
cookbook/migrations/0051_auto_20200611_1518.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 3.0.7 on 2020-06-11 13:18
|
||||||
|
|
||||||
|
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', '0050_auto_20200611_1509'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='mealtype',
|
||||||
|
name='created_by',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
@ -214,6 +214,7 @@ class RecipeBookEntry(models.Model):
|
|||||||
class MealType(models.Model):
|
class MealType(models.Model):
|
||||||
name = models.CharField(max_length=128)
|
name = models.CharField(max_length=128)
|
||||||
order = models.IntegerField(default=0)
|
order = models.IntegerField(default=0)
|
||||||
|
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -49,6 +49,8 @@
|
|||||||
<thead class="thead-dark">
|
<thead class="thead-dark">
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="d in days" style="width: 14.2%; text-align: center">[[d]]<br/>[[formatDateDay(d)]].
|
<th v-for="d in days" style="width: 14.2%; text-align: center">[[d]]<br/>[[formatDateDay(d)]].
|
||||||
|
<button class="btn btn-sm btn-outline-secondary" @click="addDayToShopping(d)"><i
|
||||||
|
class="fas fa-cart-plus fa-sm"></i></button>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -62,7 +64,7 @@
|
|||||||
<td v-for="d in mp.days">
|
<td v-for="d in mp.days">
|
||||||
<draggable class="list-group" :list="d.items" group="plan" style="min-height: 40px"
|
<draggable class="list-group" :list="d.items" group="plan" style="min-height: 40px"
|
||||||
@change="dragChanged(d.date, mp.meal_type, $event)"
|
@change="dragChanged(d.date, mp.meal_type, $event)"
|
||||||
:empty-insert-threshold="10" :options="{handle:'.handle'}">
|
:empty-insert-threshold="10" handle=".handle">
|
||||||
<div class="" v-for="(element, index) in d.items" :key="element.id">
|
<div class="" v-for="(element, index) in d.items" :key="element.id">
|
||||||
<div class="d-block d-md-none">
|
<div class="d-block d-md-none">
|
||||||
|
|
||||||
@ -93,7 +95,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr/>
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<i class="fas fa-calendar-plus"></i> {% trans 'New Entry' %}
|
<i class="fas fa-calendar-plus"></i> {% trans 'New Entry' %}
|
||||||
@ -112,7 +113,7 @@
|
|||||||
<draggable class="list-group" :list="recipes"
|
<draggable class="list-group" :list="recipes"
|
||||||
:group="{ name: 'plan', pull: 'clone', put: false }" :clone="cloneRecipe">
|
:group="{ name: 'plan', pull: 'clone', put: false }" :clone="cloneRecipe">
|
||||||
<div class="list-group-item" v-for="(element, index) in recipes" :key="element.id">
|
<div class="list-group-item" v-for="(element, index) in recipes" :key="element.id">
|
||||||
<i class="fas fa-arrows-alt"></i> <a href="#">[[element.name]]</a>
|
<i class="fas fa-arrows-alt"></i> [[element.name]]
|
||||||
</div>
|
</div>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
@ -141,6 +142,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fas fa-shopping-cart"></i> {% trans 'Shopping List' %}
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card-body">
|
||||||
|
<template v-if="shopping_list.length < 1">{% trans 'Shopping List currently empty' %}</template>
|
||||||
|
<template v-else>
|
||||||
|
<a v-bind:href="getShoppingUrl()" class="btn btn-success"
|
||||||
|
target="_blank">{% trans 'Open Shopping List' %}</a>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
{% trans 'Recipes' %}
|
||||||
|
<ul class="list-group" style="margin-top: 8px">
|
||||||
|
<li class="list-group-item" v-for="item in shopping_list"> [[ item.recipe_name ]]</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<hr/>
|
<hr/>
|
||||||
<br/>
|
<br/>
|
||||||
@ -192,6 +223,9 @@
|
|||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-danger"
|
<button type="button" class="btn btn-danger"
|
||||||
@click="deleteEntry(plan_detail)">{% trans 'Delete' %}</button>
|
@click="deleteEntry(plan_detail)">{% trans 'Delete' %}</button>
|
||||||
|
<button type="button" class="btn btn-success"
|
||||||
|
v-if="!shopping_list.includes(plan_detail) && plan_detail.recipe_name !== undefined"
|
||||||
|
@click="shopping_list.push(plan_detail)">{% trans 'Add to Shopping' %}</button>
|
||||||
<a class="btn btn-primary" v-bind:href="planDetailEditUrl()">{% trans 'Edit' %}</a>
|
<a class="btn btn-primary" v-bind:href="planDetailEditUrl()">{% trans 'Edit' %}</a>
|
||||||
<button type="button" class="btn btn-secondary"
|
<button type="button" class="btn btn-secondary"
|
||||||
data-dismiss="modal">{% trans 'Close' %}</button>
|
data-dismiss="modal">{% trans 'Close' %}</button>
|
||||||
@ -229,6 +263,8 @@
|
|||||||
default_shared_users: [],
|
default_shared_users: [],
|
||||||
user_id_update: [],
|
user_id_update: [],
|
||||||
user_names: {},
|
user_names: {},
|
||||||
|
shopping: false,
|
||||||
|
shopping_list: [],
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
console.log("MOUNTED")
|
console.log("MOUNTED")
|
||||||
@ -427,6 +463,32 @@
|
|||||||
changeWeek: function (change) {
|
changeWeek: function (change) {
|
||||||
this.week = moment(this.week).add(change, 'w').format('YYYY-[W]WW')
|
this.week = moment(this.week).add(change, 'w').format('YYYY-[W]WW')
|
||||||
this.updatePlan();
|
this.updatePlan();
|
||||||
|
},
|
||||||
|
getShoppingUrl: function () {
|
||||||
|
let url = "{% url 'view_shopping' %}"
|
||||||
|
let first = true
|
||||||
|
for (let se of this.shopping_list) {
|
||||||
|
if (first) {
|
||||||
|
url += `?r=${se.recipe}`
|
||||||
|
first = false
|
||||||
|
} else {
|
||||||
|
url += `&r=${se.recipe}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
},
|
||||||
|
addDayToShopping: function (day) {
|
||||||
|
let date = moment(this.week).weekday(this.days.indexOf(day)).format('YYYY-MM-DD')
|
||||||
|
|
||||||
|
for (let t of this.meal_types) {
|
||||||
|
console.log(t.id, date)
|
||||||
|
for (let i of this.meal_plan[t.id].days[date].items) {
|
||||||
|
if (!this.shopping_list.includes(i)) {
|
||||||
|
console.log("adding ", i)
|
||||||
|
this.shopping_list.push(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from annoying.decorators import ajax_request
|
from annoying.decorators import ajax_request
|
||||||
@ -10,8 +9,8 @@ from django.db.models import Q
|
|||||||
from django.http import HttpResponse, FileResponse
|
from django.http import HttpResponse, FileResponse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from rest_framework import viewsets, permissions, serializers
|
from rest_framework import viewsets, permissions
|
||||||
from rest_framework.exceptions import ValidationError, APIException
|
from rest_framework.exceptions import APIException
|
||||||
|
|
||||||
from cookbook.helper.permission_helper import group_required
|
from cookbook.helper.permission_helper import group_required
|
||||||
from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog
|
from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog
|
||||||
@ -57,6 +56,10 @@ class MealTypeViewSet(viewsets.ModelViewSet):
|
|||||||
serializer_class = MealTypeSerializer
|
serializer_class = MealTypeSerializer
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = MealType.objects.filter(created_by=self.request.user).all()
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class RecipeViewSet(viewsets.ModelViewSet):
|
class RecipeViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Recipe.objects.all()
|
queryset = Recipe.objects.all()
|
||||||
@ -81,11 +84,12 @@ class ViewLogViewSet(viewsets.ModelViewSet):
|
|||||||
permission_classes = [permissions.IsAuthenticated]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
# TODO user + unique filter
|
queryset = ViewLog.objects.filter(created_by=self.request.user).all()[:5]
|
||||||
queryset = ViewLog.objects.all()[:5]
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
# -------------- non django rest api views --------------------
|
||||||
|
|
||||||
def get_recipe_provider(recipe):
|
def get_recipe_provider(recipe):
|
||||||
if recipe.storage.method == Storage.DROPBOX:
|
if recipe.storage.method == Storage.DROPBOX:
|
||||||
return Dropbox
|
return Dropbox
|
||||||
|
Loading…
Reference in New Issue
Block a user