tt/src/tt/db.py

134 lines
3.5 KiB
Python

import json
from datetime import date, timedelta, datetime
from enum import Enum
from peewee import (
BooleanField,
CharField,
DateTimeField,
ForeignKeyField,
Model,
SqliteDatabase,
TextField,
)
db = SqliteDatabase(
"tasks.db",
pragmas={
"journal_mode": "wal",
"synchronous": "normal",
"foreign_keys": 1,
},
)
class TaskStatus(Enum):
# order is used for progression in toggle
ZERO = "zero"
WIP = "wip"
BLOCKED = "blocked"
DONE = "done"
class GeneratorType(Enum):
DAYS_BETWEEN = "days-btwn"
MONTHLY = "monthly"
class BaseModel(Model):
class Meta:
database = db
class Category(BaseModel):
name = CharField(unique=True)
def __str__(self):
return self.name
class Task(BaseModel):
text = TextField()
status = CharField(
choices=[(status.value, status.name) for status in TaskStatus],
default=TaskStatus.ZERO.value,
)
due = DateTimeField(null=True)
category = ForeignKeyField(Category, backref="tasks", null=True)
type = CharField()
created_at = DateTimeField(default=datetime.now)
updated_at = DateTimeField(default=datetime.now)
deleted = BooleanField(default=False)
def save(self, *args, **kwargs):
self.updated_at = datetime.now()
return super(Task, self).save(*args, **kwargs)
class SavedSearch(BaseModel):
name = CharField(unique=True)
filters = CharField()
sort_string = CharField()
def __str__(self):
return self.name
class TaskGenerator(BaseModel):
template = CharField()
type = CharField()
config = TextField() # JSON
deleted = BooleanField(default=False)
last_generated_at = DateTimeField(null=True)
created_at = DateTimeField(default=datetime.now)
def next_at(self) -> datetime.date:
if self.deleted:
return None
today = date.today()
val = int(json.loads(self.config)["val"])
if self.type == GeneratorType.DAYS_BETWEEN.value:
if not self.last_generated_at:
return today
return self.last_generated_at + timedelta(days=val)
elif self.type == GeneratorType.MONTHLY.value:
year, month, day = today.year, today.month, today.day
day_of_month = val
# if we need to go forward a month
if day_of_month < day:
month += 1
if month == 13:
month = 1
year += 1
# recurring tasks on 29-31 in Feb will just happen on 28th
if day_of_month >= 29 and month == 2:
maybe_next = date(year, month, 28)
else:
maybe_next = date(year, month, day_of_month)
if not self.last_generated_at or self.last_generated_at < maybe_next:
return maybe_next
# TODO: this doesn't handle if a month was missed somehow, just advances one
# same logic as above, if we're stepping another month forward
month += 1
if month == 13:
month = 1
year += 1
if day_of_month >= 29 and month == 2:
maybe_next = date(year, month, 28)
else:
maybe_next = date(year, month, day_of_month)
return maybe_next
def initialize_db():
db.connect()
db.create_tables([Category, Task, SavedSearch, TaskGenerator])
if not Category.select().exists():
Category.create(name="default")
db.close()