feat: task
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
from tortoise import migrations
|
||||||
|
from tortoise.migrations import operations as ops
|
||||||
|
from uuid import uuid4
|
||||||
|
from tortoise import fields
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [('models', '0001_initial')]
|
||||||
|
|
||||||
|
initial = False
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
ops.CreateModel(
|
||||||
|
name='Task',
|
||||||
|
fields=[
|
||||||
|
('id', fields.UUIDField(primary_key=True, default=uuid4, unique=True, db_index=True)),
|
||||||
|
('created_at', fields.DatetimeField(auto_now=False, auto_now_add=True)),
|
||||||
|
('updated_at', fields.DatetimeField(auto_now=True, auto_now_add=False)),
|
||||||
|
('list', fields.CharField(db_index=True, max_length=32)),
|
||||||
|
('name', fields.TextField(unique=False)),
|
||||||
|
('reset_cron', fields.CharField(null=True, max_length=32)),
|
||||||
|
('check_date', fields.DatetimeField(null=True, auto_now=False, auto_now_add=False)),
|
||||||
|
('previous_check_date', fields.DatetimeField(null=True, auto_now=False, auto_now_add=False)),
|
||||||
|
],
|
||||||
|
options={'table': 'task', 'app': 'models', 'pk_attr': 'id'},
|
||||||
|
bases=['AbstractModel'],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1 +1,2 @@
|
|||||||
from .comment import Comment # noqa: F401
|
from .comment import Comment # noqa: F401
|
||||||
|
from .task import Task # noqa: F401
|
||||||
|
|||||||
+2
-2
@@ -4,8 +4,8 @@ import tortoise.models
|
|||||||
|
|
||||||
class AbstractModel(tortoise.models.Model):
|
class AbstractModel(tortoise.models.Model):
|
||||||
id = tortoise.fields.UUIDField(primary_key=True)
|
id = tortoise.fields.UUIDField(primary_key=True)
|
||||||
created_at = tortoise.fields.DatetimeField(auto_now_add=True)
|
created_at = tortoise.fields.DatetimeField(auto_now_add=True, null=False)
|
||||||
updated_at = tortoise.fields.DatetimeField(auto_now=True)
|
updated_at = tortoise.fields.DatetimeField(auto_now=True, null=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ from app.models.base import AbstractModel
|
|||||||
|
|
||||||
|
|
||||||
class Comment(AbstractModel):
|
class Comment(AbstractModel):
|
||||||
content = tortoise.fields.TextField()
|
content = tortoise.fields.TextField(null=False)
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import typing
|
||||||
|
|
||||||
|
import tortoise
|
||||||
|
|
||||||
|
from app.models.base import AbstractModel
|
||||||
|
|
||||||
|
# https://stackoverflow.com/a/57639657
|
||||||
|
CRONTAB_REGEX = r"/(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})/"
|
||||||
|
|
||||||
|
|
||||||
|
class Task(AbstractModel):
|
||||||
|
list = tortoise.fields.CharField(max_length=32, db_index=True, null=False)
|
||||||
|
name = tortoise.fields.TextField(null=False)
|
||||||
|
reset_cron = tortoise.fields.CharField(max_length=64, null=True)
|
||||||
|
check_date = tortoise.fields.DatetimeField(null=True)
|
||||||
|
previous_check_date = tortoise.fields.DatetimeField(null=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_create(cls, data: dict[str, typing.Any]) -> dict | None:
|
||||||
|
out_data = {}
|
||||||
|
try:
|
||||||
|
for field in [
|
||||||
|
"list",
|
||||||
|
"name",
|
||||||
|
"reset_cron",
|
||||||
|
"check_date",
|
||||||
|
"previous_check_date",
|
||||||
|
]:
|
||||||
|
getattr(cls, field).validate(data.get(field))
|
||||||
|
out_data[field] = data.get(field)
|
||||||
|
except tortoise.exceptions.ValidationError:
|
||||||
|
return None
|
||||||
|
return out_data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_update(cls, data: dict[str, typing.Any]) -> dict | None:
|
||||||
|
out_data = {}
|
||||||
|
try:
|
||||||
|
for field in [
|
||||||
|
"list",
|
||||||
|
"name",
|
||||||
|
"reset_cron",
|
||||||
|
"check_date",
|
||||||
|
"previous_check_date",
|
||||||
|
]:
|
||||||
|
if field in data:
|
||||||
|
getattr(cls, field).validate(data["field"])
|
||||||
|
out_data[field] = data["field"]
|
||||||
|
except tortoise.exceptions.ValidationError:
|
||||||
|
return None
|
||||||
|
return out_data
|
||||||
+43
-1
@@ -5,9 +5,10 @@ import flask
|
|||||||
import flask_limiter
|
import flask_limiter
|
||||||
import flask_limiter.util
|
import flask_limiter.util
|
||||||
import gunicorn.app.base
|
import gunicorn.app.base
|
||||||
|
import tortoise
|
||||||
|
|
||||||
from app import PKG_NAME
|
from app import PKG_NAME
|
||||||
from app.models.comment import Comment
|
from app.models import Comment, Task
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from app.params import Parameters
|
from app.params import Parameters
|
||||||
@@ -50,6 +51,47 @@ class Server(gunicorn.app.base.BaseApplication):
|
|||||||
await Comment.create(content=data["content"])
|
await Comment.create(content=data["content"])
|
||||||
return ("", 204)
|
return ("", 204)
|
||||||
|
|
||||||
|
@self.app.route("/api/lists/<list_name>", methods=["GET"])
|
||||||
|
async def get_tasks(list_name: str) -> list:
|
||||||
|
return await Task.filter(list=list_name).values()
|
||||||
|
|
||||||
|
@self.app.route("/api/lists/<list_name>", methods=["POST"])
|
||||||
|
async def post_task(list_name: str) -> typing.Any:
|
||||||
|
data = flask.request.get_json()
|
||||||
|
data["list"] = list_name
|
||||||
|
parsed_data = Task.validate_create(data)
|
||||||
|
if parsed_data is None:
|
||||||
|
flask.abort(400)
|
||||||
|
return (await Task.create(**parsed_data)).get().values()
|
||||||
|
|
||||||
|
@self.app.route("/api/lists/<list_name>/task/<task_uuid>", methods=["PUT"])
|
||||||
|
async def put_task(list_name: str, task_uuid: str) -> typing.Any:
|
||||||
|
data = flask.request.get_json()
|
||||||
|
data["list"] = list_name
|
||||||
|
parsed_data = Task.validate_update(data)
|
||||||
|
if parsed_data is None:
|
||||||
|
flask.abort(400)
|
||||||
|
try:
|
||||||
|
task = await Task.get(id=task_uuid)
|
||||||
|
await task.update_from_dict(parsed_data)
|
||||||
|
return task.get().values()
|
||||||
|
except tortoise.exceptions.ObjectDoesNotExistError:
|
||||||
|
flask.abort(404)
|
||||||
|
|
||||||
|
@self.app.route("/api/lists/<list_name>/task/<task_uuid>", methods=["DELETE"])
|
||||||
|
async def delete_task(list_name: str, task_uuid: str) -> typing.Any:
|
||||||
|
data = flask.request.get_json()
|
||||||
|
data["list"] = list_name
|
||||||
|
parsed_data = Task.validate_update(data)
|
||||||
|
if parsed_data is None:
|
||||||
|
flask.abort(400)
|
||||||
|
try:
|
||||||
|
task = await Task.get(id=task_uuid)
|
||||||
|
await task.delete()
|
||||||
|
except tortoise.exceptions.ObjectDoesNotExistError:
|
||||||
|
flask.abort(404)
|
||||||
|
return ""
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@typing.override
|
@typing.override
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ exclude = ["app/migrations"]
|
|||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["ALL"]
|
select = ["ALL"]
|
||||||
ignore = ["D", "E501", "ANN401", "BLE001", "COM812", "S101", "PT", "S104"]
|
ignore = ["D", "E501", "ANN401", "BLE001", "COM812", "S101", "PT", "S104", "C901"]
|
||||||
|
|
||||||
[tool.ty.src]
|
[tool.ty.src]
|
||||||
include = ["app"]
|
include = ["app"]
|
||||||
|
|||||||
Reference in New Issue
Block a user