Use django-recurrence for recurrence fields

This commit is contained in:
Adam Goldsmith 2021-05-19 18:22:33 -04:00
parent 6918a3d497
commit 66c1ef629b
6 changed files with 74 additions and 20 deletions

View File

@ -4,7 +4,6 @@ verify_ssl = true
name = "pypi" name = "pypi"
[packages] [packages]
python-dateutil = "*"
django = "*" django = "*"
django-widget-tweaks = "*" django-widget-tweaks = "*"
django-auth-ldap = "*" django-auth-ldap = "*"
@ -12,6 +11,7 @@ django-markdownx = "*"
django-markdownify = "*" django-markdownify = "*"
uvicorn = "*" uvicorn = "*"
mysqlclient = "*" mysqlclient = "*"
django-recurrence = "*"
[dev-packages] [dev-packages]

12
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "cf9669556a14beab13e75133255258d1c446c321e486d27def845667bfaec370" "sha256": "909b6de0a11b2a6648f920e4bf5a8c191e482bc956a0c22965a0c65cb06a642b"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -72,6 +72,14 @@
"index": "pypi", "index": "pypi",
"version": "==3.0.1" "version": "==3.0.1"
}, },
"django-recurrence": {
"hashes": [
"sha256:715f681f6af029ff3a8d73c7b1460abd8cbc5d5a5001efcb127032e84d9cb963",
"sha256:9053b44b78b7fbfe3530673edfdd6d2f562105f8a192bc6a4b906a3df4f95f59"
],
"index": "pypi",
"version": "==1.10.3"
},
"django-widget-tweaks": { "django-widget-tweaks": {
"hashes": [ "hashes": [
"sha256:9f91ca4217199b7671971d3c1f323a2bec71a0c27dec6260b3c006fa541bc489", "sha256:9f91ca4217199b7671971d3c1f323a2bec71a0c27dec6260b3c006fa541bc489",
@ -203,7 +211,7 @@
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
], ],
"index": "pypi", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.1" "version": "==2.8.1"
}, },
"python-ldap": { "python-ldap": {

View File

@ -26,6 +26,7 @@ INSTALLED_APPS = [
'widget_tweaks', 'widget_tweaks',
'markdownx', 'markdownx',
'markdownify', 'markdownify',
'recurrence',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.3 on 2021-05-19 21:46
from django.db import migrations
import recurrence
import recurrence.fields
def transfer_recurrence(apps, schema_editor):
Task = apps.get_model('tasks', 'task')
for task in Task.objects.all():
task.recurrence = recurrence.deserialize('RRULE:' + task.recurrence_interval)
task.save(update_fields=['recurrence'])
class Migration(migrations.Migration):
dependencies = [
('tasks', '0002_tool_slug'),
]
operations = [
migrations.AddField(
model_name='task',
name='recurrence',
field=recurrence.fields.RecurrenceField(default=''),
preserve_default=False,
),
migrations.RunPython(transfer_recurrence),
migrations.RemoveField(
model_name='task',
name='recurrence_interval',
),
]

View File

@ -1,11 +1,11 @@
from datetime import datetime import datetime
from dateutil.rrule import rrulestr
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from markdownx.models import MarkdownxField from markdownx.models import MarkdownxField
from recurrence.fields import RecurrenceField
class Tool(models.Model): class Tool(models.Model):
name = models.CharField(max_length=200) name = models.CharField(max_length=200)
@ -24,7 +24,7 @@ class Task(models.Model):
slug = models.SlugField() slug = models.SlugField()
tool = models.ForeignKey(Tool, on_delete=models.CASCADE) tool = models.ForeignKey(Tool, on_delete=models.CASCADE)
description = MarkdownxField(blank=True) description = MarkdownxField(blank=True)
recurrence_interval = models.CharField(max_length=200) recurrence = RecurrenceField(include_dtstart=False)
recurrence_base = models.DateField(null=True, blank=True) recurrence_base = models.DateField(null=True, blank=True)
class Meta: class Meta:
@ -42,18 +42,20 @@ class Task(models.Model):
@property @property
def next_recurrence(self): def next_recurrence(self):
def _date_to_datetime(date):
return datetime.datetime.combine(date, datetime.time.min)
if self.recurrence_base is None: # relative date if self.recurrence_base is None: # relative date
try: try:
rrule = rrulestr(self.recurrence_interval, dtstart=self.last_event.date) return self.recurrence.after(
return rrule[1] _date_to_datetime(self.last_event.date),
dtstart=_date_to_datetime(self.last_event.date))
except Event.DoesNotExist: except Event.DoesNotExist:
return None return None
else: # absolute date else: # absolute date
rrule = rrulestr(self.recurrence_interval, dtstart=self.recurrence_base)
try: try:
return rrule.after(self.last_event.date) return self.recurrence.after(_date_to_datetime(self.last_event.date))
except Event.DoesNotExist: except Event.DoesNotExist:
return rrule[1] return self.recurrence.occurrences()[0]
@property @property
def is_overdue(self): def is_overdue(self):
@ -61,7 +63,7 @@ class Task(models.Model):
if next_rec is None: if next_rec is None:
return False return False
else: else:
return next_rec < datetime.now() return next_rec < datetime.datetime.now()
class SubscriptionSettings(models.Model): class SubscriptionSettings(models.Model):
@ -104,7 +106,7 @@ class GroupTaskSubscription(SubscriptionSettings):
next_recurrence = self.task.next_recurrence next_recurrence = self.task.next_recurrence
if next_recurrence is None: if next_recurrence is None:
return False return False
time_until_overdue = next_recurrence - datetime.now() time_until_overdue = next_recurrence - datetime.datetime.now()
return self.task.is_overdue or (time_until_overdue.days <= self.days_before) return self.task.is_overdue or (time_until_overdue.days <= self.days_before)
def __str__(self): def __str__(self):

View File

@ -14,14 +14,26 @@
</ol> </ol>
</nav> </nav>
<p> Next scheduled time: {{ task.next_recurrence|date }} </p> <section>
<h2> Recurrence </h2>
<ul>
{% for rule in task.recurrence.rrules %}
<li> {{ rule.to_text }} </li>
{% endfor %}
</ul>
<p> Next scheduled time: {{ task.next_recurrence|date|default:"never" }} </p>
{% if task.is_overdue %} {% if task.is_overdue %}
<div class="alert alert-danger"> <div class="alert alert-danger">
Task is overdue! Task is overdue!
</div> </div>
{% endif %} {% endif %}
</section>
<section>
<h2> Description </h2>
{{ task.description|markdownify }} {{ task.description|markdownify }}
</section>
{% if form.errors %} {% if form.errors %}
<div class="alert alert-warning"> <div class="alert alert-warning">