Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/185/cloud migration #189

Merged
merged 59 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
a2292da
Update no new platform version
RichardKruemmel Aug 30, 2023
c21c603
Update env for pushing to new ebs env
RichardKruemmel Aug 30, 2023
0c66d21
Trigger cd pipeline on cloud migration branch
RichardKruemmel Aug 30, 2023
79d95e9
disable tests temporarily
RichardKruemmel Aug 30, 2023
0c2fa13
Update CI
RichardKruemmel Sep 28, 2023
d715024
Add openai
RichardKruemmel Sep 28, 2023
a5c0b50
Delete csv data
RichardKruemmel Sep 28, 2023
5da7e3e
Create new api version
RichardKruemmel Sep 28, 2023
25e9a95
Add Income to db model
RichardKruemmel Sep 28, 2023
56b40ab
Add Image copyright politician model
RichardKruemmel Sep 28, 2023
9196aeb
Add latest elections to parser
RichardKruemmel Sep 28, 2023
8c1daca
Add match topic to position function
RichardKruemmel Sep 28, 2023
6817c83
Create get last day of the month util function
RichardKruemmel Sep 28, 2023
5624f31
Add get party donation details function
RichardKruemmel Sep 28, 2023
50f5a8d
Update to v2 and incluse api v2
RichardKruemmel Sep 28, 2023
5f23b9c
Add new schemas
RichardKruemmel Sep 28, 2023
224d623
Update Schema naming
RichardKruemmel Sep 28, 2023
637fdc4
Fix politician route only showing 5 sidejobs
RichardKruemmel Sep 28, 2023
941ed99
Fix append_candidacies & comittees, add income to sidejobs, add appen…
RichardKruemmel Sep 28, 2023
0d517d0
Update information about scrapers
RichardKruemmel Oct 6, 2023
6c3ce7e
Load partydonation orgs and clean it
RichardKruemmel Oct 29, 2023
474867f
Extract and clean donors
RichardKruemmel Oct 29, 2023
60b7401
Fox reformat data function and check if donation exists
RichardKruemmel Oct 29, 2023
e86804f
Refactor partydonation org function
RichardKruemmel Oct 29, 2023
2afecef
Update no new platform version
RichardKruemmel Aug 30, 2023
abfe706
Update env for pushing to new ebs env
RichardKruemmel Aug 30, 2023
35a8e17
Trigger cd pipeline on cloud migration branch
RichardKruemmel Aug 30, 2023
2c9f8cf
Update CI
RichardKruemmel Sep 28, 2023
a87f0c9
Add openai
RichardKruemmel Sep 28, 2023
f211e61
Delete csv data
RichardKruemmel Sep 28, 2023
355bdc7
Create new api version
RichardKruemmel Sep 28, 2023
c633c5d
Add Income to db model
RichardKruemmel Sep 28, 2023
a37c66b
Add Image copyright politician model
RichardKruemmel Sep 28, 2023
aec9465
Add latest elections to parser
RichardKruemmel Sep 28, 2023
68812f2
Add match topic to position function
RichardKruemmel Sep 28, 2023
1feb6e2
Create get last day of the month util function
RichardKruemmel Sep 28, 2023
e2d7d2c
Add get party donation details function
RichardKruemmel Sep 28, 2023
7ebe1b0
Update to v2 and incluse api v2
RichardKruemmel Sep 28, 2023
b6ecf4e
Add new schemas
RichardKruemmel Sep 28, 2023
cb75721
Update Schema naming
RichardKruemmel Sep 28, 2023
64a3bc9
Fix politician route only showing 5 sidejobs
RichardKruemmel Sep 28, 2023
261f6f8
Fix append_candidacies & comittees, add income to sidejobs, add appen…
RichardKruemmel Sep 28, 2023
fa5ff71
Update information about scrapers
RichardKruemmel Oct 6, 2023
40a31d8
Load partydonation orgs and clean it
RichardKruemmel Oct 29, 2023
3ba5cda
Extract and clean donors
RichardKruemmel Oct 29, 2023
f4dc043
Fox reformat data function and check if donation exists
RichardKruemmel Oct 29, 2023
6bca07f
Refactor partydonation org function
RichardKruemmel Oct 29, 2023
71cfac2
Merge branch 'feature/185/cloud-migration' of https://github.com/Face…
RichardKruemmel Oct 29, 2023
d498848
Fix JSonEncoder for SQL models
RichardKruemmel Nov 5, 2023
a329d13
Change partydonation details to align with quarters and add helper fu…
RichardKruemmel Nov 5, 2023
f9c876d
Add get last day of the month function
RichardKruemmel Nov 5, 2023
1de0bd8
Fix donation_exists and clean_donations
RichardKruemmel Nov 5, 2023
5d0097a
Add donation_org exist, add edge cases and fix helper functions
RichardKruemmel Nov 5, 2023
b473ca0
Fix extract and clean donor function
RichardKruemmel Nov 5, 2023
9fb4475
Add caching to v2 routes
RichardKruemmel Nov 5, 2023
0596e68
Fix append partydonation function
RichardKruemmel Nov 5, 2023
767dde9
Update poetry.lock
RichardKruemmel Nov 5, 2023
78a3cc5
Add ci job for development PR
RichardKruemmel Nov 5, 2023
42acf86
Disable tests temporarily
RichardKruemmel Nov 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .elasticbeanstalk/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ environment-defaults:
global:
application_name: Face-The-Facts Backend
default_ec2_keyname: aws-eb
default_platform: Python 3.8 running on 64bit Amazon Linux 2
default_platform: Python 3.11 running on 64bit Amazon Linux 2
default_region: eu-central-1
include_git_submodules: true
instance_profile: null
Expand Down
17 changes: 2 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ on:
push:
branches: [main, development]
pull_request:
branches: [main]
branches: [main, development]

jobs:
ci:
Expand All @@ -27,23 +27,10 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

- name: Tests
env:
DATABASE_HOST: ${{ secrets.DATABASE_HOST}}
DATABASE_USER: ${{ secrets.DATABASE_USER}}
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD}}
DATABASE_NAME: ${{ secrets.DATABASE_NAME}}
POLITRACK_API_URL: ${{ secrets.POLITRACK_API_URL}}
POLITRACK_USERNAME: ${{ secrets.POLITRACK_USERNAME}}
POLITRACK_SECRET_PASSWORD: ${{ secrets.POLITRACK_SECRET_PASSWORD}}
REDIS_HOST: ${{ secrets.REDIS_HOST}}
# Exempt tests/e2e because tests/api uses production database to test whereas tests/e2e uses localhost == avoid conflicts
run: poetry run pytest -m "not e2e"

cd:
runs-on: ubuntu-latest
needs: [ci]
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/development') }}
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/development') }}

steps:
- name: Checkout source code
Expand Down
1,667 changes: 1,107 additions & 560 deletions poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ python-levenshtein = "^0.20.9"
aiofiles = "^23.1.0"
urllib3 = "1.26.15"
pylint = "^3.0.0"
openai = "^0.28.0"

[tool.poetry.dev-dependencies]
black = "22.3"
Expand Down
95 changes: 79 additions & 16 deletions src/api/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import datetime
from dateutil.relativedelta import relativedelta


# third-party
from sqlalchemy.orm import Session, joinedload

Expand All @@ -16,6 +17,7 @@
transform_topics_dict_to_minimal_array,
did_vote_pass,
)
from src.api.utils.date_utils import get_last_day_of_the_month
from src.api.utils.topic_ids_converter import convert_into_topic_id
from src.api.utils.party_sort import party_sort
from src.api.utils.speeches import fetch_speech_data, process_speech_data
Expand Down Expand Up @@ -541,22 +543,24 @@ def get_politician_by_constituency(
)
if candidacy_data:
constituency_id = candidacy_data.electoral_data.constituency_id
politicians = (
db.query(models.Politician)
.join(models.CandidacyMandate)
.join(models.ElectoralData)
.filter(models.ElectoralData.constituency_id == constituency_id)
.all()
)
constituency = (
db.query(models.Constituency)
.filter(models.Constituency.id == constituency_id)
.first()
)
constituency_politicians["constituency_number"] = constituency.number
constituency_politicians["constituency_name"] = constituency.name
constituency_politicians["politicians"] = party_sort(politicians)
return constituency_politicians

if constituency_id not in [9607, 4721, 5309, 423]:
politicians = (
db.query(models.Politician)
.join(models.CandidacyMandate)
.join(models.ElectoralData)
.filter(models.ElectoralData.constituency_id == constituency_id)
.all()
)
constituency = (
db.query(models.Constituency)
.filter(models.Constituency.id == constituency_id)
.first()
)
constituency_politicians["constituency_number"] = constituency.number
constituency_politicians["constituency_name"] = constituency.name
constituency_politicians["politicians"] = party_sort(politicians)
return constituency_politicians
return None


Expand Down Expand Up @@ -753,3 +757,62 @@ def get_parties(db: Session):
parties = db.query(models.Party).order_by(models.Party.id.asc()).all()

return parties


def get_end_of_current_quarter():
today = datetime.datetime.now()
quarter = (today.month - 1) // 3 + 1
return datetime.date(today.year, quarter * 3, 1) + relativedelta(months=1, days=-1)


def get_party_donations_details(db: Session, party_id: Optional[int]):
# Get all party donations sorted by party id, then by date, in ascending order
party_donations = (
db.query(models.PartyDonation)
.filter(models.PartyDonation.party_id == party_id)
.order_by(models.PartyDonation.date.asc())
.all()
if party_id
else db.query(models.PartyDonation)
.order_by(models.PartyDonation.party_id.asc(), models.PartyDonation.date.asc())
.all()
)

# Initialize the response structure
response_data = (
{}
if party_id is None
else {
"donations_older_than_8_years": [],
"donations_4_to_8_years_old": [],
"donations_less_than_4_years_old": [],
}
)

end_of_current_quarter = get_end_of_current_quarter()
four_years_ago = end_of_current_quarter - relativedelta(years=4)
eight_years_ago = end_of_current_quarter - relativedelta(years=8)

for donation in party_donations:
# Adjust the structure based on whether party_id is provided
if party_id:
donation_target = response_data
else:
party_key = str(donation.party_id)
if party_key not in response_data:
response_data[party_key] = {
"donations_older_than_8_years": [],
"donations_4_to_8_years_old": [],
"donations_less_than_4_years_old": [],
}
donation_target = response_data[party_key]

# add donation to the appropriate quarter range
if donation.date <= eight_years_ago:
donation_target["donations_older_than_8_years"].append(donation)
elif donation.date <= four_years_ago:
donation_target["donations_4_to_8_years_old"].append(donation)
else:
donation_target["donations_less_than_4_years_old"].append(donation)

return response_data
5 changes: 3 additions & 2 deletions src/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


# local
from src.api.versions import v1, plugin
from src.api.versions import v2, v1, plugin
from src.api.utils.openapi import api_description, tags_metadata
import src.cron_jobs.append_db as cron_jobs
from src.redis_cache.cache import redis_url, CustomFastApiRedisCache, get_redis
Expand All @@ -26,7 +26,7 @@
app = FastAPI(
title="FaceTheFacts API",
description=api_description,
version="1.0",
version="2.0",
terms_of_service="https://facethefacts.app/legal-notice",
contact={
"name": "FaceTheFacts",
Expand Down Expand Up @@ -56,6 +56,7 @@ def startup():
# List all versions here
app.include_router(plugin.router)
app.include_router(v1.router)
app.include_router(v2.router)

# CORS-policy
# * docs: https://fastapi.tiangolo.com/tutorial/cors/
Expand Down
37 changes: 37 additions & 0 deletions src/api/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class Sidejob(FTFBaseModel):
interval: Optional[str]
created: date
sidejob_organization: Optional[SidejobOrganization]
income: Optional[float]


# -----------------------
Expand Down Expand Up @@ -472,6 +473,12 @@ class Config:
}


class PoliticianWithSource(Politician):
image_copyright: Optional[str] = Field(
..., description="The copyright information for the politician's image"
)


class PoliticianHeader(FTFBaseModel):
id: int = Field(..., description="The unique ID of the politician")
label: str = Field(..., description="The name of the politician")
Expand Down Expand Up @@ -499,6 +506,30 @@ class Config:
}


class PoliticianHeaderWithSource(PoliticianHeader):
image_copyright: Optional[str] = Field(..., description="The source of the image")

class Config:
schema_extra = {
"example": {
"id": 79137,
"label": "Angela Merkel",
"party": {
"id": 2,
"label": "CDU",
"party_style": {
"id": 2,
"display_name": "CDU",
"foreground_color": "#FFFFFF",
"background_color": "#636363",
"border_color": None,
},
},
"image_copyright": "DBT/Inga Haar",
}
}


class VoteResult(FTFBaseModel):
yes: int
no: int
Expand Down Expand Up @@ -698,6 +729,12 @@ class HomepagePartyDonation(FTFBaseModel):
largest_quarter: float


class PartyDonationDetail(FTFBaseModel):
donations_older_than_8_years: List[PartyDonation]
donations_4_to_8_years_old: List[PartyDonation]
donations_less_than_4_years_old: List[PartyDonation]


class PluginPoll(FTFBaseModel):
poll: Poll
result: VoteResult
Expand Down
17 changes: 17 additions & 0 deletions src/api/utils/date_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import datetime


def get_last_day_of_the_month():
last_day_of_the_month = None

today = datetime.date.today()
tomorrow = today + datetime.timedelta(days=1)

if tomorrow.month != today.month:
last_day_of_the_month = today
else:
last_day_of_the_month = datetime.date(
today.year, today.month, 1
) - datetime.timedelta(days=1)

return last_day_of_the_month
2 changes: 1 addition & 1 deletion src/api/versions/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def read_politician(
votes_start: int = Query(None, description="Starting index of votes", example=0),
votes_end: int = Query(6, description="Ending index of votes", example=6),
):
return get_politician_profile(id, db, votes_start, votes_end, "v1")
return get_politician_profile(id, db, votes_start, votes_end)


@router.get(
Expand Down
Loading
Loading