Skip to content

Commit 2730ecf

Browse files
Feature 179 add notes to calendar (#267)
* Apply automatic translateable string changes
1 parent fd99fc1 commit 2730ecf

35 files changed

+1154
-352
lines changed

Diff for: app/database/models.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ class UserFeature(Base):
3939
__tablename__ = "user_feature"
4040

4141
id = Column(Integer, primary_key=True, index=True)
42-
feature_id = Column('feature_id', Integer, ForeignKey('features.id'))
43-
user_id = Column('user_id', Integer, ForeignKey('users.id'))
42+
feature_id = Column("feature_id", Integer, ForeignKey("features.id"))
43+
user_id = Column("user_id", Integer, ForeignKey("users.id"))
4444

4545
is_enable = Column(Boolean, default=False)
4646

@@ -90,6 +90,8 @@ class User(Base):
9090
uselist=False,
9191
)
9292

93+
notes = relationship("Note", back_populates="creator")
94+
9395
def __repr__(self):
9496
return f"<User {self.id}>"
9597

@@ -614,3 +616,18 @@ def insert_data(target, session: Session, **kw):
614616

615617

616618
event.listen(Language.__table__, "after_create", insert_data)
619+
620+
621+
class Note(Base):
622+
__tablename__ = "notes"
623+
624+
id = Column(Integer, primary_key=True, index=True)
625+
title = Column(String, nullable=False)
626+
description = Column(String)
627+
timestamp = Column(DateTime, default=datetime.utcnow, nullable=False)
628+
user_id = Column(Integer, ForeignKey("users.id"))
629+
630+
creator = relationship("User", back_populates="notes")
631+
632+
def __repr__(self) -> str:
633+
return f"<Note {self.id} {self.title}>"

Diff for: app/database/schemas.py

+35-10
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
1+
from datetime import datetime
12
from typing import Optional, Union
23

3-
from pydantic import BaseModel, EmailError, EmailStr, validator
4+
from pydantic import BaseModel, EmailError, EmailStr, Field, validator
45

56
EMPTY_FIELD_STRING = "field is required"
67
MIN_FIELD_LENGTH = 3
78
MAX_FIELD_LENGTH = 20
89

910

10-
def fields_not_empty(field: Optional[str]) -> Union[ValueError, str]:
11+
def fields_not_empty(field: Optional[str]) -> str:
1112
"""Global function to validate fields are not empty."""
1213
if not field:
1314
raise ValueError(EMPTY_FIELD_STRING)
1415
return field
1516

1617

18+
class UserModel(BaseModel):
19+
username: str
20+
password: str
21+
email: str = Field(regex="^\\S+@\\S+\\.\\S+$")
22+
language: str
23+
language_id: int
24+
25+
1726
class UserBase(BaseModel):
1827
"""
1928
Validating fields types
@@ -60,18 +69,14 @@ class UserCreate(UserBase):
6069
)
6170

6271
@validator("confirm_password")
63-
def passwords_match(
64-
cls,
65-
confirm_password: str,
66-
values: UserBase,
67-
) -> Union[ValueError, str]:
72+
def passwords_match(cls, confirm_password: str, values: UserBase) -> str:
6873
"""Validating passwords fields identical."""
6974
if "password" in values and confirm_password != values["password"]:
7075
raise ValueError("doesn't match to password")
7176
return confirm_password
7277

7378
@validator("username")
74-
def username_length(cls, username: str) -> Union[ValueError, str]:
79+
def username_length(cls, username: str) -> str:
7580
"""Validating username length is legal"""
7681
if not (MIN_FIELD_LENGTH < len(username) < MAX_FIELD_LENGTH):
7782
raise ValueError("must contain between 3 to 20 charactars")
@@ -80,14 +85,14 @@ def username_length(cls, username: str) -> Union[ValueError, str]:
8085
return username
8186

8287
@validator("password")
83-
def password_length(cls, password: str) -> Union[ValueError, str]:
88+
def password_length(cls, password: str) -> str:
8489
"""Validating username length is legal"""
8590
if not (MIN_FIELD_LENGTH < len(password) < MAX_FIELD_LENGTH):
8691
raise ValueError("must contain between 3 to 20 charactars")
8792
return password
8893

8994
@validator("email")
90-
def confirm_mail(cls, email: str) -> Union[ValueError, str]:
95+
def confirm_mail(cls, email: str) -> str:
9196
"""Validating email is valid mail address."""
9297
try:
9398
EmailStr.validate(email)
@@ -104,3 +109,23 @@ class User(UserBase):
104109

105110
id: int
106111
is_active: bool
112+
113+
114+
class NoteSchema(BaseModel):
115+
title: str
116+
description: Optional[str] = None
117+
timestamp: Optional[datetime]
118+
creator: Optional[User]
119+
120+
class Config:
121+
orm_mode = True
122+
schema_extra = {
123+
"example": {
124+
"title": "Foo",
125+
"description": "Bar",
126+
},
127+
}
128+
129+
130+
class NoteDB(NoteSchema):
131+
id: int

Diff for: app/internal/agenda_events.py

+25-26
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,26 @@
66
from sqlalchemy.orm import Session
77

88
from app.database.models import Event
9+
from app.internal.user import user
910
from app.routers.event import sort_by_date
10-
from app.routers.user import get_all_user_events
1111

1212

1313
def get_events_per_dates(
14-
session: Session,
15-
user_id: int,
16-
start: Optional[date],
17-
end: Optional[date]
14+
session: Session,
15+
user_id: int,
16+
start: Optional[date],
17+
end: Optional[date],
1818
) -> Union[Iterator[Event], list]:
1919
"""Read from the db. Return a list of all
2020
the user events between the relevant dates."""
2121

2222
if start > end:
2323
return []
2424

25-
return (
26-
filter_dates(
27-
sort_by_date(
28-
get_all_user_events(session, user_id)
29-
),
30-
start,
31-
end,
32-
)
25+
return filter_dates(
26+
sort_by_date(user.get_all_user_events(session, user_id)),
27+
start,
28+
end,
3329
)
3430

3531

@@ -54,15 +50,17 @@ def get_time_delta_string(start: date, end: date) -> str:
5450
diff = end - start
5551
granularity = build_arrow_delta_granularity(diff)
5652
duration_string = arrow_end.humanize(
57-
arrow_start, only_distance=True, granularity=granularity
53+
arrow_start,
54+
only_distance=True,
55+
granularity=granularity,
5856
)
5957
return duration_string
6058

6159

6260
def filter_dates(
63-
events: List[Event],
64-
start: Union[None, date] = None,
65-
end: Union[None, date] = None,
61+
events: List[Event],
62+
start: Union[None, date] = None,
63+
end: Union[None, date] = None,
6664
) -> Iterator[Event]:
6765
"""Returns all events in a time frame.
6866
@@ -82,24 +80,25 @@ def filter_dates(
8280

8381

8482
def get_events_in_time_frame(
85-
start_date: Union[date, None],
86-
end_date: Union[date, None],
87-
user_id: int, db: Session
83+
start_date: Union[date, None],
84+
end_date: Union[date, None],
85+
user_id: int,
86+
db: Session,
8887
) -> Iterator[Event]:
8988
"""Yields all user's events in a time frame."""
90-
events = get_all_user_events(db, user_id)
89+
events = user.get_all_user_events(db, user_id)
9190
yield from filter_dates(events, start_date, end_date)
9291

9392

94-
def get_events_for_the_week(db: Session, user_id: int
95-
) -> Tuple[Union[Iterator[Event], list], Dict]:
93+
def get_events_for_the_week(
94+
db: Session,
95+
user_id: int,
96+
) -> Tuple[Union[Iterator[Event], list], Dict]:
9697
WEEK_DAYS = 7
9798
start_date = date.today()
9899
end_date = start_date + timedelta(days=WEEK_DAYS - 1)
99100

100-
events_this_week = get_events_per_dates(
101-
db, user_id, start_date, end_date
102-
)
101+
events_this_week = get_events_per_dates(db, user_id, start_date, end_date)
103102
events_for_graph = {
104103
str(start_date + timedelta(i)): 0 for i in range(WEEK_DAYS)
105104
}

Diff for: app/internal/friend_view.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@
33
from sqlalchemy.orm import Session
44

55
from app.database.models import Event
6+
from app.internal.user import user
67
from app.routers.event import sort_by_date
7-
from app.routers.user import get_all_user_events
88

99

1010
def get_events_per_friend(
11-
session: Session,
12-
user_id: int,
13-
my_friend: str,
11+
session: Session,
12+
user_id: int,
13+
my_friend: str,
1414
) -> List[Event]:
15-
""" My_friend is the name of a person that appears in the invite list of
15+
"""My_friend is the name of a person that appears in the invite list of
1616
events. He is not necessarily a registered userץ The variable is used to
1717
show all events where we are both in the invitees list"""
1818

1919
events_together = []
20-
sorted_events = sort_by_date(get_all_user_events(session, user_id))
20+
sorted_events = sort_by_date(user.get_all_user_events(session, user_id))
2121
for event in sorted_events:
22-
if my_friend in event.invitees.split(','):
22+
if my_friend in event.invitees.split(","):
2323
events_together.append(event)
2424
return events_together

Diff for: app/internal/notes/__init__.py

Whitespace-only changes.

Diff for: app/internal/notes/notes.py

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from datetime import datetime
2+
from typing import Any, Dict, List
3+
4+
from fastapi import HTTPException, status
5+
from sqlalchemy.orm import Session
6+
7+
from app.database.models import Note
8+
from app.database.schemas import NoteSchema
9+
10+
11+
async def create(session: Session, payload: NoteSchema) -> int:
12+
note = Note(
13+
title=payload.title,
14+
description=payload.description,
15+
creator=payload.creator,
16+
)
17+
session.add(note)
18+
session.commit()
19+
session.refresh(note)
20+
return note.id
21+
22+
23+
async def view(session: Session, note_id: int) -> Note:
24+
note = session.query(Note).filter_by(id=note_id).first()
25+
if not note:
26+
raise HTTPException(
27+
status_code=status.HTTP_404_NOT_FOUND,
28+
detail=f"Note with id {note_id} not found",
29+
)
30+
return note
31+
32+
33+
async def get_all(
34+
session: Session,
35+
skip: int = 0,
36+
limit: int = 100,
37+
) -> List[Note]:
38+
return session.query(Note).offset(skip).limit(limit).all()
39+
40+
41+
async def update(request: NoteSchema, session: Session, note_id: int) -> str:
42+
note = session.query(Note).filter_by(id=note_id)
43+
if not note.first():
44+
raise HTTPException(
45+
status_code=status.HTTP_404_NOT_FOUND,
46+
detail=f"Note with id {note_id} not found",
47+
)
48+
if request.timestamp is None:
49+
request.timestamp = datetime.utcnow()
50+
note.update(request.dict(exclude_unset=True), synchronize_session=False)
51+
session.commit()
52+
return "updated"
53+
54+
55+
async def delete(session: Session, note_id: int) -> str:
56+
note = session.query(Note).filter_by(id=note_id)
57+
if not note.first():
58+
raise HTTPException(
59+
status_code=status.HTTP_404_NOT_FOUND,
60+
detail=f"Note with id {note_id} not found",
61+
)
62+
note.delete(synchronize_session=False)
63+
session.commit()
64+
return "deleted"
65+
66+
67+
async def create_note(note: NoteSchema, session: Session) -> Dict[str, Any]:
68+
note_id = await create(session, note)
69+
return {"id": note_id, **dict(note)}

0 commit comments

Comments
 (0)