import copy from datetime import datetime, timedelta from django.contrib import messages from django.contrib.auth import update_session_auth_hash, authenticate from django.contrib.auth.forms import PasswordChangeForm from django.contrib.auth.password_validation import validate_password from django.core.exceptions import ValidationError from django.db.models import Q from django.http import HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.utils import timezone from django_tables2 import RequestConfig from django.utils.translation import gettext as _ from django.conf import settings from cookbook.filters import RecipeFilter from cookbook.forms import * from cookbook.helper.permission_helper import group_required from cookbook.tables import RecipeTable, RecipeTableSmall, CookLogTable, ViewLogTable def index(request): if not request.user.is_authenticated: return HttpResponseRedirect(reverse_lazy('view_search')) try: page_map = { UserPreference.SEARCH: reverse_lazy('view_search'), UserPreference.PLAN: reverse_lazy('view_plan'), UserPreference.BOOKS: reverse_lazy('view_books'), } return HttpResponseRedirect(page_map.get(request.user.userpreference.default_page)) except UserPreference.DoesNotExist: return HttpResponseRedirect(reverse_lazy('view_search')) def search(request): if request.user.is_authenticated: f = RecipeFilter(request.GET, queryset=Recipe.objects.all().order_by('name')) if request.user.userpreference.search_style == UserPreference.LARGE: table = RecipeTable(f.qs) else: table = RecipeTableSmall(f.qs) RequestConfig(request, paginate={'per_page': 25}).configure(table) if request.GET == {} and request.user.userpreference.show_recent: qs = Recipe.objects.filter(viewlog__created_by=request.user).order_by('-viewlog__created_at').all() recent_list = [] for r in qs: if r not in recent_list: recent_list.append(r) if len(recent_list) >= 5: break last_viewed = RecipeTable(recent_list) else: last_viewed = None return render(request, 'index.html', {'recipes': table, 'filter': f, 'last_viewed': last_viewed}) else: return render(request, 'index.html') @group_required('guest') def recipe_view(request, pk): recipe = get_object_or_404(Recipe, pk=pk) ingredients = RecipeIngredient.objects.filter(recipe=recipe) comments = Comment.objects.filter(recipe=recipe) if request.method == "POST": comment_form = CommentForm(request.POST, prefix='comment') if comment_form.is_valid(): comment = Comment() comment.recipe = recipe comment.text = comment_form.cleaned_data['text'] comment.created_by = request.user comment.save() messages.add_message(request, messages.SUCCESS, _('Comment saved!')) bookmark_form = RecipeBookEntryForm(request.POST, prefix='bookmark') if bookmark_form.is_valid(): bookmark = RecipeBookEntry() bookmark.recipe = recipe bookmark.book = bookmark_form.cleaned_data['book'] bookmark.save() messages.add_message(request, messages.SUCCESS, _('Bookmark saved!')) comment_form = CommentForm() bookmark_form = RecipeBookEntryForm() if request.user.is_authenticated: if not ViewLog.objects.filter(recipe=recipe).filter(created_by=request.user).filter(created_at__gt=(timezone.now() - timezone.timedelta(minutes=5))).exists(): ViewLog.objects.create(recipe=recipe, created_by=request.user) return render(request, 'recipe_view.html', {'recipe': recipe, 'ingredients': ingredients, 'comments': comments, 'comment_form': comment_form, 'bookmark_form': bookmark_form}) @group_required('user') def books(request): book_list = [] books = RecipeBook.objects.filter(Q(created_by=request.user) | Q(shared=request.user)).distinct().all() for b in books: book_list.append({'book': b, 'recipes': RecipeBookEntry.objects.filter(book=b).all()}) return render(request, 'books.html', {'book_list': book_list}) def get_start_end_from_week(p_year, p_week): first_day_of_week = datetime.strptime(f'{p_year}-W{int(p_week) - 1}-1', "%Y-W%W-%w").date() last_day_of_week = first_day_of_week + timedelta(days=6.9) return first_day_of_week, last_day_of_week def get_days_from_week(start, end): delta = end - start days = [] for i in range(delta.days + 1): days.append(start + timedelta(days=i)) return days @group_required('user') def meal_plan(request): js_week = datetime.now().strftime("%Y-W%V") if request.method == "POST": js_week = request.POST['week'] year, week = js_week.split('-') first_day, last_day = get_start_end_from_week(year, week.replace('W', '')) surrounding_weeks = {'next': (last_day + timedelta(3)).strftime("%Y-W%V"), 'prev': (first_day - timedelta(3)).strftime("%Y-W%V")} days = get_days_from_week(first_day, last_day) days_dict = {} for d in days: days_dict[d] = [] plan = {} for t in MealPlan.MEAL_TYPES: plan[t[0]] = {'type_name': t[1], 'days': copy.deepcopy(days_dict)} for d in days: plan_day = MealPlan.objects.filter(date=d).filter(Q(created_by=request.user) | Q(shared=request.user)).distinct().all() for p in plan_day: plan[p.meal]['days'][d].append(p) return render(request, 'meal_plan.html', {'js_week': js_week, 'plan': plan, 'days': days, 'surrounding_weeks': surrounding_weeks}) @group_required('user') def meal_plan_entry(request, pk): plan = MealPlan.objects.get(pk=pk) if plan.created_by != request.user and plan.shared != request.user: messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!')) return HttpResponseRedirect(reverse_lazy('index')) same_day_plan = MealPlan.objects.filter(date=plan.date).exclude(pk=plan.pk).filter(Q(created_by=request.user) | Q(shared=request.user)).order_by('meal').all() return render(request, 'meal_plan_entry.html', {'plan': plan, 'same_day_plan': same_day_plan}) @group_required('user') def shopping_list(request): markdown_format = True if request.method == "POST": form = ShoppingForm(request.POST) if form.is_valid(): recipes = form.cleaned_data['recipe'] markdown_format = form.cleaned_data['markdown_format'] else: recipes = [] else: raw_list = request.GET.getlist('r') recipes = [] for r in raw_list: if re.match(r'^([1-9])+$', r): if Recipe.objects.filter(pk=int(r)).exists(): recipes.append(int(r)) markdown_format = False form = ShoppingForm(initial={'recipe': recipes, 'markdown_format': False}) ingredients = [] for r in recipes: for ri in RecipeIngredient.objects.filter(recipe=r).exclude(unit__name__contains='Special:').all(): index = None for x, ig in enumerate(ingredients): if ri.ingredient == ig.ingredient and ri.unit == ig.unit: index = x if index: ingredients[index].amount = ingredients[index].amount + ri.amount else: ingredients.append(ri) return render(request, 'shopping_list.html', {'ingredients': ingredients, 'recipes': recipes, 'form': form, 'markdown_format': markdown_format}) @group_required('guest') def user_settings(request): up = request.user.userpreference user_name_form = UserNameForm(instance=request.user) password_form = PasswordChangeForm(request.user) if request.method == "POST": if 'preference_form' in request.POST: form = UserPreferenceForm(request.POST, prefix='preference') if form.is_valid(): if not up: up = UserPreference(user=request.user) up.theme = form.cleaned_data['theme'] up.nav_color = form.cleaned_data['nav_color'] up.default_unit = form.cleaned_data['default_unit'] up.default_page = form.cleaned_data['default_page'] up.show_recent = form.cleaned_data['show_recent'] up.search_style = form.cleaned_data['search_style'] up.plan_share.set(form.cleaned_data['plan_share']) up.save() if 'user_name_form' in request.POST: user_name_form = UserNameForm(request.POST, prefix='name') if user_name_form.is_valid(): request.user.first_name = user_name_form.cleaned_data['first_name'] request.user.last_name = user_name_form.cleaned_data['last_name'] request.user.save() if 'password_form' in request.POST: password_form = PasswordChangeForm(request.user, request.POST) if password_form.is_valid(): user = password_form.save() update_session_auth_hash(request, user) if up: preference_form = UserPreferenceForm(instance=up) else: preference_form = UserPreferenceForm() return render(request, 'settings.html', {'preference_form': preference_form, 'user_name_form': user_name_form, 'password_form': password_form}) @group_required('guest') def history(request): view_log = ViewLogTable(ViewLog.objects.filter(created_by=request.user).order_by('-created_at').all()) cook_log = CookLogTable(CookLog.objects.filter(created_by=request.user).order_by('-created_at').all()) return render(request, 'history.html', {'view_log': view_log, 'cook_log': cook_log}) def setup(request): if User.objects.count() > 0 or 'django.contrib.auth.backends.RemoteUserBackend' in settings.AUTHENTICATION_BACKENDS: messages.add_message(request, messages.ERROR, _('The setup page can only be used to create the first user! If you have forgotten your superuser credentials please consult the django documentation on how to reset passwords.')) return HttpResponseRedirect(reverse('login')) if request.method == 'POST': form = SuperUserForm(request.POST) if form.is_valid(): if form.cleaned_data['password'] != form.cleaned_data['password_confirm']: form.add_error('password', _('Passwords dont match!')) else: user = User( username=form.cleaned_data['name'], is_superuser=True ) try: validate_password(form.cleaned_data['password'], user=user) user.set_password(form.cleaned_data['password']) user.save() messages.add_message(request, messages.SUCCESS, _('User has been created, please login!')) return HttpResponseRedirect(reverse('login')) except ValidationError as e: for m in e: form.add_error('password', m) else: form = SuperUserForm() return render(request, 'setup.html', {'form': form}) def markdown_info(request): return render(request, 'markdown_info.html', {})