Dreams module completed (?)

This commit is contained in:
Kumi 2021-01-01 17:49:39 +01:00
parent 4784185e99
commit fc7d56680a
18 changed files with 705 additions and 5 deletions

16
TODO.md
View file

@ -2,6 +2,7 @@
## mood module ## mood module
[_] Missing mood views
[ ] Statistics / graphs [ ] Statistics / graphs
## cbt module ## cbt module
@ -16,7 +17,14 @@
## dreams module ## dreams module
[ ] New dream page [x] New dream page
[ ] Edit dream page [x] Edit dream page
[ ] Delete dream page [x] Delete dream page
[ ] Statistics / template tags [ ] Statistics / template tags
[ ] Check for copy-paste errors in pages
## Frontend
[ ] Better icons for sidebar items
[ ] Sidebar auto-generation (?)
[ ] Fix sidebar highlighting for pages with same name

17
dreams/forms.py Normal file
View file

@ -0,0 +1,17 @@
from django.forms import ModelForm, ModelMultipleChoiceField
from multiupload.fields import MultiFileField
from .models import Dream, Theme
class DreamForm(ModelForm):
uploads = MultiFileField(required=False)
themes = ModelMultipleChoiceField(queryset=Theme.objects.all())
class Meta:
model = Dream
fields = ["timestamp", "mood", "title", "content", 'type', 'wet', 'lucid']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["mood"].required = False

View file

@ -14,6 +14,9 @@ class Theme(models.Model):
icon = models.CharField(default="fas fa-bed", max_length=64) icon = models.CharField(default="fas fa-bed", max_length=64)
color = ColorField(default="#000000") color = ColorField(default="#000000")
def __str__(self):
return self.name
class Dream(models.Model): class Dream(models.Model):
class DreamTypes(models.IntegerChoices): class DreamTypes(models.IntegerChoices):
NIGHT = 0, 'Night (main) sleep' NIGHT = 0, 'Night (main) sleep'
@ -21,6 +24,7 @@ class Dream(models.Model):
NAP = 2, 'Napping' NAP = 2, 'Napping'
user = models.ForeignKey(get_user_model(), models.CASCADE) user = models.ForeignKey(get_user_model(), models.CASCADE)
timestamp = models.DateTimeField(default=timezone.now)
title = models.CharField(max_length=64) title = models.CharField(max_length=64)
content = models.TextField() content = models.TextField()
type = models.IntegerField(choices=DreamTypes.choices) type = models.IntegerField(choices=DreamTypes.choices)
@ -28,6 +32,14 @@ class Dream(models.Model):
lucid = models.BooleanField(default=False) lucid = models.BooleanField(default=False)
wet = models.BooleanField(default=False) wet = models.BooleanField(default=False)
@property
def short_text(self):
return self.title or self.content[:64]
@property
def theme_set(self):
return [theme.theme for theme in self.dreamtheme_set.all()]
class DreamTheme(models.Model): class DreamTheme(models.Model):
dream = models.ForeignKey(Dream, models.CASCADE) dream = models.ForeignKey(Dream, models.CASCADE)
theme = models.ForeignKey(Theme, models.CASCADE) theme = models.ForeignKey(Theme, models.CASCADE)

View file

@ -0,0 +1,16 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Delete {{ object }}</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<p>Are you sure you wish to delete this dream? This cannot be undone.</p>
<form action="" method="POST">{% csrf_token %}<button class="form-control btn-danger" type="submit">Delete Dream</button></form>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,60 @@
{% extends "frontend/base.html" %}
{% block "content" %}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger" role="alert">
{{ field.name }}: {{ error }}
</div>
{% endfor %}
{% endfor %}
{% endif %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Edit {{ object.title }}</h6>
</div>
<div class="card-body">
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="table-responsive">
<table>
<tr><th><label for="id_timestamp">Timestamp:</label></th><td><input type="text" name="timestamp" value="{% if object.timestamp %}{{ object.timestamp | date:"Y-m-d H:i" }}{% else %}{% now "Y-m-d H:i" %}{% endif %}" required id="id_timestamp"><input type="hidden" name="initial-timestamp" value="2020-12-26 19:24:14" id="initial-id_timestamp"></td></tr>
<tr><th><label for="id_type">Type:</label></th><td><select name="type" required="" id="id_type">
{% for value, text in form.type.field.choices %}
<option value="{{ value }}" {% if object.type == value %}selected{% endif %}>{{ text }}</option>
{% endfor %}
</select></td></tr>
<tr><th><label for="id_title">Title:</label></th><td><input value="{{ object.title }}" type="text" name="title" maxlength="64" id="id_title"></td></tr>
<tr><th><label for="id_content">Text:</label></th><td><textarea name="content" cols="40" rows="10" id="id_content">{{ object.content }}</textarea></td></tr>
<tr><th><label for="id_mood">Mood:</label></th><td><select name="mood" class="dtb" required id="id_mood">
<option value="" {% if not object.mood %}selected{% endif %}>---------</option>
{% for mood in request.user.mood_set.all|dictsort:"value" %}
<option data-icon="{{ mood.icon }}" value="{{ mood.id }}" {% if object.mood == mood %}selected{% endif %}>{{ mood }}</option>
{% endfor %}
</select></td></tr>
<tr><th><label for="id_lucid">Lucid:</label></th><td><input type="checkbox" {% if object.lucid %}checked{% endif %} name="lucid"> <i class="fas fa-exclamation"></i> Lucid Dream?<br></td></tr>
<tr><th><label for="id_lucid">Wet:</label></th><td><input type="checkbox" {% if object.wet %}checked{% endif %} name="wet"> <i class="fas fa-tint"></i> Wet Dream?<br></td></tr>
<tr><th><label for="activities">Themes:</label></th><td>
{% for theme in request.user.theme_set.all %}
<input type="checkbox" {% if theme in object.theme_set %}checked{% endif %} value="{{ theme.id }}" name="themes"> <i class="{{ theme.icon }}" style="color:{{ theme.color }};"></i> {{ theme }}<br>
{% endfor %}
</td></tr>
<tr><th><label for="id_uploads">Uploads:</label></th><td><input type="file" name="uploads" id="id_uploads" multiple="multiple"></td></tr>
</table>
</div>
<button style="margin-top: 20px;" class="form-control btn-primary" type="submit">Save</button>
</form>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,34 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Your Dreams</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table data-order="[[ 0, &quot;desc&quot; ]]" class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Timestamp</th>
<th>Mood</th>
<th>Themes</th>
<th>Title</th>
</tr>
</thead>
<tbody>
{% for dream in object_list %}
<tr onclick="window.location.href='{% url "dreams:dream_view" dream.id %}'">
<td data-order="{{ dream.timestamp | date:"U" }}">{{ dream.timestamp }}</td>
<td><i data-order="{{ dream.mood.value }}" style="color:{{ dream.mood.color }};" class="{{ dream.mood.icon }}"></i> {{ dream.mood }}</td>
<td>{% for theme in dream.dreamtheme_set.all %}<i title="{{ theme.theme }}{% if theme.comment %} - {{ theme.comment }}{% endif %}" style="color:{{ theme.theme.color }};" class="{{ theme.theme.icon }}"></i> {% endfor %}</td>
<td>{{ dream.short_text }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,70 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="row">
<!-- Entry details -->
<div class="col-xl-8 col-lg-7">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Dream Entry</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<p><i>{{ object.timestamp }}</i></p>
<h3>{{ object.title }}</h3>
<blockquote>{{ object.content|linebreaks }}</blockquote>
</div>
</div>
</div>
<!-- Mood -->
<div class="col-xl-4 col-lg-5">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Mood</h6>
</div>
<!-- Card Body -->
<div class="card-body">
<i title="{{ object.mood }}" style="color: {{ object.mood.color }}; font-size: 200px;" title="" class="{{ object.mood.icon }}"></i>
</div>
</div>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Themes</h6>
</div>
<div class="py-3">
<div class="container">
<div class="row" id="cards">
{% for theme in object.dreamtheme_set.all %}
<div class="card">
<i title="{{ theme.theme }}" style="display: inline; color: {{ theme.theme.color }}; font-size: 50px;" title="" class="{{ theme.theme.icon }}"></i>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Attachments</h6>
</div>
<div class="py-3">
<div class="container">
<ul>
{% for attachment in object.dreammedia_set.all %}
<li><a href="{{ attachment.media.url }}">{{ attachment.media.name }}</a></li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,28 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Your Moods</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Name <i>(Value)</i></th>
</tr>
</thead>
<tbody>
{% for mood in object_list %}
<tr onclick="window.location.href='{% url "mood:mood_edit" mood.id %}'">
<td><i data-order="{{ mood.value }}" style="color:{{ mood.color }};" class="{{ mood.icon }}"></i> {{ mood }} <i>({{ mood.value }})</i></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,16 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Delete {{ object.time }} Notification?</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<p>Are you sure you wish to delete this notification? This cannot be undone.</p>
<form action="" method="POST">{% csrf_token %}<button class="form-control btn-danger" type="submit">Delete Notification</button></form>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,30 @@
{% extends "frontend/base.html" %}
{% block "content" %}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger" role="alert">
{{ field.name }}: {{ error }}
</div>
{% endfor %}
{% endfor %}
{% endif %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Edit {{ object.time }}</h6>
</div>
<div class="card-body">
<form action="" method="POST">
{% csrf_token %}
<div class="table-responsive">
<table>
<tr><th><label for="id_time">Time:</label></th><td><input type="time" name="time" value="{% if object.time %}{{ object.time|date:"H:i" }}{% else %}12:00{% endif %}" maxlength="64" required id="id_time"></td></tr>
</table>
</div>
<button style="margin-top: 20px;" class="form-control btn-primary" type="submit">Save</button>
</form>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,28 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Your Daily Notifications</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Time</th>
</tr>
</thead>
<tbody>
{% for notification in object_list %}
<tr onclick="window.location.href='{% url "mood:notification_edit" notification.id %}'">
<td>{{ notification.time }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,16 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Delete {{ object }}</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<p>Are you sure you wish to delete {{ object }}? This cannot be undone. Mood entries that are associated with this activity will not be deleted.</p>
<form action="" method="POST">{% csrf_token %}<button class="form-control btn-danger" type="submit">Delete Activity</button></form>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,30 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Edit {{ object.name }}</h6>
</div>
<div class="card-body">
<form action="" method="POST">
{% csrf_token %}
<div class="table-responsive">
<table>
<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" value="{{ object.name }}" maxlength="64" required id="id_name"></td></tr>
<tr><th><label for="id_icon">Icon:</label></th><td><input style="visibility: hidden;" class="icp icp-auto" type="text" name="icon" value="{{ object.icon }}" maxlength="64" required id="id_icon"></td></tr>
<tr><th><label for="id_color">Color:</label></th><td><input type="text"
id="id_color"
class="form-control colorfield_field jscolor"
name="color"
value="{{ object.color }}"
placeholder="{{ object.color }}"
data-jscolor="{hash:true,width:225,height:150,required:true}"
required /></td></tr>
</table>
</div>
<button style="margin-top: 20px;" class="form-control btn-primary" type="submit">Save</button>
</form>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,28 @@
{% extends "frontend/base.html" %}
{% block "content" %}
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Your Themes</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
{% for theme in object_list %}
<tr onclick="window.location.href='{% url "dreams:theme_edit" theme.id %}'">
<td><i data-order="{{ theme }}" style="color:{{ theme.color }};" class="{{ theme.icon }}"></i> {{ theme }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

21
dreams/urls.py Normal file
View file

@ -0,0 +1,21 @@
from .views import DreamListView, DreamViewView, DreamDeleteView, DreamEditView, DreamCreateView, ThemeListView, ThemeEditView, ThemeCreateView, ThemeDeleteView, NotificationCreateView, NotificationDeleteView, NotificationEditView, NotificationListView
from django.urls import path, include
app_name = "dreams"
urlpatterns = [
path('', DreamListView.as_view(), name="dream_list"),
path('dream/<int:id>/view/', DreamViewView.as_view(), name="dream_view"),
path('dream/<int:id>/edit/', DreamEditView.as_view(), name="dream_edit"),
path('dream/<int:id>/delete/', DreamDeleteView.as_view(), name="dream_delete"),
path('dream/new/', DreamCreateView.as_view(), name="dream_create"),
path('theme/', ThemeListView.as_view(), name="theme_list"),
path('theme/<int:id>/edit/', ThemeEditView.as_view(), name="theme_edit"),
path('theme/new/', ThemeCreateView.as_view(), name="theme_create"),
path('theme/<int:id>/delete/', ThemeDeleteView.as_view(), name="theme_delete"),
path('notification/', NotificationListView.as_view(), name="notification_list"),
path('notification/<int:id>/edit/', NotificationEditView.as_view(), name="notification_edit"),
path('notification/<int:id>/delete/', NotificationDeleteView.as_view(), name="notification_delete"),
path('notification/new/', NotificationCreateView.as_view(), name="notification_create"),
]

View file

@ -1,3 +1,259 @@
from django.shortcuts import render from django.shortcuts import render
# Create your views here. from django.views.generic import TemplateView, ListView, UpdateView, DetailView, CreateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.http import HttpResponseRedirect
from .models import Dream, DreamTheme, DreamMedia, Theme
from .forms import DreamForm
from msgio.models import NotificationDailySchedule, Notification
class DreamListView(LoginRequiredMixin, ListView):
template_name = "dreams/dream_list.html"
model = Dream
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Dream List"
context["subtitle"] = "A list of the dreams you have entered so far."
context["buttons"] = [(reverse_lazy("dreams:dream_create"), "New Dream", "plus")]
return context
def get_queryset(self):
return Dream.objects.filter(user=self.request.user).order_by('timestamp')
class DreamViewView(LoginRequiredMixin, DetailView):
template_name = "dreams/dream_view.html"
model = Dream
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "View Dream"
context["subtitle"] = "View the details of your dream."
context["buttons"] = [(reverse_lazy("dreams:dream_edit", kwargs={"id": self.kwargs["id"]}), "Edit Dream", "pen")]
return context
def get_object(self):
return get_object_or_404(Dream, user=self.request.user, id=self.kwargs["id"])
class DreamCreateView(LoginRequiredMixin, CreateView):
template_name = "dreams/dream_edit.html"
form_class = DreamForm
model = Dream
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Create Dream"
context["subtitle"] = "What did you dream?"
context["scripts"] = ["frontend/js/dropdown-to-buttons.js"]
return context
def form_valid(self, form):
form.instance.user = self.request.user
ret = super().form_valid(form)
for theme in form.cleaned_data["themes"]:
if theme.user == self.request.user:
DreamTheme.objects.create(theme=theme, dream=form.instance)
for attachment in form.cleaned_data["uploads"]:
DreamMedia.objects.create(dream=form.instance, media=attachment)
return ret
def get_success_url(self):
return reverse_lazy("dreams:dream_view", kwargs={"id": self.object.id})
class DreamEditView(LoginRequiredMixin, UpdateView):
template_name = "dreams/dream_edit.html"
form_class = DreamForm
model = Dream
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Update Dream"
context["subtitle"] = "Change details of a dream you entered before."
context["scripts"] = ["frontend/js/dropdown-to-buttons.js"]
context["buttons"] = [(reverse_lazy("dreams:dream_delete", kwargs={"id": self.kwargs["id"]}), "Delete Dream", "trash-alt")]
return context
def get_object(self):
return get_object_or_404(Dream, user=self.request.user, id=self.kwargs["id"])
def form_valid(self, form):
for theme in form.cleaned_data["themes"]:
if theme.user == self.request.user:
if not theme in form.instance.theme_set:
DreamTheme.objects.create(theme=theme, dream=form.instance)
for dreamtheme in form.instance.dreamtheme_set.all():
if not dreamtheme.theme in form.cleaned_data["themes"]:
dreamtheme.delete()
for upload in form.cleaned_data["uploads"]:
DreamMedia.objects.create(dream=form.instance, media=upload)
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("dreams:dream_view", kwargs={"id": self.object.id})
class DreamDeleteView(LoginRequiredMixin, DeleteView):
template_name = "dreams/dream_delete.html"
model = Dream
def get_object(self):
return get_object_or_404(Dream, user=self.request.user, id=self.kwargs["id"])
def get_success_url(self):
return reverse_lazy("dreams:dream_list")
class ThemeListView(LoginRequiredMixin, ListView):
template_name = "dreams/theme_list.html"
model = Theme
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Themes"
context["subtitle"] = "The themes you have defined for your dreams."
context["buttons"] = [(reverse_lazy("dreams:theme_create"), "Create Theme", "pen")]
return context
def get_queryset(self):
return Theme.objects.filter(user=self.request.user)
class ThemeEditView(LoginRequiredMixin, UpdateView):
template_name = "dreams/theme_edit.html"
model = Theme
fields = ["name", "icon", "color"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Edit Theme"
context["subtitle"] = "Make changes to the theme."
context["scripts"] = ["colorfield/jscolor/jscolor.js", "colorfield/colorfield.js", "frontend/js/fontawesome-iconpicker.min.js", "frontend/js/iconpicker-loader.js"]
context["styles"] = ["frontend/css/fontawesome-iconpicker.min.css"]
context["buttons"] = [(reverse_lazy("dreams:theme_delete", kwargs={"id": self.kwargs["id"]}), "Delete Theme", "trash-alt")]
return context
def get_object(self):
return get_object_or_404(Theme, user=self.request.user, id=self.kwargs["id"])
def get_success_url(self):
return reverse_lazy("dreams:theme_list")
class ThemeCreateView(LoginRequiredMixin, CreateView):
template_name = "dreams/theme_edit.html"
model = Theme
fields = ["name", "icon", "color"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Create Theme"
context["subtitle"] = "Add a new theme for your dreams."
context["scripts"] = ["colorfield/jscolor/jscolor.js", "colorfield/colorfield.js", "frontend/js/fontawesome-iconpicker.min.js", "frontend/js/iconpicker-loader.js"]
context["styles"] = ["frontend/css/fontawesome-iconpicker.min.css"]
return context
def form_valid(self, form):
obj = form.save(commit=False)
obj.user = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("dreams:theme_list")
class ThemeDeleteView(LoginRequiredMixin, DeleteView):
template_name = "dreams/theme_delete.html"
model = Theme
def get_object(self):
return get_object_or_404(Theme, user=self.request.user, id=self.kwargs["id"])
def get_success_url(self):
return reverse_lazy("dreams:theme_list")
class NotificationListView(LoginRequiredMixin, ListView):
template_name = "dreams/notification_list.html"
model = NotificationDailySchedule
fields = ["time"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Notifications"
context["subtitle"] = "The daily reminders you have set up."
context["buttons"] = [(reverse_lazy("dreams:notification_create"), "New Notification", "plus")]
return context
def get_queryset(self):
return NotificationDailySchedule.objects.filter(notification__recipient=self.request.user, notification__app="dreams")
class NotificationCreateView(LoginRequiredMixin, CreateView):
template_name = "dreams/notification_edit.html"
model = NotificationDailySchedule
fields = ["time"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Create Notification"
context["subtitle"] = "Add a new daily notification."
return context
def form_valid(self, form):
notification = Notification.objects.create(content="What did you dream tonight? Go to %KUMIFYURL% to document your dreams!", recipient=self.request.user, app="dreams")
obj = form.save(commit=False)
obj.notification = notification
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("dreams:notification_list")
class NotificationEditView(LoginRequiredMixin, UpdateView):
template_name = "dreams/notification_edit.html"
model = NotificationDailySchedule
fields = ["time"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Edit Notification"
context["subtitle"] = "Change the time of a daily notification."
context["buttons"] = [(reverse_lazy("dreams:notification_delete", args=[self.kwargs["id"]]), "Delete Notification")]
return context
def get_success_url(self):
return reverse_lazy("dreams:notification_list")
def get_object(self):
return get_object_or_404(NotificationDailySchedule, notification__recipient=self.request.user, id=self.kwargs["id"])
class NotificationDeleteView(LoginRequiredMixin, DeleteView):
template_name = "dreams/notification_delete.html"
model = NotificationDailySchedule
def get_object(self):
return get_object_or_404(NotificationDailySchedule, notification__recipient=self.request.user, id=self.kwargs["id"])
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
success_url = self.get_success_url()
self.object.notification.delete()
return HttpResponseRedirect(success_url)
def get_success_url(self):
return reverse_lazy("dreams:notification_list")

View file

@ -55,6 +55,35 @@
<span>Notifications</span></a> <span>Notifications</span></a>
</li> </li>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading">
Dreams
</div>
<!-- Nav Item - Dream List -->
<li class="nav-item {% if title == "Dream List" %}active{% endif %}">
<a class="nav-link" href="{% url "dreams:dream_list" %}">
<i class="fas fa-fw fa-smile"></i>
<span>Dream List</span></a>
</li>
<!-- Nav Item - Theme List -->
<li class="nav-item {% if title == "Themes" %}active{% endif %}">
<a class="nav-link" href="{% url "dreams:theme_list" %}">
<i class="fas fa-fw fa-smile"></i>
<span>Themes</span></a>
</li>
<!-- Nav Item - Notification List -->
<li class="nav-item {% if title == "Notifications" %}active{% endif %}">
<a class="nav-link" href="{% url "dreams:notification_list" %}">
<i class="fas fa-fw fa-smile"></i>
<span>Notifications</span></a>
</li>
<!-- Divider --> <!-- Divider -->
<hr class="sidebar-divider d-none d-md-block"> <hr class="sidebar-divider d-none d-md-block">

View file

@ -25,4 +25,5 @@ urlpatterns = [
path('mood/', include("mood.urls", "mood")), path('mood/', include("mood.urls", "mood")),
path('cron/', include("cronhandler.urls", "cron")), path('cron/', include("cronhandler.urls", "cron")),
path('webhooks/telegram/', TelegramWebhookView.as_view()), path('webhooks/telegram/', TelegramWebhookView.as_view()),
path('dreams/', include("dreams.urls", "dreams")),
] ]