Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d71e1d0
feat(notifications): add alert subscription api
sudip-khanal Nov 29, 2025
c2f60f3
chore(app): base setup for alert system app
sandeshit Nov 12, 2025
2dcdd6d
feat(polling): extraction logic for polling
sandeshit Nov 12, 2025
a6011ac
chore(sentry): add cron monitor for tracking
sandeshit Nov 12, 2025
1813a7c
feat(commands): management commands to run different polling tasks
sandeshit Nov 12, 2025
6185bee
refactor(extraction): refactor extraction logic for hazards and impacts.
sandeshit Nov 17, 2025
b469ece
feat(extraction): use different classes for different sources
sandeshit Nov 23, 2025
aa10976
feat(filter): add filtration classes and cronjob
sandeshit Nov 23, 2025
77560f3
feat(etl): refactor existing extraction into ETL.
sandeshit Nov 28, 2025
d839541
feat(etl): add past events fetcher
sandeshit Dec 7, 2025
c8a8e1d
chore(alert-system): clean up naming and cronjobs
sandeshit Dec 7, 2025
0746f17
feat(etl): add past events from GO event table
sandeshit Dec 19, 2025
dcae4c6
feat(etl): add usgs source
sandeshit Dec 19, 2025
fcc9bdd
chore(etl): separate past event extraction into different class
sandeshit Dec 23, 2025
356e806
fixup! chore(etl): separate past event extraction into different class
sandeshit Jan 5, 2026
ad0aa8c
feat(etl): change transform logic.
sandeshit Jan 9, 2026
843503b
feat(alert-system): Add email alert setup
sudip-khanal Jan 4, 2026
9457eb6
chore(assets): Update assets commit reference
sudip-khanal Jan 4, 2026
73f95f4
feat(alert-system): feat(alert-system): update alert email task and f…
sudip-khanal Jan 6, 2026
4d884a8
chore(alert-system): Update duplicate reply tests for multi-user subs…
sudip-khanal Jan 9, 2026
c1f4a3b
chore(alert-system): fix migrations
sudip-khanal Jan 9, 2026
903cbfd
fixup! feat(alert-system): feat(alert-system): update alert email tas…
sudip-khanal Jan 9, 2026
256bc5a
fixup! chore(alert-system): Update duplicate reply tests for multi-us…
sudip-khanal Jan 16, 2026
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
Empty file added alert_system/__init__.py
Empty file.
94 changes: 94 additions & 0 deletions alert_system/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from django.contrib import admin

from .models import AlertEmailLog, AlertEmailThread, Connector, ExtractionItem, LoadItem


@admin.register(Connector)
class ConnectorAdmin(admin.ModelAdmin):
list_display = ("id", "type", "last_success_run", "status")
readonly_fields = ("last_success_run",)


@admin.register(ExtractionItem)
class EventAdmin(admin.ModelAdmin):
list_display = (
"stac_id",
"created_at",
"collection",
"correlation_id",
)
list_filter = ("connector", "collection")
readonly_fields = ("connector",)
search_fields = (
"stac_id",
"correlation_id",
)


@admin.register(LoadItem)
class LoadItemAdmin(admin.ModelAdmin):
list_display = (
"id",
"event_title",
"created_at",
"correlation_id",
"item_eligible",
"is_past_event",
)
list_filter = (
"connector",
"item_eligible",
"is_past_event",
)
readonly_fields = (
"connector",
"item_eligible",
"related_montandon_events",
"related_go_events",
)
search_fields = (
"id",
"correlation_id",
)


@admin.register(AlertEmailThread)
class AlertEmailThreadAdmin(admin.ModelAdmin):
list_display = (
"user",
"correlation_id",
"root_email_message_id",
)
search_fields = (
"correlation_id",
"root_email_message_id",
"user__username",
)
list_select_related = ("user",)
autocomplete_fields = ("user",)


@admin.register(AlertEmailLog)
class AlertEmailLogAdmin(admin.ModelAdmin):
list_display = (
"id",
"message_id",
"status",
)
list_select_related = (
"user",
"subscription",
"item",
"thread",
)
search_fields = (
"user__username",
"message_id",
)
autocomplete_fields = (
"user",
"subscription",
"item",
"thread",
)
list_filter = ("status",)
6 changes: 6 additions & 0 deletions alert_system/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class AlertSystemConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "alert_system"
75 changes: 75 additions & 0 deletions alert_system/dev_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from django.http import HttpResponse
from django.template import loader
from rest_framework import permissions
from rest_framework.views import APIView


class AlertEmailPreview(APIView):
permission_classes = [permissions.IsAuthenticated]

def get(self, request):
type_param = request.GET.get("type")

template_map = {
"alert": "email/alert_system/alert_notification.html",
"alert_reply": "email/alert_system/alert_notification_reply.html",
}

if type_param not in template_map:
valid_values = ", ".join(template_map.keys())
return HttpResponse(
f"Invalid 'type' parameter. Please use one of the following values: {valid_values}.",
)
context_map = {
"alert": {
"user_name": "Test User",
"event_title": "Test Title",
"event_description": "This is a test description for the alert email.",
"start_datetime": "2025-11-28 01:00:00",
"end_datetime": "2025-11-28 01:00:00",
"country_name": [
"Nepal",
],
"total_people_exposed": 1200,
"total_buildings_exposed": 150,
"hazard_types": "Flood",
"related_montandon_events": [
{
"event_title": "Related Event 1",
"total_people_exposed": 100,
"total_buildings_exposed": 300,
"start_datetime": "2025-11-28 01:00:00",
"end_datetime": "2025-11-28 01:00:00",
},
{
"event_title": "Related Event 2",
"total_people_exposed": 200,
"total_buildings_exposed": 500,
"start_datetime": "2025-11-28 01:00:00",
"end_datetime": "2025-11-28 01:00:00",
},
],
"related_go_events": [
"go-event-uuid-1",
"go-event-uuid-2",
],
},
"alert_reply": {
"event_title": "Test Title",
"event_description": "This is a test description for the alert email.",
"start_datetime": "2025-11-28 01:00:00",
"end_datetime": "2025-11-28 01:00:00",
"country_name": [
"Nepal",
],
"total_people_exposed": 1200,
"total_buildings_exposed": 150,
},
}

context = context_map.get(type_param)
if context is None:
return HttpResponse("No context found for the email preview.")
template_file = template_map[type_param]
template = loader.get_template(template_file)
return HttpResponse(template.render(context, request))
13 changes: 13 additions & 0 deletions alert_system/etl/base/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import Dict, TypedDict


class ExtractionConfig(TypedDict):
event_collection_type: str
hazard_collection_type: str | None
impact_collection_type: str | None

filter_event: Dict | None
filter_hazard: Dict | None
filter_impact: Dict | None

people_exposed_threshold: int
Loading
Loading