Skip to content

Commit 507fb2e

Browse files
authored
Merge 6f784b5 into 2730ecf
2 parents 2730ecf + 6f784b5 commit 507fb2e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+33871
-6
lines changed

app/config.py.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,8 @@ LOG_FORMAT = ("<level>{level: <8}</level>"
114114
" - <cyan>{name}</cyan>:<cyan>{function}</cyan>"
115115
" - <level>{message}</level>")
116116

117+
# EXERCISE_FILE_PATH
118+
EXERCISE_FILE = "web_page/exercises/Exercise_{num}.htm"
119+
117120
# RESOURCES
118121
RESOURCES_DIR = pathlib.Path(__file__).parent / 'resources'

app/database/models.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class User(Base):
5757
avatar = Column(String, default="profile.png")
5858
telegram_id = Column(String, unique=True)
5959
is_active = Column(Boolean, default=False)
60+
is_active_exercise = Column(Boolean, default=False)
6061
disabled = Column(Boolean, default=False, nullable=False)
6162
privacy = Column(String, default="Private", nullable=False)
6263
is_manager = Column(Boolean, default=False)
@@ -101,6 +102,18 @@ async def get_by_username(db: Session, username: str) -> User:
101102
return db.query(User).filter(User.username == username).first()
102103

103104

105+
class UserExercise(Base):
106+
"""
107+
Table name user exercise
108+
Save when user start his exercise
109+
"""
110+
__tablename__ = "user_exercise"
111+
112+
id = Column(Integer, primary_key=True, index=True)
113+
user_id = Column(Integer, ForeignKey("users.id"))
114+
start_date = Column(DateTime, nullable=False)
115+
116+
104117
class Feature(Base):
105118
__tablename__ = "features"
106119

app/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def create_tables(engine, psql_environment):
7070
dayview,
7171
email,
7272
event,
73+
exercise,
7374
export,
7475
features,
7576
four_o_four,
@@ -124,6 +125,7 @@ async def swagger_ui_redirect():
124125
dayview.router,
125126
email.router,
126127
event.router,
128+
exercise.router,
127129
export.router,
128130
features.router,
129131
four_o_four.router,

app/routers/event.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,8 @@ def is_fields_types_valid(to_check: Dict[str, Any], types: Dict[str, Any]):
416416
"""validate dictionary values by dictionary of types"""
417417
errors = []
418418
for field_name, field_type in to_check.items():
419-
if types[field_name] and not isinstance(field_type, types[field_name]):
419+
if types[field_name] and not isinstance(field_type,
420+
(types[field_name])):
420421
errors.append(
421422
f"{field_name} is '{type(field_type).__name__}' and"
422423
+ f"it should be from type '{types[field_name].__name__}'",

app/routers/exercise.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from fastapi import APIRouter, Depends, Request
2+
from app.database.models import User
3+
from app.dependencies import get_db, templates
4+
from app.routers.user_exercise import get_user_exercise
5+
from datetime import datetime
6+
from app import config
7+
from sqlalchemy.orm import Session
8+
9+
router = APIRouter(
10+
prefix="/exercise",
11+
tags=["exercise"],
12+
responses={404: {"description": "Not found"}},
13+
)
14+
15+
16+
@router.get("/")
17+
async def exercise(
18+
request: Request,
19+
session: Session = Depends(get_db),
20+
):
21+
"""
22+
If is active exercise = True
23+
Show user exercise for a specific day if is_active_exercise is ture.
24+
"""
25+
user = session.query(User).filter_by(id=1).first()
26+
if not user:
27+
# create empty default user
28+
user = User(
29+
username='',
30+
password='',
31+
email=''
32+
)
33+
# Get user exercise
34+
user_exercise = get_user_exercise(session, user_id=user.id)
35+
if user_exercise:
36+
# Get exercise day
37+
delta = datetime.now() - user_exercise[0].start_date
38+
# All exercises split to 30 days
39+
day = (delta.days % 30) + 1
40+
else:
41+
day = 1
42+
exercise_day = str(config.EXERCISE_FILE.format(num=day))
43+
return templates.TemplateResponse("exercise.html", {
44+
"request": request,
45+
"user": user,
46+
"exercise": exercise_day
47+
})

app/routers/profile.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
from app.internal.on_this_day_events import get_on_this_day_events
1919
from app.internal.privacy import PrivacyKinds
2020
from app.internal.showevent import get_upcoming_events
21-
21+
from app.routers.user_exercise import create_user_exercise
22+
from sqlalchemy.orm import Session
2223
PICTURE_EXTENSION = config.PICTURE_EXTENSION
2324
PICTURE_SIZE = config.AVATAR_SIZE
2425
FIVE_EVENTS = 5
@@ -39,6 +40,7 @@ def get_placeholder_user():
3940
full_name="My Name",
4041
language_id=1,
4142
telegram_id="",
43+
is_active_exercise=False,
4244
)
4345

4446

@@ -88,6 +90,32 @@ async def profile(
8890
)
8991

9092

93+
@router.get("/exercise/start")
94+
async def start_exercise(session: Session = Depends(get_db)):
95+
user = session.query(User).filter_by(id=1).first()
96+
97+
# Update database
98+
user.is_active_exercise = True
99+
session.commit()
100+
101+
# create user exercise
102+
create_user_exercise(session, user)
103+
url = router.url_path_for("profile")
104+
return RedirectResponse(url=url, status_code=HTTP_302_FOUND)
105+
106+
107+
@router.get("/exercise/stop")
108+
async def stop_exercise(session=Depends(get_db)):
109+
user = session.query(User).filter_by(id=1).first()
110+
111+
# Update database
112+
user.is_active_exercise = False
113+
session.commit()
114+
115+
url = router.url_path_for("profile")
116+
return RedirectResponse(url=url, status_code=HTTP_302_FOUND)
117+
118+
91119
@router.post("/update_user_fullname")
92120
async def update_user_fullname(request: Request, session=Depends(get_db)):
93121
user = session.query(User).filter_by(id=1).first()

app/routers/user_exercise.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from sqlalchemy.exc import SQLAlchemyError
2+
from sqlalchemy.orm import Session
3+
from datetime import datetime
4+
from app.database.models import Base, User, UserExercise
5+
6+
7+
def save(session: Session, instance: Base) -> bool:
8+
"""Commits an instance to the db.
9+
source: app.database.models.Base"""
10+
11+
if issubclass(instance.__class__, Base):
12+
session.add(instance)
13+
session.commit()
14+
return True
15+
return False
16+
17+
18+
def create_user_exercise(session: Session, user: User) -> UserExercise:
19+
"""Create and save new user exercise"""
20+
if not does_user_exercise_exist(session=session, user_id=user.id):
21+
user_exercise = UserExercise(
22+
user_id=user.id,
23+
start_date=datetime.now()
24+
)
25+
save(session=session, instance=user_exercise)
26+
else:
27+
user_exercise = update_user_exercise(session=session, user=user)
28+
return user_exercise
29+
30+
31+
def does_user_exercise_exist(session: Session, user_id: int) -> bool:
32+
"""Check if a user exercise for user id exists."""
33+
return get_user_exercise(session=session, user_id=user_id)
34+
35+
36+
def get_user_exercise(session: Session, **param) -> list:
37+
"""Returns user exercise filter by param."""
38+
try:
39+
user_exercise = list(session.query(UserExercise).filter_by(**param))
40+
except SQLAlchemyError:
41+
return []
42+
else:
43+
return user_exercise
44+
45+
46+
def update_user_exercise(session: Session, user: User) -> UserExercise:
47+
user_ex = session.query(UserExercise).filter_by(user_id=user.id).first()
48+
# Update database
49+
user_ex.start_date = datetime.now()
50+
session.commit()
51+
return user_ex

app/static/style.css

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,13 @@ p {
114114
}
115115

116116
.profile-modal-header {
117-
border: none;
118-
background-color: whitesmoke;
117+
border: none;
118+
background-color: whitesmoke;
119+
}
120+
121+
.exercise {
122+
font-family: 'Assistant', sans-serif;
123+
text-align: center;
119124
}
120125

121126
#on,

0 commit comments

Comments
 (0)