mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-08 07:42:47 +03:00
Add the analytics preview API
This commit is contained in:
Vendored
+19
@@ -10,6 +10,25 @@ servers:
|
|||||||
- url: https://demo.frigate.video/api
|
- url: https://demo.frigate.video/api
|
||||||
- url: http://localhost:5001/api
|
- url: http://localhost:5001/api
|
||||||
paths:
|
paths:
|
||||||
|
/analytics/preview:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Analytics
|
||||||
|
summary: Get Analytics Preview
|
||||||
|
description: |-
|
||||||
|
**Access:** Admin role required.
|
||||||
|
|
||||||
|
Get the analytics report Frigate would send next, without sending it.
|
||||||
|
operationId: get_analytics_preview_analytics_preview_get
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Successful Response
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: {}
|
||||||
|
security:
|
||||||
|
- frigateAdminAuth: []
|
||||||
|
x-required-role: admin
|
||||||
/auth/first_time_login:
|
/auth/first_time_login:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
"""Analytics APIs."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, Request
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from frigate.analytics.report import preview_report
|
||||||
|
from frigate.api.auth import require_role
|
||||||
|
from frigate.api.defs.tags import Tags
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
router = APIRouter(tags=[Tags.analytics])
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/analytics/preview", dependencies=[Depends(require_role(["admin"]))])
|
||||||
|
def get_analytics_preview(request: Request) -> JSONResponse:
|
||||||
|
"""Get the analytics report Frigate would send next, without sending it."""
|
||||||
|
report = preview_report(
|
||||||
|
request.app.frigate_config,
|
||||||
|
request.app.stats_emitter,
|
||||||
|
request.app.notice_registry,
|
||||||
|
)
|
||||||
|
return JSONResponse(content=report.model_dump(mode="json"))
|
||||||
@@ -2,6 +2,7 @@ from enum import Enum
|
|||||||
|
|
||||||
|
|
||||||
class Tags(Enum):
|
class Tags(Enum):
|
||||||
|
analytics = "Analytics"
|
||||||
app = "App"
|
app = "App"
|
||||||
auth = "Auth"
|
auth = "Auth"
|
||||||
camera = "Camera"
|
camera = "Camera"
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ from slowapi.middleware import SlowAPIMiddleware
|
|||||||
from starlette_context import middleware, plugins
|
from starlette_context import middleware, plugins
|
||||||
from starlette_context.plugins import Plugin
|
from starlette_context.plugins import Plugin
|
||||||
|
|
||||||
from frigate.api import app as main_app
|
|
||||||
from frigate.api import (
|
from frigate.api import (
|
||||||
|
analytics,
|
||||||
auth,
|
auth,
|
||||||
camera,
|
camera,
|
||||||
chat,
|
chat,
|
||||||
@@ -30,6 +30,7 @@ from frigate.api import (
|
|||||||
record,
|
record,
|
||||||
review,
|
review,
|
||||||
)
|
)
|
||||||
|
from frigate.api import app as main_app
|
||||||
from frigate.api.auth import get_jwt_secret, limiter, require_admin_by_default
|
from frigate.api.auth import get_jwt_secret, limiter, require_admin_by_default
|
||||||
from frigate.comms.dispatcher import Dispatcher
|
from frigate.comms.dispatcher import Dispatcher
|
||||||
from frigate.comms.event_metadata_updater import (
|
from frigate.comms.event_metadata_updater import (
|
||||||
@@ -140,6 +141,7 @@ def create_fastapi_app(
|
|||||||
|
|
||||||
# Routes
|
# Routes
|
||||||
# Order of include_router matters: https://fastapi.tiangolo.com/tutorial/path-params/#order-matters
|
# Order of include_router matters: https://fastapi.tiangolo.com/tutorial/path-params/#order-matters
|
||||||
|
app.include_router(analytics.router)
|
||||||
app.include_router(auth.router)
|
app.include_router(auth.router)
|
||||||
app.include_router(camera.router)
|
app.include_router(camera.router)
|
||||||
app.include_router(chat.router)
|
app.include_router(chat.router)
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
"""Tests for the analytics preview API."""
|
||||||
|
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
from frigate.analytics import report
|
||||||
|
from frigate.analytics.collectors import hardware
|
||||||
|
from frigate.models import Notice, NoticeStats, User
|
||||||
|
from frigate.notices.registry import NoticeRegistry
|
||||||
|
from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp
|
||||||
|
|
||||||
|
|
||||||
|
class TestHttpAnalytics(BaseTestHttp):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp([Notice, NoticeStats, User])
|
||||||
|
stats = Mock()
|
||||||
|
stats.get_latest_stats.return_value = self.test_stats
|
||||||
|
self.app = self.create_app(stats=stats, notice_registry=NoticeRegistry())
|
||||||
|
|
||||||
|
for target, name, value in (
|
||||||
|
(report, "load_state", None),
|
||||||
|
(hardware.hardware_prober, "probe", []),
|
||||||
|
(hardware, "hwaccel_options", ("", [])),
|
||||||
|
):
|
||||||
|
patcher = patch.object(target, name, return_value=value)
|
||||||
|
patcher.start()
|
||||||
|
self.addCleanup(patcher.stop)
|
||||||
|
|
||||||
|
def test_preview_returns_the_report_without_sending_it(self):
|
||||||
|
with (
|
||||||
|
patch("frigate.analytics.transport.requests.post") as post,
|
||||||
|
AuthTestClient(self.app) as client,
|
||||||
|
):
|
||||||
|
response = client.get("/analytics/preview")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
body = response.json()
|
||||||
|
self.assertEqual(body["install_id"], report.PREVIEW_INSTALL_ID)
|
||||||
|
self.assertEqual(body["schema_version"], 1)
|
||||||
|
self.assertEqual(body["cameras"]["total"], 1)
|
||||||
|
post.assert_not_called()
|
||||||
|
|
||||||
|
def test_preview_is_admin_only(self):
|
||||||
|
with AuthTestClient(self.app) as client:
|
||||||
|
response = client.get(
|
||||||
|
"/analytics/preview",
|
||||||
|
headers={"remote-user": "viewer", "remote-role": "viewer"},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
@@ -47,8 +47,8 @@ from fastapi.routing import APIRoute
|
|||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
from ruamel.yaml.scalarstring import LiteralScalarString
|
from ruamel.yaml.scalarstring import LiteralScalarString
|
||||||
|
|
||||||
from frigate.api import app as main_app
|
|
||||||
from frigate.api import (
|
from frigate.api import (
|
||||||
|
analytics,
|
||||||
auth,
|
auth,
|
||||||
camera,
|
camera,
|
||||||
chat,
|
chat,
|
||||||
@@ -65,6 +65,7 @@ from frigate.api import (
|
|||||||
record,
|
record,
|
||||||
review,
|
review,
|
||||||
)
|
)
|
||||||
|
from frigate.api import app as main_app
|
||||||
from frigate.api.auth import require_admin_by_default
|
from frigate.api.auth import require_admin_by_default
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||||
@@ -145,6 +146,7 @@ def build_app() -> FastAPI:
|
|||||||
"""
|
"""
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
routers = [
|
routers = [
|
||||||
|
analytics.router,
|
||||||
auth.router,
|
auth.router,
|
||||||
camera.router,
|
camera.router,
|
||||||
chat.router,
|
chat.router,
|
||||||
|
|||||||
Reference in New Issue
Block a user