fix: working tasks after first tests
TS Lint / ESLint (push) Successful in 1m0s
Python Lint CI / ty (push) Successful in 1m6s
Python Lint CI / ruff (push) Successful in 1m7s
Python Lint CI / ruff-format-check (push) Successful in 1m12s
TS Lint / Oxlint (push) Failing after 4m55s
TS Lint / TypeScript (push) Successful in 5m15s
TS Lint / ESLint (push) Successful in 1m0s
Python Lint CI / ty (push) Successful in 1m6s
Python Lint CI / ruff (push) Successful in 1m7s
Python Lint CI / ruff-format-check (push) Successful in 1m12s
TS Lint / Oxlint (push) Failing after 4m55s
TS Lint / TypeScript (push) Successful in 5m15s
This commit is contained in:
+1
-1
@@ -13,5 +13,5 @@ def main() -> int:
|
|||||||
setup_logs(params)
|
setup_logs(params)
|
||||||
logging.getLogger().info("%s %s", PKG_NAME, PKG_VERSION)
|
logging.getLogger().info("%s %s", PKG_NAME, PKG_VERSION)
|
||||||
Database(params).init()
|
Database(params).init()
|
||||||
Server(params).register_routes().start()
|
Server(params).register_routes().run()
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Migration(migrations.Migration):
|
|||||||
('id', fields.UUIDField(primary_key=True, default=uuid4, unique=True, db_index=True)),
|
('id', fields.UUIDField(primary_key=True, default=uuid4, unique=True, db_index=True)),
|
||||||
('created_at', fields.DatetimeField(auto_now=False, auto_now_add=True)),
|
('created_at', fields.DatetimeField(auto_now=False, auto_now_add=True)),
|
||||||
('updated_at', fields.DatetimeField(auto_now=True, auto_now_add=False)),
|
('updated_at', fields.DatetimeField(auto_now=True, auto_now_add=False)),
|
||||||
('list', fields.CharField(db_index=True, max_length=32)),
|
('list_name', fields.CharField(db_index=True, max_length=32)),
|
||||||
('name', fields.TextField(unique=False)),
|
('name', fields.TextField(unique=False)),
|
||||||
('reset_cron', fields.CharField(null=True, max_length=32)),
|
('reset_cron', fields.CharField(null=True, max_length=32)),
|
||||||
('check_date', fields.DatetimeField(null=True, auto_now=False, auto_now_add=False)),
|
('check_date', fields.DatetimeField(null=True, auto_now=False, auto_now_add=False)),
|
||||||
|
|||||||
+5
-1
@@ -1,4 +1,5 @@
|
|||||||
import tortoise
|
import typing
|
||||||
|
|
||||||
import tortoise.models
|
import tortoise.models
|
||||||
|
|
||||||
|
|
||||||
@@ -9,3 +10,6 @@ class AbstractModel(tortoise.models.Model):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
def serialize(self) -> dict[str, typing.Any]:
|
||||||
|
return dict(self) # ty:ignore[no-matching-overload]
|
||||||
|
|||||||
+9
-12
@@ -1,41 +1,41 @@
|
|||||||
import typing
|
import typing
|
||||||
|
|
||||||
import tortoise
|
import tortoise
|
||||||
|
import tortoise.validators
|
||||||
|
|
||||||
from app.models.base import AbstractModel
|
from app.models.base import AbstractModel
|
||||||
|
|
||||||
# https://stackoverflow.com/a/57639657
|
# 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})/"
|
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):
|
class Task(AbstractModel):
|
||||||
list = tortoise.fields.CharField(max_length=32, db_index=True, null=False)
|
list_name = tortoise.fields.CharField(max_length=32, db_index=True, null=False)
|
||||||
name = tortoise.fields.TextField(null=False)
|
name = tortoise.fields.TextField(null=False)
|
||||||
reset_cron = tortoise.fields.CharField(max_length=64, null=True)
|
reset_cron = tortoise.fields.CharField(
|
||||||
|
max_length=64,
|
||||||
|
null=True,
|
||||||
|
validators=[tortoise.validators.RegexValidator(CRONTAB_REGEX, 0)],
|
||||||
|
)
|
||||||
check_date = tortoise.fields.DatetimeField(null=True)
|
check_date = tortoise.fields.DatetimeField(null=True)
|
||||||
previous_check_date = tortoise.fields.DatetimeField(null=True)
|
previous_check_date = tortoise.fields.DatetimeField(null=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_create(cls, data: dict[str, typing.Any]) -> dict | None:
|
def validate_create(cls, data: dict[str, typing.Any]) -> dict | None:
|
||||||
out_data = {}
|
out_data = {}
|
||||||
try:
|
|
||||||
for field in [
|
for field in [
|
||||||
"list",
|
"list_name",
|
||||||
"name",
|
"name",
|
||||||
"reset_cron",
|
"reset_cron",
|
||||||
"check_date",
|
"check_date",
|
||||||
"previous_check_date",
|
"previous_check_date",
|
||||||
]:
|
]:
|
||||||
getattr(cls, field).validate(data.get(field))
|
|
||||||
out_data[field] = data.get(field)
|
out_data[field] = data.get(field)
|
||||||
except tortoise.exceptions.ValidationError:
|
|
||||||
return None
|
|
||||||
return out_data
|
return out_data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_update(cls, data: dict[str, typing.Any]) -> dict | None:
|
def validate_update(cls, data: dict[str, typing.Any]) -> dict | None:
|
||||||
out_data = {}
|
out_data = {}
|
||||||
try:
|
|
||||||
for field in [
|
for field in [
|
||||||
"name",
|
"name",
|
||||||
"reset_cron",
|
"reset_cron",
|
||||||
@@ -43,8 +43,5 @@ class Task(AbstractModel):
|
|||||||
"previous_check_date",
|
"previous_check_date",
|
||||||
]:
|
]:
|
||||||
if field in data:
|
if field in data:
|
||||||
getattr(cls, field).validate(data["field"])
|
|
||||||
out_data[field] = data["field"]
|
out_data[field] = data["field"]
|
||||||
except tortoise.exceptions.ValidationError:
|
|
||||||
return None
|
|
||||||
return out_data
|
return out_data
|
||||||
|
|||||||
+13
-27
@@ -53,41 +53,40 @@ class Server(gunicorn.app.base.BaseApplication):
|
|||||||
|
|
||||||
@self.app.route("/api/lists/<list_name>/tasks", methods=["GET"])
|
@self.app.route("/api/lists/<list_name>/tasks", methods=["GET"])
|
||||||
async def get_tasks(list_name: str) -> list:
|
async def get_tasks(list_name: str) -> list:
|
||||||
return await Task.filter(list=list_name).values()
|
return await Task.filter(list_name=list_name).values()
|
||||||
|
|
||||||
@self.app.route("/api/lists/<list_name>/tasks", methods=["POST"])
|
@self.app.route("/api/lists/<list_name>/tasks", methods=["POST"])
|
||||||
async def post_task(list_name: str) -> typing.Any:
|
async def post_task(list_name: str) -> typing.Any:
|
||||||
data = flask.request.get_json()
|
data = flask.request.get_json()
|
||||||
data["list"] = list_name
|
logging.getLogger(self.__class__.__name__).info("%s", data)
|
||||||
|
data["list_name"] = list_name
|
||||||
parsed_data = Task.validate_create(data)
|
parsed_data = Task.validate_create(data)
|
||||||
if parsed_data is None:
|
if parsed_data is None:
|
||||||
flask.abort(400)
|
flask.abort(400)
|
||||||
return (await Task.create(**parsed_data)).get().values()
|
return (await Task.create(**parsed_data)).serialize()
|
||||||
|
|
||||||
@self.app.route("/api/lists/<list_name>/tasks/<task_uuid>", methods=["PUT"])
|
@self.app.route("/api/tasks/<task_uuid>", methods=["PUT"])
|
||||||
async def put_task(list_name: str, task_uuid: str) -> typing.Any:
|
async def put_task(task_uuid: str) -> typing.Any:
|
||||||
data = flask.request.get_json()
|
data = flask.request.get_json()
|
||||||
data["list"] = list_name
|
|
||||||
parsed_data = Task.validate_update(data)
|
parsed_data = Task.validate_update(data)
|
||||||
if parsed_data is None:
|
if parsed_data is None:
|
||||||
flask.abort(400)
|
flask.abort(400)
|
||||||
try:
|
try:
|
||||||
task = await Task.get(id=task_uuid)
|
task = await Task.get(id=task_uuid)
|
||||||
await task.update_from_dict(parsed_data)
|
await task.update_from_dict(parsed_data)
|
||||||
return task.get().values()
|
return task.serialize()
|
||||||
|
except tortoise.exceptions.ValidationError:
|
||||||
|
flask.abort(400)
|
||||||
except tortoise.exceptions.ObjectDoesNotExistError:
|
except tortoise.exceptions.ObjectDoesNotExistError:
|
||||||
flask.abort(404)
|
flask.abort(404)
|
||||||
|
|
||||||
@self.app.route("/api/lists/<list_name>/tasks/<task_uuid>", methods=["DELETE"])
|
@self.app.route("/api/tasks/<task_uuid>", methods=["DELETE"])
|
||||||
async def delete_task(list_name: str, task_uuid: str) -> typing.Any:
|
async def delete_task(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:
|
try:
|
||||||
task = await Task.get(id=task_uuid)
|
task = await Task.get(id=task_uuid)
|
||||||
await task.delete()
|
await task.delete()
|
||||||
|
except tortoise.exceptions.ValidationError:
|
||||||
|
flask.abort(400)
|
||||||
except tortoise.exceptions.ObjectDoesNotExistError:
|
except tortoise.exceptions.ObjectDoesNotExistError:
|
||||||
flask.abort(404)
|
flask.abort(404)
|
||||||
return ""
|
return ""
|
||||||
@@ -106,16 +105,3 @@ class Server(gunicorn.app.base.BaseApplication):
|
|||||||
|
|
||||||
def load(self) -> flask.Flask:
|
def load(self) -> flask.Flask:
|
||||||
return self.app
|
return self.app
|
||||||
|
|
||||||
def start(self) -> None:
|
|
||||||
if self.env == "production":
|
|
||||||
self.run()
|
|
||||||
else:
|
|
||||||
self.app.run(
|
|
||||||
host=self.bind,
|
|
||||||
port=self.port,
|
|
||||||
debug=self.debug,
|
|
||||||
load_dotenv=False,
|
|
||||||
use_evalex=False,
|
|
||||||
use_reloader=False,
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -11,27 +11,26 @@ export async function createTask(
|
|||||||
): Promise<RawTask> {
|
): Promise<RawTask> {
|
||||||
const response = await fetch(`/api/lists/${list}/tasks`, {
|
const response = await fetch(`/api/lists/${list}/tasks`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ data }),
|
body: JSON.stringify({ ...data }),
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateTask(
|
export async function updateTask(
|
||||||
list: string,
|
|
||||||
taskId: string,
|
taskId: string,
|
||||||
data: TaskUpdateData,
|
data: TaskUpdateData,
|
||||||
): Promise<RawTask> {
|
): Promise<RawTask> {
|
||||||
const response = await fetch(`/api/lists/${list}/tasks/${taskId}`, {
|
const response = await fetch(`/api/tasks/${taskId}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
body: JSON.stringify({ data }),
|
body: JSON.stringify({ ...data }),
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
});
|
});
|
||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteTask(list: string, taskId: string): Promise<void> {
|
export async function deleteTask(taskId: string): Promise<void> {
|
||||||
await fetch(`/api/lists/${list}/tasks/${taskId}`, {
|
await fetch(`/api/tasks/${taskId}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export interface RawTask {
|
|||||||
id: string;
|
id: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
list: string;
|
list_name: string;
|
||||||
name: string;
|
name: string;
|
||||||
reset_cron: string | null;
|
reset_cron: string | null;
|
||||||
check_date: string | null;
|
check_date: string | null;
|
||||||
|
|||||||
Reference in New Issue
Block a user