Skip to content

Commit 6caac10

Browse files
Merge pull request #20 from divar-ir/addon-v2
[Addons] feat: widgets and addons v2
2 parents ecdf0dc + 73f6bb0 commit 6caac10

20 files changed

+160
-225
lines changed

kenar/addon.py

+22-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from enum import Enum
2+
from logging import log
23
from typing import List, Optional, Dict
34

45
from pydantic import BaseModel, model_serializer, field_serializer, field_validator
@@ -17,7 +18,7 @@ class CreatePostAddonRequest(BaseModel):
1718

1819
@field_serializer("widgets")
1920
def serialize_widgets(self, widgets, _info):
20-
return {"widget_list": [w.serialize_model() for w in widgets]}
21+
return [w.serialize_model() for w in widgets]
2122

2223

2324
class CreatePostAddonResponse(BaseModel):
@@ -47,7 +48,7 @@ class App(BaseModel):
4748
display: str = None
4849
avatar: str = None
4950
status: Status = None
50-
service_type: str
51+
service_type: str = None
5152

5253

5354
class AddonMetaData(BaseModel):
@@ -64,27 +65,16 @@ class PostAddon(BaseModel):
6465

6566
token: str
6667

67-
widgets: List[WidgetTypesUnion] = None
68-
6968
score: int
7069

7170
semantic: Dict[str, str] = None
7271
semantic_sensitives: List[str] = None
7372

74-
@field_validator("widgets", mode="before")
75-
@classmethod
76-
def deserialize_model(cls, widgets: Dict):
77-
widget_list = widgets.get("widget_list", [])
78-
return [
79-
get_widget_class(w["widget_type"]).deserialize_model(w) for w in widget_list
80-
]
73+
class Config:
74+
exclude= {"semantic_sensitives"}
8175

82-
@field_serializer("widgets")
83-
def serialize_widgets(self, widgets, _info):
84-
if widgets:
85-
p = [w.serialize_model() for w in widgets]
86-
return {"widget_list": p}
87-
return None
76+
77+
8878

8979

9080
class GetPostAddonsRequest(BaseModel):
@@ -121,11 +111,23 @@ class CreateUserAddonRequest(BaseModel):
121111
categories: List[str]
122112
ticket_uuid: Optional[str] = None
123113
verification_cost: Optional[int] = None
114+
cost: Optional[int] = None
115+
116+
@field_validator("cost", mode="before")
117+
@classmethod
118+
def set_cost_from_verification(cls, cost: Optional[int], values):
119+
if cost is None and values.get("verification_cost") is not None:
120+
return values.get("verification_cost")
121+
return cost
122+
123+
class Config:
124+
exclude = {"verification_cost", "management_permalink",
125+
"notes", "removal_permalink", "semantic_sensitives"}
124126

125127
@field_serializer("widgets")
126128
def serialize_widgets(self, widgets, _info):
127129
p = [w.serialize_model() for w in widgets]
128-
return {"widget_list": p}
130+
return p
129131

130132

131133
class CreateUserAddonResponse(BaseModel):
@@ -160,16 +162,15 @@ class UserAddon(BaseModel):
160162
@field_validator("widgets", mode="before")
161163
@classmethod
162164
def deserialize_model(cls, widgets: Dict):
163-
widget_list = widgets.get("widget_list", [])
164165
return [
165-
get_widget_class(w["widget_type"]).deserialize_model(w) for w in widget_list
166+
get_widget_class(w.keys()).deserialize_model(w) for w in widgets
166167
]
167168

168169
@field_serializer("widgets")
169170
def serialize_widgets(self, widgets, _info):
170171
if widgets:
171172
p = [w.serialize_model() for w in widgets]
172-
return {"widget_list": p}
173+
return p
173174
return None
174175

175176

kenar/app.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ def create_user_addon(
188188
@retry(max_retries=max_retry, delay=retry_delay)
189189
def send_request():
190190
return self._client.post(
191-
url=f"/v1/open-platform/addons/user/{data.phone}",
192-
content=data.json(),
191+
url=f"/v2/open-platform/addons/user/{data.phone}",
192+
content=data.model_dump_json(),
193193
headers={ACCESS_TOKEN_HEADER_NAME: access_token},
194194
)
195195

@@ -222,7 +222,7 @@ def get_user_addons(
222222
def send_request():
223223
return self._client.get(
224224
url=f"/v1/open-platform/addons/user/{data.phone}",
225-
params=data.json(),
225+
params=data.model_dump_json(),
226226
)
227227

228228
rsp = send_request()
@@ -238,8 +238,8 @@ def create_post_addon(
238238
@retry(max_retries=max_retry, delay=retry_delay)
239239
def send_request():
240240
return self._client.post(
241-
url=f"/v1/open-platform/addons/post/{data.token}",
242-
content=data.json(),
241+
url=f"/v2/open-platform/addons/post/{data.token}",
242+
content=data.model_dump_json(exclude={"token"}),
243243
headers={ACCESS_TOKEN_HEADER_NAME: access_token},
244244
)
245245

kenar/widgets/__init__.py

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from .event_row import EventRow
55
from .group_info_row import GroupInfo
66
from .image_carousel_row import ImageCarouselRow
7-
from .legend_title_row import LegendTitleRow
87
from .score_row import ScoreRow
98
from .selector_row import SelectorRow
109
from .subtitle_row import SubtitleRow

kenar/widgets/action.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ def get_action(link: str) -> Dict:
55
return (
66
{
77
"action": {
8-
"type": "LOAD_WEB_VIEW_PAGE",
9-
"fallback_link": link,
10-
"payload": {
11-
"@type": "type.googleapis.com/widgets.LoadWebViewPagePayload",
12-
"url": link,
13-
},
8+
"open_direct_link": link,
149
}
1510
}
1611
if len(link) > 0
@@ -19,4 +14,4 @@ def get_action(link: str) -> Dict:
1914

2015

2116
def get_link_from_action(action: Dict) -> str:
22-
return action["payload"]["url"]
17+
return action.get("open_direct_link", "")

kenar/widgets/color.py

+1-9
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,9 @@
22

33

44
class Color(Enum):
5+
COLOR_UNSPECIFIED = "COLOR_UNSPECIFIED"
56
SUCCESS_PRIMARY = "SUCCESS_PRIMARY"
67
SUCCESS_SECONDARY = "SUCCESS_SECONDARY"
78
WARNING_PRIMARY = "WARNING_PRIMARY"
89
WARNING_SECONDARY = "WARNING_SECONDARY"
910
ERROR_PRIMARY = "ERROR_PRIMARY"
10-
TEXT_PRIMARY = "TEXT_PRIMARY"
11-
TEXT_SECONDARY = "TEXT_SECONDARY"
12-
TEXT_HINT = "TEXT_HINT"
13-
TEXT_DIVIDER = "TEXT_DIVIDER"
14-
ICON_PRIMARY = "ICON_PRIMARY"
15-
ICON_SECONDARY = "ICON_SECONDARY"
16-
ICON_HINT = "ICON_HINT"
17-
ICON_DIVIDER = "ICON_DIVIDER"
18-
WHITE_PRIMARY = "WHITE_PRIMARY"

kenar/widgets/description_row.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
class DescriptionRow(BaseModel, BaseWidget):
1010
text: str
1111
has_divider: bool = False
12-
is_primary: bool
12+
is_primary: bool = False
1313
expandable: bool = False
1414
padded: bool = False
1515
preview_max_line: int = 0
@@ -26,13 +26,10 @@ def check_preview_max_line(self) -> Self:
2626

2727
def serialize_model(self) -> dict:
2828
return {
29-
"widget_type": "DESCRIPTION_ROW",
30-
"data": {"@type": "type.googleapis.com/widgets.DescriptionRowData"}
31-
| self.model_dump(),
29+
"description_row": self.model_dump(exclude={"is_primary", "padded"}),
3230
}
3331

3432
@classmethod
3533
def deserialize_model(cls, data: Dict):
36-
widget_data = data.get("data", {})
37-
widget_data.pop("@type", None)
38-
return cls.parse_obj(widget_data)
34+
widget_data = data.get("description_row", {})
35+
return cls.model_validate(widget_data)

kenar/widgets/evaluation_row.py

+16-10
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,27 @@
22

33
from pydantic import BaseModel, field_validator
44

5-
from kenar.icons import Icon
5+
from kenar.icons import Icon, IconName
66
from kenar.widgets.base import BaseWidget
77
from kenar.widgets.color import Color
88

99

1010
class EvaluationRow(BaseModel, BaseWidget):
1111
class Section(BaseModel):
1212
text: str
13-
text_color: Color
13+
text_color: Color = Color.COLOR_UNSPECIFIED
1414
section_color: Color
1515

16+
class Config:
17+
exclude = {"text_color"}
18+
19+
1620
indicator_text: str
1721

1822
indicator_percentage: int
19-
indicator_icon: Icon
23+
indicator_icon: Icon = Icon(icon_name=IconName.UNKNOWN)
2024

21-
indicator_color: Color
25+
indicator_color: Color = Color.COLOR_UNSPECIFIED
2226

2327
left: Section
2428
middle: Section
@@ -33,13 +37,15 @@ def check_indicator_percentage(cls, indicator_percentage: int) -> int:
3337

3438
def serialize_model(self) -> dict:
3539
return {
36-
"widget_type": "EVALUATION_ROW",
37-
"data": {"@type": "type.googleapis.com/widgets.EvaluationRowData"}
38-
| self.model_dump(),
40+
"evaluation_row": self.model_dump(exclude={"indicator_color", "indicator_icon"})
41+
| self.indicator_icon.model_dump() ,
3942
}
4043

4144
@classmethod
4245
def deserialize_model(cls, data: Dict):
43-
widget_data = data.get("data", {})
44-
widget_data.pop("@type", None)
45-
return cls.parse_obj(widget_data)
46+
widget_data = data.get("evaluation_row", {})
47+
48+
widget_data["icon"] = {
49+
"icon_name": "UNKNOWN"
50+
}
51+
return cls.model_validate(widget_data)

kenar/widgets/event_row.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from pydantic import BaseModel
55

6-
from kenar.icons import Icon
6+
from kenar.icons import Icon, IconName
77
from kenar.widgets.action import get_action, get_link_from_action
88
from kenar.widgets.base import BaseWidget
99

@@ -17,21 +17,27 @@ class EventRow(BaseModel, BaseWidget):
1717
has_divider: bool = False
1818
link: str = ""
1919
padded: bool = False
20-
icon: Icon
20+
icon: Icon = Icon(icon_name=IconName.UNKNOWN)
2121

2222
def serialize_model(self) -> dict:
2323
return {
24-
"widget_type": "EVENT_ROW",
25-
"data": {"@type": "type.googleapis.com/widgets.EventRowData"}
26-
| self.dict(exclude={"link"})
27-
| get_action(link=self.link),
24+
"event_row": self.model_dump(exclude={"link", "icon", "image_url"})
25+
| get_action(link=self.link) | {"image_id": self.image_url} | self.icon.model_dump()
2826
}
2927

28+
class Config:
29+
exclude = {"padded", "has_indicator"}
30+
3031
@classmethod
3132
def deserialize_model(cls, data: Dict):
32-
widget_data = data.get("data", {})
33-
widget_data.pop("@type", None)
33+
widget_data = data.get("event_row", {})
3434
if "action" in widget_data:
3535
widget_data["link"] = get_link_from_action(widget_data["action"])
3636
widget_data.pop("action", None)
37-
return cls.parse_obj(widget_data)
37+
widget_data["image_url"] = widget_data.pop("image_id", "")
38+
39+
widget_data["icon"] = {
40+
"icon_name": widget_data.pop("icon_name", "UNKNOWN")
41+
}
42+
43+
return cls.model_validate(widget_data)

kenar/widgets/group_info_row.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,10 @@ def check_items_length(cls, items: List[GroupInfoItem]) -> List[GroupInfoItem]:
2222

2323
def serialize_model(self) -> dict:
2424
return {
25-
"widget_type": "GROUP_INFO_ROW",
26-
"data": {"@type": "type.googleapis.com/widgets.GroupInfoRow"} | self.dict(),
25+
"group_info_row": self.model_dump(),
2726
}
2827

2928
@classmethod
3029
def deserialize_model(cls, data: Dict):
31-
widget_data = data.get("data", {})
32-
widget_data.pop("@type", None)
30+
widget_data = data.get("group_info_row", {})
3331
return cls.parse_obj(widget_data)

kenar/widgets/image_carousel_row.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,22 @@ class ImageCarouselRowItem(BaseModel):
1111
image_url: str
1212
description: str
1313

14+
def serialize_model(self) -> dict:
15+
return {
16+
"image_id" : self.image_url,
17+
"description": self.description
18+
}
19+
1420
items: List[ImageCarouselRowItem]
1521
has_divider: bool = False
1622

1723

1824
def serialize_model(self) -> dict:
1925
return {
20-
"widget_type": "IMAGE_CAROUSEL_ROW",
21-
"data": {"@type": "type.googleapis.com/widgets.ImageCarouselRowData"} | self.dict(),
26+
"image_carousel_row": self.model_dump(),
2227
}
2328

2429
@classmethod
2530
def deserialize_model(cls, data: Dict):
26-
widget_data = data.get("data", {})
27-
widget_data.pop("@type", None)
28-
return cls.parse_obj(widget_data)
31+
widget_data = data.get("image_carousel_row", {})
32+
return cls.model_validate(widget_data)

kenar/widgets/legend_title_row.py

-38
This file was deleted.

0 commit comments

Comments
 (0)