Repository: keephq/keep
Pull request: feat: API endpoint to see how many alerts a provider has sent
- add service function in api/core/db.py
- add endpoint in api/routes/providers.py

<!-- 
Thanks for creating this pull request 🤗

Please make sure that the pull request is limited to one type (docs, feature, etc.) and keep it as small as possible. You can open multiple prs instead of opening a huge one.
-->

<!-- If this pull request closes an issue, please mention the issue number below -->
Closes #1249 
/claim #1249

## 📑 Description
<!-- Add a brief description of the pr -->

<!-- You can also choose to add a list of changes and if they have been completed or not by using the markdown to-do list syntax
- [ ] Not Completed
- [x] Completed
-->

## ✅ Checks
<!-- Make sure your pr passes the CI checks and do check the following fields as needed - -->
- [ ] My pull request adheres to the code style of this project
- [ ] My code requires changes to the documentation
- [ ] I have updated the documentation as required
- [ ] All the tests have passed

## ℹ Additional Information
<!-- Any additional information like breaking changes, dependencies added, screenshots, comparisons between new and old behavior, etc. -->


Problem statement:
[➕ Feature] API endpoint to see how many alerts a provider has sent
This endpoint could be then used to monitor the "health" of some provider or just expose some BI of trends.

**Describe your use case**
An API endpoint that exposes the number of alerts a specific provider has received (in a specific time time period or ever)

**Are you already using Keep?**
**Yes**/No

**Additional context**
-


[🐛 Bug]: Poor performance of the single incidents page with large amount of alerts
**Describe the bug**
The single Incident page is loaded slowly when it has many alerts

**To Reproduce**
Steps to reproduce the behavior:

1. Create an incident
2. Assign 5-10k alerts to it
3. Go to the Incidents list page
4. Go to the single incident page

**Expected behavior**
The incident page should be loaded fast

Hints from issue discussion:
@talboren maybe worth making it a prometheus-formatted metrics exporter endpoint?
/bounty 30
/attempt #1249

<div id="algora-attempt" />

| [Algora profile](https://console.algora.io/@/35C4n0r) | Completed bounties | Tech | Active attempts | Options |
| --- | --- | --- | --- | --- |
| @35C4n0r | &nbsp;&nbsp;&nbsp;11 keephq bounties <br/> + 10 bounties from 4 projects | <div align="center">Python, HTML, <br />JavaScript & more</div> | <div align="center">﹟1259</div> | [Cancel attempt](https://console.algora.io/api/bounties/clxsqgd7y0004mh09f4rk338y/cancel-attempt) |
/attempt
/attempt #1249


<div id="algora-attempt" />

<details>
  <summary>Options</summary>
  <ul>
    <li>
      <a href="https://console.algora.io/api/bounties/clxsqgd7y0004mh09f4rk338y/cancel-attempt">
        Cancel my attempt
      </a>
    </li>
  </ul>
</details>
/attempt #1249  
would like to give it a shot, if no one is attempting this one. @Matvey-Kuk 

<div id="algora-attempt" />

<details>
  <summary>Options</summary>
  <ul>
    <li>
      <a href="https://console.algora.io/api/bounties/clxsqgd7y0004mh09f4rk338y/cancel-attempt">
        Cancel my attempt
      </a>
    </li>
  </ul>
</details>
@kumarvikramshahi youre good to go
Here are some steps and pointers to help you get started with implementing the API endpoint to see how many alerts a provider has sent:

### Steps to Implement the Feature

1. **Define the Endpoint:**
   - Create a new endpoint, for example, `GET /providers/{provider_type}/{provider_id}/alerts/count`.
   - This endpoint should accept query parameters for filtering by time period (e.g., `start_date` and `end_date`).

2. **Update OpenAPI Documentation:**
   - Add the new endpoint to the OpenAPI documentation. You can refer to the existing documentation files for similar endpoints:
     - `/docs/api-ref/providers/get-alerts-configuration.mdx`
     - `/docs/api-ref/providers/add-alert.mdx`

3. **Backend Logic:**
   - Implement the logic to count the alerts for a specific provider. You can refer to the existing alert-related endpoints for guidance:
     - `/docs/api-ref/alerts/get-all-alerts.mdx`
     - `/docs/api-ref/alerts/search-alerts.mdx`
   - Ensure that the counting logic can handle filtering by time period if provided.

4. **Database Query:**
   - Write a database query to count the alerts for the specified provider. Make sure to include any necessary joins or filters to accurately count the alerts.

### Relevant Files and Directories

- **API Documentation:**
  - `/docs/api-ref/providers/get-alerts-configuration.mdx`
  - `/docs/api-ref/providers/add-alert.mdx`
  - `/docs/api-ref/alerts/get-all-alerts.mdx`
  - `/docs/api-ref/alerts/search-alerts.mdx`

- **Alerts Overview:**
  - `/docs/platform/alerts.mdx`

### Potential Implications

- **Security:**
  - Ensure that the endpoint is secured and only accessible to authorized users.
  - Validate the input parameters to prevent SQL injection or other malicious inputs.

- **Stability:**
  - Test the endpoint thoroughly to ensure it handles large datasets efficiently.
  - Consider implementing pagination or rate limiting if the number of alerts is very large.

- **Potential Bugs:**
  - Verify that the counting logic correctly handles edge cases, such as overlapping time periods or missing data.
  - Ensure that the endpoint returns accurate counts even when alerts are being added or removed concurrently.

### Reference Similar Code

- Look at the implementation of the existing alert endpoints to understand the structure and logic used:
  - `/docs/api-ref/alerts/get-all-alerts.mdx`
  - `/docs/api-ref/alerts/search-alerts.mdx`
I don't see any progress on this, I'll raise a PR for this
/attempt #1249

Commit message: feat: add api endpoint to count alerts recieved by a provider

- add service function in api/core/db.py
- add endpoint in api/routes/providers.py

Signed-off-by: 35C4n0r <jaykumar20march@gmail.com>

Patch to review:
diff --git a/keep/api/core/db.py b/keep/api/core/db.py
index aabb21562b..204a11e047 100644
--- a/keep/api/core/db.py
+++ b/keep/api/core/db.py
@@ -733,6 +733,39 @@ def enrich_alert(
     )
 
 
+def count_alerts(
+    ever: bool,
+    start_time: Optional[datetime],
+    end_time: Optional[datetime],
+    provider_id: str,
+    provider_type: str,
+    tenant_id: str,
+):
+    with Session(engine) as session:
+        if ever:
+            return (
+                session.query(Alert)
+                .filter(
+                    Alert.tenant_id == tenant_id,
+                    Alert.provider_id == provider_id,
+                    Alert.provider_type == provider_type,
+                )
+                .count()
+            )
+        else:
+            return (
+                session.query(Alert)
+                .filter(
+                    Alert.tenant_id == tenant_id,
+                    Alert.provider_id == provider_id,
+                    Alert.provider_type == provider_type,
+                    Alert.timestamp >= start_time,
+                    Alert.timestamp <= end_time,
+                )
+                .count()
+            )
+
+
 def get_enrichment(tenant_id, fingerprint):
     with Session(engine) as session:
         alert_enrichment = session.exec(
diff --git a/keep/api/routes/providers.py b/keep/api/routes/providers.py
index f2a26f83a4..4981c4d054 100644
--- a/keep/api/routes/providers.py
+++ b/keep/api/routes/providers.py
@@ -13,7 +13,7 @@
 from starlette.datastructures import UploadFile
 
 from keep.api.core.config import config
-from keep.api.core.db import get_provider_distribution, get_session
+from keep.api.core.db import get_provider_distribution, get_session, count_alerts
 from keep.api.core.dependencies import AuthenticatedEntity, AuthVerifier
 from keep.api.models.db.provider import Provider
 from keep.api.models.webhook import ProviderWebhookSettings
@@ -229,6 +229,35 @@ def get_alerts_schema(
         raise HTTPException(404, detail=f"Provider {provider_type} not found")
 
 
+@router.get("/{provider_type}/{provider_id}/alerts/count")
+def get_alert_count(
+    provider_type: str,
+    provider_id: str,
+    ever: bool,
+    start_time: Optional[datetime.datetime] = None,
+    end_time: Optional[datetime.datetime] = None,
+    authenticated_entity: AuthenticatedEntity = Depends(AuthVerifier(["read:alert"])),
+):
+    tenant_id = authenticated_entity.tenant_id
+    if ever is False and (start_time is None or end_time is None):
+        return JSONResponse(
+            status_code=400, content={"message": "Missing start_time or end_time"}
+        )
+    return JSONResponse(
+        status_code=200,
+        content={
+            "alert_count": count_alerts(
+                provider_type=provider_type,
+                provider_id=provider_id,
+                start_time=start_time,
+                end_time=end_time,
+                ever=ever,
+                tenant_id=tenant_id,
+            )
+        },
+    )
+
+
 @router.post(
     "/{provider_type}/{provider_id}/alerts",
     description="Push new alerts to the provider",


Code review comments:
diff_hunk: @@ -229,6 +229,35 @@ def get_alerts_schema(
         raise HTTPException(404, detail=f"Provider {provider_type} not found")
 
 
+@router.get("/{provider_type}/{provider_id}/alerts/count")
+def get_alert_count(
+    provider_type: str,
+    provider_id: str,
+    ever: bool,
+    start_time: Optional[datetime.datetime] = None,
+    end_time: Optional[datetime.datetime] = None,
+    authenticated_entity: AuthenticatedEntity = Depends(AuthVerifier(["read:alert"])),
+):
+    tenant_id = authenticated_entity.tenant_id
+    if ever is False and (start_time is None or end_time is None):
+        return JSONResponse(
+            status_code=400, content={"message": "Missing start_time or end_time"}
+        )
+    return JSONResponse(
+        status_code=200,
+        content={
+            "alert_count": count_alerts(
+                provider_type=provider_type,
+                provider_id=provider_id,
+                start_time=start_time,
+                end_time=end_time,
+                ever=ever,
+                tenant_id=tenant_id,
+            )
path: keep/api/routes/providers.py
text: @user1:
lets define a model for it

@user1:
(e.g., ProviderAlertsCountDto)