Skip to content

Commit 23c7354

Browse files
authored
Merge branch 'develop' into feature/i18n
2 parents c6bbfd7 + 21faa13 commit 23c7354

Some content is hidden

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

49 files changed

+1063
-451
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,5 @@ app/.vscode/
148148

149149
# PyCharm
150150
.idea
151+
152+
junit/

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ uvicorn app.main:app --reload
3535
python -m venv venv
3636
source venv/bin/activate
3737
pip install -r requirements.txt
38-
cp app/config.py.example app/configuration.py
38+
cp app/config.py.example app/config.py
3939
# Edit the variables' values.
4040
uvicorn app.main:app --reload
4141
```

app/config.py.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ AVATAR_SIZE = (120, 120)
3232
WEBSITE_LANGUAGE = "en"
3333

3434
# API-KEYS
35+
# Get a free API KEY for Astronomy feature @ www.weatherapi.com/signup.aspx
36+
ASTRONOMY_API_KEY = os.getenv('ASTRONOMY_API_KEY')
3537
WEATHER_API_KEY = os.getenv('WEATHER_API_KEY')
3638

3739
# EXPORT

app/database/models.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
from datetime import datetime
44
from typing import Dict, Any
55

6+
7+
from app.config import PSQL_ENVIRONMENT
8+
from app.database.database import Base
69
from sqlalchemy import (DDL, Boolean, Column, DateTime, ForeignKey, Index,
7-
Integer, String, event, UniqueConstraint)
10+
Integer, String, event, UniqueConstraint, JSON)
811
from sqlalchemy.dialects.postgresql import TSVECTOR
912
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
1013
from sqlalchemy.orm import relationship, Session
1114

12-
from app.config import PSQL_ENVIRONMENT
13-
from app.database.database import Base
1415
from app.dependencies import logger
1516

1617

@@ -158,6 +159,16 @@ def __repr__(self):
158159
)
159160

160161

162+
class WikipediaEvents(Base):
163+
__tablename__ = "wikipedia_events"
164+
165+
id = Column(Integer, primary_key=True, index=True)
166+
date_ = Column(String, nullable=False)
167+
wikipedia = Column(String, nullable=False)
168+
events = Column(JSON, nullable=True)
169+
date_inserted = Column(DateTime, default=datetime.utcnow)
170+
171+
161172
class Quote(Base):
162173
__tablename__ = "quotes"
163174

app/internal/astronomy.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import datetime
2+
import functools
3+
import httpx
4+
from typing import Dict
5+
6+
from app import config
7+
8+
9+
# This feature requires an API KEY - get yours free @ www.weatherapi.com
10+
11+
ASTRONOMY_URL = "http://api.weatherapi.com/v1/astronomy.json"
12+
NO_API_RESPONSE = "No response from server"
13+
14+
15+
@functools.lru_cache(maxsize=128, typed=False)
16+
async def get_data_from_api(formatted_date: str, location: str)\
17+
-> Dict[str, int]:
18+
""" get the relevant astronomical data by calling the "weather api" API.
19+
Args:
20+
formatted_date (date) - relevant date.
21+
location (str) - location name.
22+
Returns:
23+
response_json (json dict) including:
24+
relevant part (data / error) of the JSON returned by the API.
25+
Success (bool)
26+
ErrorDescription (str) - error message.
27+
"""
28+
input_query_string = {'key': config.ASTRONOMY_API_KEY, 'q': location,
29+
'dt': formatted_date}
30+
output = {}
31+
try:
32+
async with httpx.AsyncClient() as client:
33+
response = await client.get(ASTRONOMY_URL,
34+
params=input_query_string)
35+
except httpx.HTTPError:
36+
output["Success"] = False
37+
output["ErrorDescription"] = NO_API_RESPONSE
38+
return output
39+
if response.status_code != httpx.codes.OK:
40+
output["Success"] = False
41+
output["ErrorDescription"] = NO_API_RESPONSE
42+
return output
43+
output["Success"] = True
44+
try:
45+
output.update(response.json()['location'])
46+
return output
47+
except KeyError:
48+
output["Success"] = False
49+
output["ErrorDescription"] = response.json()['error']['message']
50+
return output
51+
52+
53+
async def get_astronomical_data(requested_date: datetime.datetime,
54+
location: str) -> Dict[str, int]:
55+
""" get astronomical data (Sun & Moon) for date & location -
56+
main function.
57+
Args:
58+
requested_date (date) - date requested for astronomical data.
59+
location (str) - location name.
60+
Returns: dictionary with the following entries:
61+
Status - success / failure.
62+
ErrorDescription - error description (relevant only in case of error).
63+
location - relevant location values(relevant only in case of success).
64+
name, region, country, lat, lon etc.
65+
astronomy - relevant astronomy values, all time in local time -
66+
(relevant only in case of success):
67+
sunrise, sunset, moonrise, moonset, moon_phase, moon_illumination.
68+
"""
69+
formatted_date = requested_date.strftime('%Y-%m-%d')
70+
return await get_data_from_api(formatted_date, location)

app/internal/on_this_day_events.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import json
2+
from datetime import date, datetime
3+
from typing import Any, Dict
4+
import requests
5+
from fastapi import Depends
6+
from loguru import logger
7+
from sqlalchemy import func
8+
from sqlalchemy.exc import SQLAlchemyError
9+
from sqlalchemy.orm import Session
10+
from sqlalchemy.orm.exc import NoResultFound
11+
12+
from app.database.database import get_db
13+
from app.database.models import WikipediaEvents
14+
15+
16+
def insert_on_this_day_data(
17+
db: Session = Depends(get_db)
18+
) -> Dict[str, Any]:
19+
now = datetime.now()
20+
day, month = now.day, now.month
21+
22+
res = requests.get(
23+
f'https://byabbe.se/on-this-day/{month}/{day}/events.json')
24+
text = json.loads(res.text)
25+
res_events = text.get('events')
26+
res_date = text.get('date')
27+
res_wiki = text.get('wikipedia')
28+
db.add(WikipediaEvents(events=res_events,
29+
date_=res_date, wikipedia=res_wiki))
30+
db.commit()
31+
return text
32+
33+
34+
def get_on_this_day_events(
35+
db: Session = Depends(get_db)
36+
) -> Dict[str, Any]:
37+
try:
38+
data = (db.query(WikipediaEvents).
39+
filter(
40+
func.date(WikipediaEvents.date_inserted) == date.today()).
41+
one())
42+
43+
except NoResultFound:
44+
data = insert_on_this_day_data(db)
45+
except (SQLAlchemyError, AttributeError) as e:
46+
logger.error(f'on this day failed with error: {e}')
47+
data = {'events': [], 'wikipedia': 'https://en.wikipedia.org/'}
48+
return data

app/main.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ def create_tables(engine, psql_environment):
3333
set_ui_language()
3434

3535
from app.routers import ( # noqa: E402
36-
agenda, calendar, categories, dayview, email,
37-
event, invitation, profile, search, telegram, whatsapp,
36+
agenda, calendar, categories, currency, dayview, email,
37+
event, invitation, profile, search, telegram, whatsapp
3838
)
3939

4040
json_data_loader.load_to_db(next(get_db()))
@@ -43,6 +43,7 @@ def create_tables(engine, psql_environment):
4343
agenda.router,
4444
calendar.router,
4545
categories.router,
46+
currency.router,
4647
dayview.router,
4748
email.router,
4849
event.router,

app/routers/agenda.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def calc_dates_range_for_agenda(
1717
start: Optional[date],
1818
end: Optional[date],
1919
days: Optional[int],
20-
) -> Tuple[date, date]:
20+
) -> Tuple[date, date]:
2121
"""Create start and end dates according to the parameters in the page."""
2222
if days is not None:
2323
start = date.today()
@@ -35,7 +35,7 @@ def agenda(
3535
start_date: Optional[date] = None,
3636
end_date: Optional[date] = None,
3737
days: Optional[int] = None,
38-
) -> _TemplateResponse:
38+
) -> _TemplateResponse:
3939
"""Route for the agenda page, using dates range or exact amount of days."""
4040

4141
user_id = 1 # there is no user session yet, so I use user id- 1.

app/routers/calendar.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async def calendar(request: Request) -> Response:
2020
user_local_time = cg.Day.get_user_local_time()
2121
day = cg.create_day(user_local_time)
2222
return templates.TemplateResponse(
23-
"calendar/calendar.html",
23+
"calendar_monthly_view.html",
2424
{
2525
"request": request,
2626
"day": day,
@@ -34,6 +34,7 @@ async def calendar(request: Request) -> Response:
3434
async def update_calendar(request: Request, date: str) -> HTMLResponse:
3535
last_day = cg.Day.convert_str_to_date(date)
3636
next_weeks = cg.create_weeks(cg.get_n_days(last_day, ADD_DAYS_ON_SCROLL))
37-
template = templates.get_template('calendar/add_week.html')
37+
template = templates.get_template(
38+
'partials/calendar/monthly_view/add_week.html')
3839
content = template.render(weeks_block=next_weeks)
3940
return HTMLResponse(content=content, status_code=HTTPStatus.OK)

app/routers/calendar_grid.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def __init__(self, date: datetime):
2929
self.date: datetime = date
3030
self.sday: str = self.date.strftime("%A")
3131
self.dailyevents: List[Tuple] = []
32-
self.events: List[Tuple] = []
32+
self.events: List[Tuple] = []
3333
self.css: Dict[str, str] = {
3434
'day_container': 'day',
3535
'date': 'day-number',
@@ -79,7 +79,7 @@ def __init__(self, date: datetime):
7979
super().__init__(date)
8080
self.css = {
8181
'day_container': 'day ',
82-
'date': ' '.join(['day-number', 'text-gray']),
82+
'date': ' '.join(['day-number', 'text-gray']),
8383
'daily_event': 'month-event',
8484
'daily_event_front': ' '.join([
8585
'daily',
@@ -100,7 +100,7 @@ class Today(Day):
100100
def __init__(self, date: datetime):
101101
super().__init__(date)
102102
self.css = {
103-
'day_container': ' '.join([
103+
'day_container': ' '.join([
104104
'day',
105105
'text-darkblue',
106106
'background-yellow'
@@ -134,7 +134,7 @@ def __init__(self, date: datetime):
134134
]),
135135
'date': 'day-number',
136136
'daily_event': 'month-event',
137-
'daily_event_front': ' '.join([
137+
'daily_event_front': ' '.join([
138138
'daily front',
139139
'text-lightgray',
140140
'background-red'
@@ -196,8 +196,8 @@ def get_n_days(date: datetime, n: int) -> Iterator[Day]:
196196

197197

198198
def create_weeks(
199-
days: Iterator[Day],
200-
length: int = Week.WEEK_DAYS
199+
days: Iterator[Day],
200+
length: int = Week.WEEK_DAYS
201201
) -> List[Week]:
202202
"""Return lists of Weeks objects."""
203203
ndays: List[Day] = list(days)

app/routers/categories.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ class CategoryModel(BaseModel):
2121
color: str
2222
user_id: int
2323

24+
class Config:
25+
schema_extra = {
26+
"example": {
27+
"name": "Guitar lessons",
28+
"color": "#aabbcc",
29+
"user_id": 1,
30+
}
31+
}
32+
2433

2534
# TODO(issue#29): get current user_id from session
2635
@router.get("/")

app/routers/currency.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import datetime
2+
3+
from app.dependencies import templates
4+
from fastapi import APIRouter, Request
5+
6+
7+
router = APIRouter()
8+
9+
# TODO: Add this as a feature to the calendar view/
10+
# day view/features panel frontend
11+
12+
13+
@router.get("/currency")
14+
def today_currency(request: Request):
15+
"""Current day currency router"""
16+
17+
date = datetime.date.today().strftime("%Y-%m-%d")
18+
return currency(request, date)
19+
20+
21+
@router.get("/currency/{date}")
22+
def currency(request: Request, date: str):
23+
"""Custom date currency router"""
24+
25+
# TODO: get user default/preferred currency
26+
base = "USD"
27+
28+
return templates.TemplateResponse("currency.html", {
29+
"request": request,
30+
"base": base,
31+
"date": date
32+
})

0 commit comments

Comments
 (0)