views.py

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
from typing import Any
from django.db.models.base import Model as Model
from django.db.models.query import QuerySet
from django.forms.forms import BaseForm
from django.http import HttpRequest, HttpResponse
from django.views.generic import (
    ListView,
    FormView,
    DetailView,
    UpdateView,
    CreateView,
    DeleteView,
)
from django.http import Http404
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth import get_user_model
from django.urls import reverse, reverse_lazy
from .models import List, Todo
from .forms import TodoForm, ListForm, EditForm, EditTodoForm


class BaseFormView(FormView):
    form_class = None

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
        context = super().get_context_data(**kwargs)
        if self.kwargs.get("todo_id", None):
            context["todo_id"] = self.kwargs.get("todo_id")
        return context

    def get_success_url(self) -> str:
        """ListForm redirects user to just created todo list (pk saved on form being valid)"""
        return reverse(
            "todos:todos",
            kwargs={
                "username": self.request.user.username,
                "pk": self.kwargs["pk"],
            },
        )


class UserListFormView(LoginRequiredMixin, ListView, BaseFormView):
    model = List
    template_name = "todos/lists.html"
    form_class = ListForm

    def get_queryset(self) -> QuerySet[Any]:
        return List.objects.filter(owner=self.request.user)

    def get_form(self, form_class=None):
        """Return an instance of the form to be used in this view."""
        if form_class is None:
            form_class = self.get_form_class()
        return form_class(queryset=self.get_queryset(), **self.get_form_kwargs())

    def form_valid(self, form: Any) -> HttpResponse:
        list_ = form.save(self.request.user)
        self.kwargs = {"list": list_, "pk": list_.pk}  # save list and pk here
        return super().form_valid(form)

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
        self.object_list = self.get_queryset()
        return super().get_context_data(**kwargs)

    def get_login_url(self) -> str:
        """filter out attempts to log back in for guest accounts"""
        from mywebsite.todos.utils import filter_guest_accounts
        from mywebsite.users.models import User

        username = self.kwargs["username"]
        is_user_in_database = User.objects.filter(username=username)
        is_user_guest_account = filter_guest_accounts(self.kwargs["username"])

        # if self.model.objects.filter(username=self.kwargs["username"]).first():
        if is_user_in_database and is_user_guest_account:
            return "/guest_accounts/login/"
        else:
            from django.core.exceptions import PermissionDenied

            raise PermissionDenied


class UserView(UserListFormView):
    def __init__(self, **kwargs: Any) -> None:
        super().__init__(**kwargs)


user_lists_view = UserView.as_view()


class TodoFormView(LoginRequiredMixin, BaseFormView):
    form_class = TodoForm

    def get_form(self, form_class: type | None = ...) -> BaseForm:
        """override get_form to pass TodoForm with init values to ProcessFormView"""
        list_ = List.objects.get(id=self.kwargs.get("pk"))
        return self.form_class(for_list=list_, **self.get_form_kwargs())

    def form_valid(self, form: Any) -> HttpResponse:
        """if form valid then runs this"""
        user = self.request.user
        pk = self.kwargs.get("pk")
        form.save(owner=user, pk=pk)
        return super().form_valid(form)


class EditFormView(LoginRequiredMixin, BaseFormView):
    form_class = EditForm

    def form_valid(self, form: Any) -> HttpResponse:
        """rename title"""
        list_ = List.objects.get(id=self.kwargs["pk"])
        todo = list_.todo_set.first()
        todo.text = form.cleaned_data["text"]
        todo.save()
        return super().form_valid(form)


class CustomTodoView(LoginRequiredMixin, DetailView):
    model = List

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
        self.object = List.objects.get(id=self.kwargs.get("pk"))
        return super().get_context_data(**kwargs)


class TodoView(CustomTodoView, UserPassesTestMixin, TodoFormView):
    template_name = "todos/details.html"

    def test_func(self) -> bool | None:
        return self.get_object().owner == self.request.user


list_todos_view = TodoView.as_view()


class EditView(EditFormView, UserPassesTestMixin, CustomTodoView):
    template_name = "todos/edit.html"

    def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self) -> bool | None:
        return self.get_object().owner == self.request.user


edit_view = EditView.as_view()


class EditTodoFormView(LoginRequiredMixin, UserPassesTestMixin, BaseFormView):
    form_class = EditTodoForm

    def form_valid(self, form: Any) -> HttpResponse:
        # todo = Todo.objects.get(todo_id=)
        id = self.kwargs.get("todo_id")
        if id:
            todo = Todo.objects.get(todo_id=id)
            if todo:
                todo.text = form.cleaned_data["text"]
                todo.save()
        return super().form_valid(form)

    def test_func(self) -> bool | None:
        return self.get_object().owner == self.request.user


class EditTodoView(EditTodoFormView, CustomTodoView):
    template_name = "todos/edit_todo.html"


edit_todo_view = EditTodoView.as_view()


class DeleteListView(UserPassesTestMixin, DeleteView):
    template_name = "todos/delete.html"
    model = List

    def get_success_url(self) -> str:
        return reverse(
            "todos:lists", kwargs={"username": f"{self.request.user.username}"}
        )

    def test_func(self) -> bool | None:
        return self.get_object().owner == self.request.user


delete_view = DeleteListView.as_view()


class DeleteTodoView(UserPassesTestMixin, DeleteView):
    model = Todo
    template_name = "todos/delete.html"

    def get_object(self, queryset=None) -> Model:
        """need to override this to filter by todo_id rather than default pk id"""
        if queryset is None:
            queryset = self.get_queryset()

        todo_id = self.kwargs.get("todo_id")
        queryset = queryset.filter(todo_id=todo_id)

        # shamelessly reusing django code...
        try:
            # Get the single item from the filtered queryset
            obj = queryset.get()
        except queryset.model.DoesNotExist:
            raise Http404(
                f"No {queryset.model._meta.verbose_name} model found matching the query"
            )
        return obj

    def get_success_url(self) -> str:
        return reverse(
            "todos:todos",
            kwargs={
                "username": f"{self.request.user.username}",
                "pk": f"{self.kwargs.get('pk')}",
            },
        )

    def test_func(self) -> bool | None:
        return self.get_object().list.owner == self.request.user


delete_todo_view = DeleteTodoView.as_view()