File size: 4,125 Bytes
3493993
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from __future__ import annotations

from datetime import datetime
from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field

MetricName = Literal[
    "views",
    "impressions",
    "likes",
    "comments",
    "shares",
    "engagement_rate",
    "reach",
    "clicks",
    "saves",
    "watch_time",
    "completion_rate",
]
Granularity = Literal["day", "week", "month"]


class AnalyticsQuery(BaseModel):
    model_config = ConfigDict(extra="forbid")

    date_from: datetime | None = None
    date_to: datetime | None = None
    timezone: str = Field(default="UTC", min_length=1, max_length=100)
    provider: str | None = Field(default=None, max_length=32)
    project_id: str | None = Field(default=None, max_length=36)
    social_account_id: str | None = Field(default=None, max_length=36)
    post_id: str | None = Field(default=None, max_length=36)
    metric: MetricName | None = None
    granularity: Granularity = "day"
    search: str | None = Field(default=None, max_length=200)
    sort: Literal["date", "views", "engagement_rate", "likes", "comments", "shares"] = "date"
    descending: bool = True
    offset: int = Field(default=0, ge=0, le=100_000)
    limit: int = Field(default=50, ge=1, le=500)


class AnalyticsMetric(BaseModel):
    model_config = ConfigDict(extra="forbid")

    provider: str
    post_id: str | None = None
    project_id: str | None = None
    metric_date: datetime
    views: int | None = None
    impressions: int | None = None
    likes: int | None = None
    comments: int | None = None
    shares: int | None = None
    engagement_rate: float | None = None
    status: Literal["available", "unavailable", "unsupported", "not_synchronized"] = "available"
    source: str = "provider"
    collected_at: datetime | None = None


class AnalyticsFreshness(BaseModel):
    status: Literal["fresh", "stale", "not_synchronized", "partial", "failed"]
    last_collected_at: datetime | None = None
    last_sync_id: str | None = None
    reason: str | None = None


class AnalyticsOverview(BaseModel):
    model_config = ConfigDict(extra="forbid")

    date_from: datetime
    date_to: datetime
    timezone: str
    timezone_source: Literal["requested", "utc_fallback"] = "requested"
    totals: dict[str, int | float | None]
    platforms: list[dict[str, Any]]
    top_posts: list[AnalyticsMetric]
    freshness: AnalyticsFreshness


class AnalyticsTimeseries(BaseModel):
    date_from: datetime
    date_to: datetime
    timezone: str
    granularity: Granularity
    metric: str
    points: list[dict[str, Any]]
    freshness: AnalyticsFreshness


class AnalyticsSyncRequest(BaseModel):
    model_config = ConfigDict(extra="forbid")

    date_from: datetime | None = None
    date_to: datetime | None = None
    timezone: str = Field(default="UTC", min_length=1, max_length=100)
    provider: str | None = Field(default=None, max_length=32)
    project_id: str | None = Field(default=None, max_length=36)
    idempotency_key: str | None = Field(default=None, min_length=8, max_length=255)


class AnalyticsSyncRunView(BaseModel):
    model_config = ConfigDict(from_attributes=True, extra="forbid")

    id: str
    status: Literal["queued", "running", "succeeded", "partial", "failed", "cancelled"]
    provider: str | None = None
    project_id: str | None = None
    date_from: datetime
    date_to: datetime
    timezone: str
    attempt_count: int
    metrics_count: int
    error_code: str | None = None
    error_message: str | None = None
    created_at: datetime
    started_at: datetime | None = None
    completed_at: datetime | None = None
    updated_at: datetime


class AnalyticsCapabilities(BaseModel):
    provider: str
    implementation_status: str
    status: Literal["available", "unsupported", "unavailable"]
    metrics: list[str]
    required_scopes: list[str] = Field(default_factory=list)


class AnalyticsSyncList(BaseModel):
    items: list[AnalyticsSyncRunView]
    offset: int
    limit: int


class AnalyticsPostList(BaseModel):
    items: list[AnalyticsMetric]
    offset: int
    limit: int
    freshness: AnalyticsFreshness