Last active
September 1, 2019 22:05
-
-
Save ahussain3/f31db43f84a523ca7d6292eb3e437d9b to your computer and use it in GitHub Desktop.
Todo list design exercise (Advanced Software Design Week 2)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from enum import Enum | |
from models import Base | |
from datetime import DateTime | |
# CONSTANTS | |
DEFAULT_PRIORITY = 0 | |
# MODELS | |
class ItemState(Enum): | |
PENDING = "PENDING" | |
IN_PROGRESS = "IN_PROGRESS" | |
UNDER_REVIEW = "UNDER_REVIEW" | |
BLOCKED = "BLOCKED" | |
COMPLETED = "COMPLETED" | |
class RelationshipType(Enum): | |
FRIEND = "FRIEND" | |
class VisibilityLevel(Enum): | |
FRIENDS = "FRIENDS" # viewable by friends of the authed user | |
PRIVATE = "PRIVATE" # viewable by authed user only | |
alias itemId: int ## autogenerated | |
class Item(Base): | |
item_id: itemId ## int autogenerated | |
list_id: foreignKey(List, backref="items", list=True) # many-to-one relationship | |
title: String | |
description: Optional[String] | |
when_created: DateTime | |
when_updated: Optional[DateTime] | |
when_completed: Optional[DateTime] | |
when_deleted: Optional[DateTime] | |
when_due: Optional[DateTime] | |
state: Enum(ItemState) | |
is_active: bool # inactive items are considered deleted/archived | |
priority: int # (check constraint, 0 <= priority <= 5) | |
visibility: Enum(VisibilityLevel) | |
class List(Base): | |
list_id: int # autogenerated | |
name: str | |
when_created: DateTime | |
class User(Base): | |
user_id: int # autogenerated | |
list_id: foreignKey(TodoList, backref="user", list=False) | |
@property | |
def friends(self) -> List[User]: | |
return [friendship.to for friendship in db.get( | |
Relationship, type=RelationshipType.FRIEND, from=self | |
)] | |
class Relationship(Base): | |
"""To create a bidirectional relationship, you need one relationship going in each direction.""" | |
type: Enum(RelationshipType) | |
from: foreignKey(User) | |
to: foreignKey(User) | |
class TimePeriod: | |
from: Optional[DateTime] | |
to: Optional[DateTime] | |
# LOGIC | |
def get_items_for_user( | |
user_id: int, | |
when_created: Optional[TimePeriod] = None, | |
when_due: Optional[TimePeriod] = None, | |
state: Optional[List[ItemState]] = None, | |
visibility: VisibilityLevel = VisibilityLevel.FRIENDS, | |
limit = Optional[int] = None, | |
) -> List[Item]: | |
def create_item( | |
title: str, | |
description: Optional[str] = None, | |
status: Optional[] = None, | |
priority: Optional[int] = None, | |
when_due: Optional[DateTime] = None, | |
visibility: VisibilityLevel = VisibilityLevel.FRIENDS, | |
) -> Item: | |
def edit_item( | |
item_id: itemId, | |
title: Optional[str] = None, | |
description: Optional[str] = None, | |
status: Optional[] = None, | |
priority: Optional[int] = None, | |
when_due: Optional[DateTime] = None, | |
visibility: VisibilityLevel = VisibilityLevel.FRIENDS, | |
) -> Item: | |
"""Any field that is None is left untouched.""" | |
def delete_item(item_id: itemId) -> None: | |
# API methods | |
def login() -> SessionId: | |
# set `logged_in_user` on Session | |
def logout() -> None: | |
# need some kind of middleware such that each function below knows who the logged in | |
# user is. | |
def get_friends() -> List[User]: | |
"""Get a list of friends for the logged in user.""" | |
def view_list( | |
user_id: Optional[int] = None, # None means show list for logged in user | |
n: int = 50, | |
show_completed: bool = true, | |
order_by: str = "when_created", # one of "priority" | "when_created" | "when_due" | |
for_user: Optional[int(userId)], # if none it shows the list of the authenticated user | |
) -> List[Item]: | |
"""By default shows the n most recent todo items.""" | |
# This function needs to check to see who the authenticated user is and check | |
# that they have permission to view the content they are trying to view? | |
def create_item( | |
title: str, | |
description: Optional[str] = None, | |
) -> Item: | |
# Check that the logged in user has permission to perform this action | |
def set_status(item_id: itemId, status: str) -> Item: | |
# Check that the logged in user has permission to perform this action | |
def set_priority(item_id: itemId, priority: int) -> Item: | |
# Check that the logged in user has permission to perform this action | |
def set_due_date(item_id: itemId, due_date: DateTime) -> Item: | |
# Check that the logged in user has permission to perform this action | |
def set_visiblity(item_id: itemId, is_private: bool) -> Item: | |
# Check that the logged in user has permission to perform this action | |
def delete_item(item_id: itemId) -> None: | |
# Check that the logged in user has permission to perform this action | |
def mark_as_done(item_id: itemId) -> Item: | |
# Check that the logged in user has permission to perform this action | |
def make_as_not_done(item_id: itemId) -> Item: | |
# Check that the logged in user has permission to perform this action | |
# UI | |
# I think the most important thing here is that the authentication / authorization | |
# logic is kept separate from the main API. | |
# The UI for viewing a friends todo list would be the same as viewing one's own todo | |
# list, except that the view_list() API call is made by passing in the user id of the | |
# friend whose list you want to view. | |
# There needs to be a separate UI page where the user can view a list of their friends, | |
# and then they need to select a friend in order to view their todo list. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment