Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
e2ad2da
Added initial files structure
Ibraam-Nashaat Jun 5, 2025
7270b74
Modified env.py to deal with hypertables
Ibraam-Nashaat Jun 8, 2025
1ea5fac
Modified index creation in env.py
Ibraam-Nashaat Jun 8, 2025
63c6680
Cleaned the files and added comments
Ibraam-Nashaat Jun 12, 2025
caa7100
Added documentation files
Ibraam-Nashaat Jun 12, 2025
cf1ef6d
Added license file
Ibraam-Nashaat Jun 12, 2025
48b0df2
Added more documentation files
Ibraam-Nashaat Jun 12, 2025
dd4324c
Added .env file, removed root path and modified the documentation files
Ibraam-Nashaat Jun 13, 2025
f3af036
Removed .env file
Ibraam-Nashaat Jun 14, 2025
f70ef03
Added database models
Ibraam-Nashaat Jun 16, 2025
999663d
Added more database models
Ibraam-Nashaat Jun 16, 2025
d1af5ad
Completed hegemony cone endpoint
Ibraam-Nashaat Jun 19, 2025
f668e60
Fixed foreign keys errors in models
Ibraam-Nashaat Jun 19, 2025
5ff2a66
Added missing indexes to models
Ibraam-Nashaat Jun 19, 2025
4379d01
Merge remote-tracking branch 'upstream/main' into database-models
Ibraam-Nashaat Jun 19, 2025
975d2ee
Untracked migration files
Ibraam-Nashaat Jun 23, 2025
6ad10dd
Renamed to hegemony_cone.py and added alembic/versions to gitignore
Ibraam-Nashaat Jun 23, 2025
7e92667
Returned some id(primary key) of tables back from BigInteger to Integer
Ibraam-Nashaat Jun 25, 2025
1a4b713
Removed foreign key constraints from some models
Ibraam-Nashaat Jun 25, 2025
df9d065
Completed merge
Ibraam-Nashaat Jun 25, 2025
92c6428
Added networks-endpoint
Ibraam-Nashaat Jun 25, 2025
337759e
Merge branch 'InternetHealthReport:main' into networks-endpoint
Ibraam-Nashaat Jun 27, 2025
bb3e0d3
Added link-delay endpoint
Ibraam-Nashaat Jun 29, 2025
d5867d3
Merge remote-tracking branch 'upstream/main' into link-delay-endpoint
Ibraam-Nashaat Jul 3, 2025
58ef29b
Added link-forwarding endpoint
Ibraam-Nashaat Jul 3, 2025
bad1113
Added /network_delay/locaions endpoint
Ibraam-Nashaat Jul 3, 2025
2f6bfe3
Added /metis/atlas/deployment endpoint
Ibraam-Nashaat Jul 3, 2025
526f316
Added /network_delay endpoint
Ibraam-Nashaat Jul 9, 2025
f7e0068
Added /network_delay/alarms endpoint
Ibraam-Nashaat Jul 9, 2025
23949e1
Change _lte and _gte in controller to __lte and __gte
Ibraam-Nashaat Jul 9, 2025
9bf2ffc
Added /metis/atlas/selection endpoint
Ibraam-Nashaat Jul 9, 2025
74f8bea
Added link/delay/alarms endpoint
Ibraam-Nashaat Jul 14, 2025
f1aede6
Merge remote-tracking branch 'upstream/main'
Ibraam-Nashaat Jul 14, 2025
33a6a4c
Removed link endpoints
Ibraam-Nashaat Jul 14, 2025
6b17dfe
Added /tr-hegemony endpoint
Ibraam-Nashaat Jul 14, 2025
3c56730
Added /disco/events endpoint
Ibraam-Nashaat Jul 14, 2025
a62fda6
Added /hegemony/alarms endpoints
Ibraam-Nashaat Jul 14, 2025
d7cff0f
Merge remote-tracking branch 'upstream/main'
Ibraam-Nashaat Jul 15, 2025
e8eb6b9
Merge branch 'hegemony-alarms-endpoint' of github.com:Ibraam-Nashaat/…
Ibraam-Nashaat Jul 15, 2025
b96500d
Added /hegemony/countries endpoint
Ibraam-Nashaat Jul 15, 2025
8905a2d
Added /hegemony endpoint
Ibraam-Nashaat Jul 15, 2025
5233743
Added /hegemony/prefixes endpoint
Ibraam-Nashaat Jul 15, 2025
2d04bbe
Merge remote-tracking branch 'upstream/main'
Ibraam-Nashaat Jul 16, 2025
65cdd04
Merge branch 'hegemony-prefix-endpoint' of github.com:Ibraam-Nashaat/…
Ibraam-Nashaat Jul 16, 2025
0554319
Merge remote-tracking branch 'upstream/main'
Ibraam-Nashaat Jul 23, 2025
51e7cc9
Merge remote-tracking branch 'upstream/main'
Ibraam-Nashaat Jul 25, 2025
b321230
Added page size ti .env file
Ibraam-Nashaat Jul 25, 2025
8eefb6a
Return recent results in all endpoints when timebin fields are not pr…
Ibraam-Nashaat Aug 6, 2025
d418b75
Updated readme
Ibraam-Nashaat Aug 6, 2025
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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,3 @@ Details how to manage database migrations using Alembic, including TimescaleDB-s
### 4. [Adding a New Endpoint](docs/add_new_endpoint.md)
A step-by-step guide on how to add a new endpoint to the application.


6 changes: 3 additions & 3 deletions controllers/metis_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from config.database import get_db
from typing import Optional
from utils import page_size
from utils import validate_timebin_params, prepare_timebin_range
from utils import validate_timebin_params

router = APIRouter(prefix="/metis/atlas", tags=["Metis"])

Expand Down Expand Up @@ -48,7 +48,7 @@ async def get_metis_atlas_deployments(
<li><b>Limitations:</b> At most 31 days of data can be fetched per request. For bulk downloads see: <a href="https://ihr-archive.iijlab.net/" target="_blank">https://ihr-archive.iijlab.net/</a>.</li>
</ul>
"""
timebin__gte, timebin__lte = prepare_timebin_range(
timebin__gte, timebin__lte = validate_timebin_params(
timebin, timebin__gte, timebin__lte, max_days=31)

deployments, total_count = MetisController.service.get_metis_atlas_deployments(
Expand Down Expand Up @@ -108,7 +108,7 @@ async def get_metis_atlas_selections(
<li><b>Limitations:</b> At most 31 days of data can be fetched per request. For bulk downloads see: <a href="https://ihr-archive.iijlab.net/" target="_blank">https://ihr-archive.iijlab.net/</a>.</li>
</ul>
"""
timebin__gte, timebin__lte = prepare_timebin_range(
timebin__gte, timebin__lte = validate_timebin_params(
timebin, timebin__gte, timebin__lte, max_days=31)

selections, total_count = MetisController.service.get_metis_atlas_selections(
Expand Down
4 changes: 2 additions & 2 deletions controllers/tr_hegemony_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from typing import Optional
from datetime import datetime
from utils import page_size
from utils import prepare_timebin_range
from utils import validate_timebin_params

router = APIRouter(prefix="/tr_hegemony", tags=["TR Hegemony"])

Expand Down Expand Up @@ -57,7 +57,7 @@ async def get_hegemony(
<li><b>Limitations:</b> At most 31 days of data can be fetched per request. For bulk downloads see: <a href="https://ihr-archive.iijlab.net/" target="_blank">https://ihr-archive.iijlab.net/</a>.</li>
</ul>
"""
timebin__gte, timebin__lte = prepare_timebin_range(
timebin__gte, timebin__lte = validate_timebin_params(
timebin, timebin__gte, timebin__lte, max_days=31)

hegemony_data, total_count = TRHegemonyController.service.get_tr_hegemony(
Expand Down
14 changes: 7 additions & 7 deletions docs/project_structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ This document provides an overview of the project's file and folder structure. E

```plaintext
.
├── alembic/ # Database migration scripts
├── config/ # App configuration
├── controllers/ # API endpoints and HTTP route handlers (Controller Layer)
├── alembic/ # [Alembic] Database migration scripts
├── config/ # [API] App configuration
├── controllers/ # [API] API endpoints and HTTP route handlers (Controller Layer)
├── docs/ # Documentation files
├── dtos/ # Data Transfer Objects for request/response schemas
├── models/ # Database models and ORM classes (Model Layer)
├── repositories/ # Data access logic and database interaction (Repository Layer)
├── services/ # Business logic layer (Service Layer)
├── dtos/ # [API] Data Transfer Objects for request/response schemas
├── models/ # [API & Alembic] Database models and ORM classes (Model Layer)
├── repositories/ # [API] Data access logic and database interaction (Repository Layer)
├── services/ # [API] Business logic layer (Service Layer)
├── .env # Environment variables (e.g., database credentials)
├── .gitignore # Specifies intentionally untracked files to ignore
├── alembic.ini # Alembic configuration file
Expand Down
7 changes: 7 additions & 0 deletions repositories/atlas_delay_alarms_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from datetime import datetime
from typing import List, Optional, Tuple
from utils import page_size
from sqlalchemy import func


class AtlasDelayAlarmsRepository:
Expand Down Expand Up @@ -38,6 +39,12 @@ def get_alarms(
.join(Startpoint, AtlasDelayAlarms.startpoint_relation)\
.join(Endpoint, AtlasDelayAlarms.endpoint_relation)


# If no time filters specified, get rows with max timebin
if not timebin and not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(AtlasDelayAlarms.timebin)).scalar()
query = query.filter(AtlasDelayAlarms.timebin == max_timebin)

if timebin:
query = query.filter(AtlasDelayAlarms.timebin == timebin)
if timebin_gte:
Expand Down
7 changes: 7 additions & 0 deletions repositories/atlas_delay_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from datetime import datetime
from typing import List, Optional, Tuple
from utils import page_size
from sqlalchemy import func


class AtlasDelayRepository:
Expand Down Expand Up @@ -41,6 +42,12 @@ def get_delays(
.join(Startpoint, AtlasDelay.startpoint_relation)\
.join(Endpoint, AtlasDelay.endpoint_relation)


# If no time filters specified, get rows with max timebin
if not timebin and not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(AtlasDelay.timebin)).scalar()
query = query.filter(AtlasDelay.timebin == max_timebin)

# Apply timebin filters
if timebin:
query = query.filter(AtlasDelay.timebin == timebin)
Expand Down
6 changes: 6 additions & 0 deletions repositories/hegemony_alarms_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from models.hegemony_alarms import HegemonyAlarms
from typing import Optional, List, Tuple
from utils import page_size
from sqlalchemy import func


class HegemonyAlarmsRepository:
Expand All @@ -21,6 +22,11 @@ def get_all(
) -> Tuple[List[HegemonyAlarms], int]:
query = db.query(HegemonyAlarms)

# If no time filters specified, get rows with max timebin
if not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(HegemonyAlarms.timebin)).scalar()
query = query.filter(HegemonyAlarms.timebin == max_timebin)

# Apply filters
if timebin_gte:
query = query.filter(HegemonyAlarms.timebin >= timebin_gte)
Expand Down
6 changes: 6 additions & 0 deletions repositories/hegemony_cone_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from models.hegemony_cone import HegemonyCone
from typing import Optional, List, Tuple
from utils import page_size
from sqlalchemy import func


class HegemonyConeRepository:
Expand All @@ -18,6 +19,11 @@ def get_all(
) -> Tuple[List[HegemonyCone], int]:
query = db.query(HegemonyCone)

# If no time filters specified, get rows with max timebin
if not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(HegemonyCone.timebin)).scalar()
query = query.filter(HegemonyCone.timebin == max_timebin)

# Apply filters
if timebin_gte:
query = query.filter(HegemonyCone.timebin >= timebin_gte)
Expand Down
6 changes: 6 additions & 0 deletions repositories/hegemony_country_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from models.hegemony_country import HegemonyCountry
from typing import Optional, List, Tuple
from utils import page_size
from sqlalchemy import func


class HegemonyCountryRepository:
Expand All @@ -24,6 +25,11 @@ def get_all(
) -> Tuple[List[HegemonyCountry], int]:
query = db.query(HegemonyCountry)

# If no time filters specified, get rows with max timebin
if not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(HegemonyCountry.timebin)).scalar()
query = query.filter(HegemonyCountry.timebin == max_timebin)

# Apply filters
if timebin_gte:
query = query.filter(HegemonyCountry.timebin >= timebin_gte)
Expand Down
6 changes: 6 additions & 0 deletions repositories/hegemony_prefix_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from models.hegemony_prefix import HegemonyPrefix
from typing import Optional, List, Tuple
from utils import page_size
from sqlalchemy import func


class HegemonyPrefixRepository:
Expand All @@ -29,6 +30,11 @@ def get_all(
) -> Tuple[List[HegemonyPrefix], int]:
query = db.query(HegemonyPrefix)

# If no time filters specified, get rows with max timebin
if not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(HegemonyPrefix.timebin)).scalar()
query = query.filter(HegemonyPrefix.timebin == max_timebin)

# Apply filters
if timebin_gte:
query = query.filter(HegemonyPrefix.timebin >= timebin_gte)
Expand Down
5 changes: 5 additions & 0 deletions repositories/hegemony_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from models.hegemony import Hegemony
from typing import Optional, List, Tuple
from utils import page_size
from sqlalchemy import func


class HegemonyRepository:
Expand All @@ -22,6 +23,10 @@ def get_all(
) -> Tuple[List[Hegemony], int]:
query = db.query(Hegemony)

# If no time filters specified, get rows with max timebin
if not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(Hegemony.timebin)).scalar()
query = query.filter(Hegemony.timebin == max_timebin)
# Apply filters
if timebin_gte:
query = query.filter(Hegemony.timebin >= timebin_gte)
Expand Down
6 changes: 6 additions & 0 deletions repositories/metis_atlas_deployment_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from models.metis_atlas_deployment import MetisAtlasDeployment
from typing import Optional, List, Tuple
from utils import page_size
from sqlalchemy import func


class MetisAtlasDeploymentRepository:
Expand All @@ -23,6 +24,11 @@ def get_all(
query = db.query(MetisAtlasDeployment).join(
MetisAtlasDeployment.asn_relation)

# If no time filters specified, get rows with max timebin
if not timebin and not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(MetisAtlasDeployment.timebin)).scalar()
query = query.filter(MetisAtlasDeployment.timebin == max_timebin)

# Apply filters
if timebin:
query = query.filter(MetisAtlasDeployment.timebin == timebin)
Expand Down
7 changes: 7 additions & 0 deletions repositories/metis_atlas_selection_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from models.metis_atlas_selection import MetisAtlasSelection
from typing import Optional, List, Tuple
from utils import page_size
from sqlalchemy import func


class MetisAtlasSelectionRepository:
Expand All @@ -23,6 +24,12 @@ def get_all(
query = db.query(MetisAtlasSelection).join(
MetisAtlasSelection.asn_relation)

# If no time filters specified, get rows with max timebin
if not timebin and not timebin_gte and not timebin_lte:
max_timebin = db.query(
func.max(MetisAtlasSelection.timebin)).scalar()
query = query.filter(MetisAtlasSelection.timebin == max_timebin)

# Apply filters
if timebin:
query = query.filter(MetisAtlasSelection.timebin == timebin)
Expand Down
6 changes: 6 additions & 0 deletions repositories/tr_hegemony_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from datetime import datetime
from typing import List, Optional, Tuple
from utils import page_size
from sqlalchemy import func


class TRHegemonyRepository:
Expand Down Expand Up @@ -35,6 +36,11 @@ def get_tr_hegemony(
.join(Origin, TRHegemony.origin_relation)\
.join(Dependency, TRHegemony.dependency_relation)

# If no time filters specified, get rows with max timebin
if not timebin and not timebin_gte and not timebin_lte:
max_timebin = db.query(func.max(TRHegemony.timebin)).scalar()
query = query.filter(TRHegemony.timebin == max_timebin)

if timebin:
query = query.filter(TRHegemony.timebin == timebin)
if timebin_gte:
Expand Down
42 changes: 3 additions & 39 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,15 @@

page_size = int(os.getenv("PAGE_SIZE"))


def validate_timebin_params(
timebin: Optional[datetime],
timebin_gte: Optional[datetime],
timebin_lte: Optional[datetime],
max_days: int = 7
) -> tuple[datetime, datetime]:

# Check if at least one time parameter exists
if not any([timebin, timebin_gte, timebin_lte]):
raise HTTPException(
status_code=400,
detail="No timebin parameter. Please provide a timebin value or a range of values with timebin__lte and timebin__gte."
)

# If timebin is not provided, both timebin_gte and timebin_lte must be provided
if not timebin and not (timebin_gte and timebin_lte):
if (not timebin_gte and timebin_lte) or (timebin_gte and not timebin_lte):
raise HTTPException(
status_code=400,
detail="Invalid timebin range. Please provide both timebin__lte and timebin__gte."
Expand All @@ -49,33 +42,4 @@ def validate_timebin_params(
detail=f"The given timebin range is too large. Should be less than {max_days} days."
)

return timebin_gte, timebin_lte


def prepare_timebin_range(
timebin: Optional[datetime],
timebin_gte: Optional[datetime],
timebin_lte: Optional[datetime],
max_days: int = 7
) -> Tuple[datetime, Optional[datetime]]:

if (not timebin_gte and timebin_lte) or (timebin_gte and not timebin_lte):
raise HTTPException(
status_code=400,
detail="Invalid timebin range. Please provide both timebin__lte and timebin__gte."
)
# If no time filters provided, default to last 6 days (including today)
if not any([timebin, timebin_gte, timebin_lte]):
today = datetime.combine(date.today(), datetime.min.time())
timebin_gte = today - timedelta(days=6)

# Validate range size if both are given
if timebin_gte and timebin_lte:
delta = timebin_lte - timebin_gte
if delta > timedelta(days=max_days):
raise HTTPException(
status_code=400,
detail=f"The given timebin range is too large. Should be less than {max_days} days."
)

return timebin_gte, timebin_lte
return timebin_gte, timebin_lte