Skip to content

Commit

Permalink
[ITG-103] List of relation types added to Task (#38)
Browse files Browse the repository at this point in the history
Added relation_types to Task.
  • Loading branch information
bkulawska committed May 11, 2022
1 parent 7d43ca1 commit af135fc
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 46 deletions.
7 changes: 7 additions & 0 deletions bode/bode/models/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from sqlalchemy import Enum
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.exc import IntegrityError, NoResultFound
from sqlalchemy.ext.hybrid import hybrid_property

from bode.app import db
from bode.models.tag import Tag
Expand Down Expand Up @@ -35,6 +36,12 @@ class Task(db.Model):

tags = db.relationship("Tag", secondary=task_tag, back_populates="task")

@hybrid_property
def relation_types(self):
from bode.models.task_relations_actions import get_relation_types

return get_relation_types(self.id)

def get(task_id):
return Task.query.get_or_404(task_id)

Expand Down
6 changes: 4 additions & 2 deletions bode/bode/models/task_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

def delete_task(task_id):
"""Function deletes task, all it's relations and all it's subtasks reursively."""
from bode.models.task_relations_actions import get_related_tasks

def is_subtask_relation(relation):
return relation.type == RelationType.Subtask.value and str(relation.first_task_id) == task_id

relation_task_pairs = TaskRelation.get_related_tasks(task_id)
relation_task_pairs = get_related_tasks(task_id)

for relation, related_task in relation_task_pairs:
TaskRelation.delete(relation.id)
Expand All @@ -24,6 +25,7 @@ def is_subtask_relation(relation):

def edit_task(task_id, **task_data):
"""Function edits task. If task is checked, all interchangable tasks with status todo will be indirectly checked."""
from bode.models.task_relations_actions import get_related_tasks

def is_interchangable_relation(relation):
return relation.type == RelationType.Interchangable.value and str(relation.first_task_id) == task_id
Expand All @@ -38,7 +40,7 @@ def is_interchangable_relation(relation):
db.session.commit()

if task_data["status"] != TaskStatus.TODO.value:
for relation, related_task in TaskRelation.get_related_tasks(task_id):
for relation, related_task in get_related_tasks(task_id):
if is_interchangable_relation(relation):
if related_task.status != TaskStatus.TODO:
continue
Expand Down
22 changes: 0 additions & 22 deletions bode/bode/models/task_relation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from sqlalchemy.dialects.postgresql import ENUM, UUID

from bode.app import db
from bode.models.task import Task


class RelationType(Enum):
Expand Down Expand Up @@ -82,27 +81,6 @@ def delete(relation_id):

return relation

def get_lhs_related_tasks(task_id, filters=list()):
all_filters = [TaskRelation.first_task_id == task_id] + filters
return (
db.session.query(TaskRelation, Task)
.filter(*all_filters)
.join(Task, TaskRelation.second_task_id == Task.id)
.all()
)

def get_rhs_related_tasks(task_id, filters=list()):
all_filters = [TaskRelation.second_task_id == task_id] + filters
return (
db.session.query(TaskRelation, Task)
.filter(*all_filters)
.join(Task, TaskRelation.first_task_id == Task.id)
.all()
)

def get_related_tasks(task_id):
return TaskRelation.get_lhs_related_tasks(task_id) + TaskRelation.get_rhs_related_tasks(task_id)

def __repr__(self):
return f"""<TaskRelation
{self.first_task_id} <{self.type}> {self.second_task_id}
Expand Down
51 changes: 51 additions & 0 deletions bode/bode/models/task_relations_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from bode.app import db
from bode.models.task_relation import RelationType, TaskRelation
from bode.resources.task_relations.schemas import DirectedRelationType


def get_lhs_related_tasks(task_id, filters=list()):
from bode.models.task import Task

all_filters = [TaskRelation.first_task_id == task_id] + filters
return (
db.session.query(TaskRelation, Task)
.filter(*all_filters)
.join(Task, TaskRelation.second_task_id == Task.id)
.all()
)


def get_rhs_related_tasks(task_id, filters=list()):
from bode.models.task import Task

all_filters = [TaskRelation.second_task_id == task_id] + filters
return (
db.session.query(TaskRelation, Task)
.filter(*all_filters)
.join(Task, TaskRelation.first_task_id == Task.id)
.all()
)


def get_related_tasks(task_id):
return get_lhs_related_tasks(task_id) + get_rhs_related_tasks(task_id)


def map_to_related_task_schema(relation: TaskRelation, task_id):
match relation.type:
case RelationType.Dependent.value:
if task_id == relation.first_task_id:
return DirectedRelationType.IsBlockedBy.value
return DirectedRelationType.Blocks.value
case RelationType.Subtask.value:
if task_id == relation.first_task_id:
return DirectedRelationType.Supertask.value
return DirectedRelationType.Subtask.value
case _:
return DirectedRelationType.Interchangable.value


def get_relation_types(task_id):
relations_lhs = db.session.query(TaskRelation).filter(TaskRelation.first_task_id == task_id).all()
relations_rhs = db.session.query(TaskRelation).filter(TaskRelation.second_task_id == task_id).all()
return {map_to_related_task_schema(relation, task_id) for relation in relations_lhs + relations_rhs}
13 changes: 13 additions & 0 deletions bode/bode/resources/directed_relation_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from enum import Enum


class DirectedRelationType(Enum):
Blocks = "blocks"
IsBlockedBy = "is_blocked_by"
Subtask = "subtask"
Supertask = "supertask"
Interchangable = "interchangable"

@classmethod
def list(cls):
return [c.value for c in cls]
18 changes: 10 additions & 8 deletions bode/bode/resources/task_relations/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

from bode.models.task import Task
from bode.models.task_relation import RelationType, TaskRelation
from bode.models.task_relations_actions import (
get_lhs_related_tasks,
get_rhs_related_tasks,
)
from bode.resources.task_relations.schemas import (
LHS_RELATION_TYPES,
RHS_RELATION_TYPES,
Expand Down Expand Up @@ -70,9 +74,9 @@ def map_to_related_task_schema(self, relation: TaskRelation, task: Task):
match relation.type:
case RelationType.Dependent.value:
type = (
DirectedRelationType.Blocks.value
DirectedRelationType.IsBlockedBy.value
if task.id == relation.first_task_id
else DirectedRelationType.IsBlockedBy.value
else DirectedRelationType.Blocks.value
)
case RelationType.Subtask.value:
type = (
Expand All @@ -93,15 +97,13 @@ def get(self, params: DirectedRelationSchema, task_id: UUID):
query_result = []

if not relation_type:
query_result += TaskRelation.get_lhs_related_tasks(task_id)
query_result += TaskRelation.get_rhs_related_tasks(
task_id, [TaskRelation.type != RelationType.Interchangable.value]
)
query_result += get_lhs_related_tasks(task_id)
query_result += get_rhs_related_tasks(task_id, [TaskRelation.type != RelationType.Interchangable.value])

elif relation_type in SYMMETRIC_RELATION_TYPES + LHS_RELATION_TYPES:
query_result += TaskRelation.get_lhs_related_tasks(task_id, [self.lhs_relation_filter(relation_type)])
query_result += get_lhs_related_tasks(task_id, [self.lhs_relation_filter(relation_type)])

elif relation_type in RHS_RELATION_TYPES:
query_result += TaskRelation.get_rhs_related_tasks(task_id, [self.rhs_relation_filter(relation_type)])
query_result += get_rhs_related_tasks(task_id, [self.rhs_relation_filter(relation_type)])

return map(lambda pair: self.map_to_related_task_schema(*pair), query_result)
15 changes: 1 addition & 14 deletions bode/bode/resources/task_relations/schemas.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from enum import Enum

from marshmallow import ValidationError, fields, validate, validates_schema

from bode.models.task_relation import RelationType
from bode.resources.base_schema import BaseSchema
from bode.resources.directed_relation_type import DirectedRelationType
from bode.resources.tasks.schemas import TaskSchema


Expand All @@ -25,18 +24,6 @@ class SimpleTaskRelationSchema(BaseSchema):
type = fields.String()


class DirectedRelationType(Enum):
Blocks = "blocks"
IsBlockedBy = "is_blocked_by"
Subtask = "subtask"
Supertask = "supertask"
Interchangable = "interchangable"

@classmethod
def list(cls):
return [c.value for c in cls]


SYMMETRIC_RELATION_TYPES = [DirectedRelationType.Interchangable.value]
LHS_RELATION_TYPES = [DirectedRelationType.IsBlockedBy.value, DirectedRelationType.Subtask.value]
RHS_RELATION_TYPES = [DirectedRelationType.Blocks.value, DirectedRelationType.Supertask.value]
Expand Down
2 changes: 2 additions & 0 deletions bode/bode/resources/tasks/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from bode.models.task import TaskStatus
from bode.resources.base_schema import BaseSchema
from bode.resources.directed_relation_type import DirectedRelationType
from bode.resources.tags.schemas import TagInputSchema, TagSchema


Expand All @@ -23,3 +24,4 @@ class TaskSchema(BaseSchema):
due_date = fields.DateTime()
status = fields.String()
tags = fields.List(fields.Nested(TagSchema))
relation_types = fields.List(fields.String(validate=validate.OneOf(DirectedRelationType.list())))

0 comments on commit af135fc

Please sign in to comment.