diff --git a/kenar/__init__.py b/kenar/__init__.py index e69de29..7628e0c 100644 --- a/kenar/__init__.py +++ b/kenar/__init__.py @@ -0,0 +1,9 @@ +from .addon import * +from .app import AppConfig, KenarApp +from .chatmessage import * +from .finder import * +from .icons import * +from .image import * +from .oauth import * +from .widgets import * + diff --git a/kenar/addon.py b/kenar/addon.py index 7c25824..13e6486 100644 --- a/kenar/addon.py +++ b/kenar/addon.py @@ -11,13 +11,13 @@ class CreatePostAddonRequest(BaseModel): token: str widgets: List[WidgetTypesUnion] - notes: str = '' + notes: str = "" semantic: Dict[str, str] = {} semantic_sensitives: List[str] = [] - @field_serializer('widgets') + @field_serializer("widgets") def serialize_widgets(self, widgets, _info): - return {'widget_list': [w.serialize_model() for w in widgets]} + return {"widget_list": [w.serialize_model() for w in widgets]} class CreatePostAddonResponse(BaseModel): @@ -34,10 +34,10 @@ class DeletePostAddonResponse(BaseModel): class Status(BaseModel): class Status(str, Enum): - ACTIVE = 'ACTIVE' - INACTIVE = 'INACTIVE' - SUSPENDED = 'SUSPENDED' - DEVELOPMENT = 'DEVELOPMENT' + ACTIVE = "ACTIVE" + INACTIVE = "INACTIVE" + SUSPENDED = "SUSPENDED" + DEVELOPMENT = "DEVELOPMENT" status: Status @@ -71,17 +71,19 @@ class PostAddon(BaseModel): semantic: Dict[str, str] = None semantic_sensitives: List[str] = None - @field_validator('widgets', mode='before') + @field_validator("widgets", mode="before") @classmethod def deserialize_model(cls, widgets: Dict): widget_list = widgets.get("widget_list", []) - return [get_widget_class(w['widget_type']).deserialize_model(w) for w in widget_list] + return [ + get_widget_class(w["widget_type"]).deserialize_model(w) for w in widget_list + ] - @field_serializer('widgets') + @field_serializer("widgets") def serialize_widgets(self, widgets, _info): if widgets: p = [w.serialize_model() for w in widgets] - return {'widget_list': p} + return {"widget_list": p} return None @@ -91,16 +93,16 @@ class GetPostAddonsRequest(BaseModel): @root_validator(pre=True) def check_mutually_exclusive(self, values): - id_, token_ = values.get('id'), values.get('token') + id_, token_ = values.get("id"), values.get("token") if id_ and token_: - raise ValueError('id and token are mutually exclusive.') + raise ValueError("id and token are mutually exclusive.") if not id_ and not token_: - raise ValueError('One of id or token must be set.') + raise ValueError("One of id or token must be set.") return values @model_serializer def ser_model(self) -> dict: - return {'id': self.id} if self.id is not None else {'token': self.token} + return {"id": self.id} if self.id is not None else {"token": self.token} class GetPostAddonsResponse(BaseModel): @@ -112,18 +114,18 @@ class CreateUserAddonRequest(BaseModel): semantic: Dict[str, str] = {} semantic_sensitives: List[str] = [] - notes: str = '' + notes: str = "" phone: str - management_permalink: str = '' - removal_permalink: str = '' + management_permalink: str = "" + removal_permalink: str = "" categories: List[str] ticket_uuid: Optional[str] = None verification_cost: Optional[int] = None - @field_serializer('widgets') + @field_serializer("widgets") def serialize_widgets(self, widgets, _info): p = [w.serialize_model() for w in widgets] - return {'widget_list': p} + return {"widget_list": p} class CreateUserAddonResponse(BaseModel): @@ -155,17 +157,19 @@ class UserAddon(BaseModel): filters: UserAddonFilters - @field_validator('widgets', mode='before') + @field_validator("widgets", mode="before") @classmethod def deserialize_model(cls, widgets: Dict): widget_list = widgets.get("widget_list", []) - return [get_widget_class(w['widget_type']).deserialize_model(w) for w in widget_list] + return [ + get_widget_class(w["widget_type"]).deserialize_model(w) for w in widget_list + ] - @field_serializer('widgets') + @field_serializer("widgets") def serialize_widgets(self, widgets, _info): if widgets: p = [w.serialize_model() for w in widgets] - return {'widget_list': p} + return {"widget_list": p} return None diff --git a/kenar/app.py b/kenar/app.py index 1cae858..6642482 100644 --- a/kenar/app.py +++ b/kenar/app.py @@ -6,19 +6,41 @@ import httpx from pydantic import BaseModel -from kenar.addon import CreateUserAddonRequest, CreateUserAddonResponse, DeleteUserAddonRequest, \ - GetUserAddonsRequest, GetUserAddonsResponse, CreatePostAddonRequest, CreatePostAddonResponse, \ - DeletePostAddonRequest, GetPostAddonsRequest, GetPostAddonsResponse, DeletePostAddonResponse -from kenar.chatmessage import SetNotifyChatPostConversationsRequest, SendMessageV2Request, SendMessageV2Response, \ - SetNotifyChatPostConversationsResponse -from kenar.finder import SearchPostRequest, \ - SearchPostResponse, GetPostRequest, GetUserRequest, \ - GetUserPostsRequest, GetUserResponse, GetUserPostsResponse, GetPostResponse +from kenar import Scope, SendChatMessageResourceIdParams +from kenar.addon import ( + CreateUserAddonRequest, + CreateUserAddonResponse, + DeleteUserAddonRequest, + GetUserAddonsRequest, + GetUserAddonsResponse, + CreatePostAddonRequest, + CreatePostAddonResponse, + DeletePostAddonRequest, + GetPostAddonsRequest, + GetPostAddonsResponse, + DeletePostAddonResponse, +) +from kenar.chatmessage import ( + SetNotifyChatPostConversationsRequest, + SendMessageV2Request, + SendMessageV2Response, + SetNotifyChatPostConversationsResponse, +) +from kenar.finder import ( + SearchPostRequest, + SearchPostResponse, + GetPostRequest, + GetUserRequest, + GetUserPostsRequest, + GetUserResponse, + GetUserPostsResponse, + GetPostResponse, +) from kenar.image import UploadImageResponse -from kenar.oauth import OAuthAccessTokenRequest, AccessTokenResponse, OauthResourceType +from kenar.oauth import OAuthAccessTokenRequest, AccessTokenResponse from kenar.request import retry -ACCESS_TOKEN_HEADER_NAME = 'x-access-token' +ACCESS_TOKEN_HEADER_NAME = "x-access-token" class AppConfig(BaseModel): @@ -28,57 +50,41 @@ class AppConfig(BaseModel): oauth_redirect_url: str -class PostConversationsNotificationRegisterPayload(BaseModel): - post_token: str - phone: str = None - endpoint: str - - -class PostConversationsNotificationPayload(BaseModel): - registration_payload: PostConversationsNotificationRegisterPayload - identification_key: str - - -class Scope(BaseModel): - resource_type: OauthResourceType - resource_id: Optional[str] = None - - -class SendChatMessageResourceIdParams(BaseModel): - user_id: str - post_token: str - peer_id: str - - class ChatService: def __init__(self, client: httpx.Client): self._client = client def set_notify_chat_post_conversations( - self, access_token: str, - data: SetNotifyChatPostConversationsRequest, - max_retry=3, retry_delay=1 + self, + access_token: str, + data: SetNotifyChatPostConversationsRequest, + max_retry=3, + retry_delay=1, ) -> SetNotifyChatPostConversationsResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.post( - url='/v1/open-platform/notify/chat/post-conversations', + url="/v1/open-platform/notify/chat/post-conversations", content=data.json(), - headers={ACCESS_TOKEN_HEADER_NAME: access_token} + headers={ACCESS_TOKEN_HEADER_NAME: access_token}, ) send_request() return SetNotifyChatPostConversationsResponse() - def send_message(self, access_token: str, data: SendMessageV2Request, - max_retry=3, retry_delay=1, - ) -> SendMessageV2Response: + def send_message( + self, + access_token: str, + data: SendMessageV2Request, + max_retry=3, + retry_delay=1, + ) -> SendMessageV2Response: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.post( - url='/v2/open-platform/chat/conversation', + url="/v2/open-platform/chat/conversation", content=data.json(), - headers={ACCESS_TOKEN_HEADER_NAME: access_token} + headers={ACCESS_TOKEN_HEADER_NAME: access_token}, ) rsp = send_request() @@ -89,58 +95,69 @@ class FinderService: def __init__(self, client: httpx.Client): self._client = client - def search_post(self, data: SearchPostRequest, - max_retry=3, retry_delay=1, - ) -> SearchPostResponse: + def search_post( + self, + data: SearchPostRequest, + max_retry=3, + retry_delay=1, + ) -> SearchPostResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.post( - url='/v1/open-platform/finder/post', - content=data.json() + url="/v1/open-platform/finder/post", content=data.json() ) rsp = send_request() return SearchPostResponse(**rsp.json()) - def get_post(self, data: GetPostRequest, - max_retry=3, retry_delay=1, - ) -> GetPostResponse: + def get_post( + self, + data: GetPostRequest, + max_retry=3, + retry_delay=1, + ) -> GetPostResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.request( - method='GET', - url=f'/v1/open-platform/finder/post/{data.token}', + method="GET", + url=f"/v1/open-platform/finder/post/{data.token}", content=data.json(), ) rsp = send_request() return GetPostResponse(**rsp.json()) - def get_user(self, access_token: str, data: GetUserRequest = None, - max_retry=3, retry_delay=1, - ): + def get_user( + self, + access_token: str, + data: GetUserRequest = None, + max_retry=3, + retry_delay=1, + ): @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.post( - url='/v1/open-platform/users', - content=data.json() if data is not None else '', - headers={ACCESS_TOKEN_HEADER_NAME: access_token} + url="/v1/open-platform/users", + content=data.json() if data is not None else "", + headers={ACCESS_TOKEN_HEADER_NAME: access_token}, ) rsp = send_request() return GetUserResponse(**rsp.json()) def get_user_posts( - self, access_token: str, - data: Optional[GetUserPostsRequest] = None, - max_retry=3, retry_delay=1, + self, + access_token: str, + data: Optional[GetUserPostsRequest] = None, + max_retry=3, + retry_delay=1, ): @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.get( - url='/v1/open-platform/finder/user-posts', - params=data.json() if data is not None else '', - headers={ACCESS_TOKEN_HEADER_NAME: access_token} + url="/v1/open-platform/finder/user-posts", + params=data.json() if data is not None else "", + headers={ACCESS_TOKEN_HEADER_NAME: access_token}, ) rsp = send_request() @@ -151,96 +168,119 @@ class AddonService: def __init__(self, client: httpx.Client): self._client = client - def create_user_addon(self, access_token: str, data: CreateUserAddonRequest, - max_retry=3, retry_delay=1, - ) -> CreateUserAddonResponse: + def create_user_addon( + self, + access_token: str, + data: CreateUserAddonRequest, + max_retry=3, + retry_delay=1, + ) -> CreateUserAddonResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.post( - url=f'/v1/open-platform/addons/user/{data.phone}', + url=f"/v1/open-platform/addons/user/{data.phone}", content=data.json(), - headers={ACCESS_TOKEN_HEADER_NAME: access_token} + headers={ACCESS_TOKEN_HEADER_NAME: access_token}, ) rsp = send_request() return CreateUserAddonResponse(**rsp.json()) - def delete_user_addon(self, data: DeleteUserAddonRequest, - max_retry=3, retry_delay=1, - ) -> DeletePostAddonResponse: + def delete_user_addon( + self, + data: DeleteUserAddonRequest, + max_retry=3, + retry_delay=1, + ) -> DeletePostAddonResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.delete( - url=f'/v1/open-platform/addons/user/{data.id}', + url=f"/v1/open-platform/addons/user/{data.id}", params=data.json(), ) send_request() return DeletePostAddonResponse() - def get_user_addons(self, data: GetUserAddonsRequest, - max_retry=3, retry_delay=1, - ) -> GetUserAddonsResponse: + def get_user_addons( + self, + data: GetUserAddonsRequest, + max_retry=3, + retry_delay=1, + ) -> GetUserAddonsResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.get( - url=f'/v1/open-platform/addons/user/{data.phone}', + url=f"/v1/open-platform/addons/user/{data.phone}", params=data.json(), ) rsp = send_request() return GetUserAddonsResponse(**rsp.json()) - def create_post_addon(self, access_token: str, data: CreatePostAddonRequest, - max_retry=3, retry_delay=1, - ) -> CreatePostAddonResponse: + def create_post_addon( + self, + access_token: str, + data: CreatePostAddonRequest, + max_retry=3, + retry_delay=1, + ) -> CreatePostAddonResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.post( - url=f'/v1/open-platform/addons/post/{data.token}', + url=f"/v1/open-platform/addons/post/{data.token}", content=data.json(), - headers={ACCESS_TOKEN_HEADER_NAME: access_token} + headers={ACCESS_TOKEN_HEADER_NAME: access_token}, ) send_request() return CreatePostAddonResponse() - def delete_post_addon(self, data: DeletePostAddonRequest, - max_retry=3, retry_delay=1, - ) -> DeletePostAddonResponse: + def delete_post_addon( + self, + data: DeletePostAddonRequest, + max_retry=3, + retry_delay=1, + ) -> DeletePostAddonResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.delete( - url=f'/v1/open-platform/addons/post/{data.token}', + url=f"/v1/open-platform/addons/post/{data.token}", params=data.json(), ) send_request() return DeletePostAddonResponse() - def upload_image(self, path: str, - max_retry=3, retry_delay=1, - ) -> UploadImageResponse: + def upload_image( + self, + path: str, + max_retry=3, + retry_delay=1, + ) -> UploadImageResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): - with open(path, 'rb') as f: + with open(path, "rb") as f: file_content = f.read() return self._client.put( - url='https://divar.ir/v2/image-service/open-platform/image.jpg', + url="https://divar.ir/v2/image-service/open-platform/image.jpg", content=file_content, - headers={'Content-Type': 'image/jpeg'} + headers={"Content-Type": "image/jpeg"}, ) rsp = send_request() return UploadImageResponse(**rsp.json()) - def get_post_addons(self, data: GetPostAddonsRequest, - max_retry=3, retry_delay=1, - ) -> GetPostAddonsResponse: + def get_post_addons( + self, + data: GetPostAddonsRequest, + max_retry=3, + retry_delay=1, + ) -> GetPostAddonsResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.get( - url=f'/v1/open-platform/addons/post/{data.token}', + url=f"/v1/open-platform/addons/post/{data.token}", params=data.dict(), ) @@ -257,29 +297,38 @@ def __init__(self, client, app_slug, oauth_redirect_url, oauth_secret): def get_oauth_redirect(self, scopes: List[Scope], state: str) -> str: scope = [ - f'{scope.resource_type.value}.{scope.resource_id}' if scope.resource_id is not None else scope.resource_type - for scope in - scopes] - return f'https://api.divar.ir/oauth2/auth?response_type=code&' \ - f'client_id={urllib.parse.quote(self._app_slug)}&' \ - f'state={state}&' \ - f'redirect_uri={urllib.parse.quote(self._oauth_redirect_url)}&' \ - f'scope={urllib.parse.quote_plus(" ".join(scope))}' - - def get_access_token(self, authorization_token: str, - max_retry=3, retry_delay=1, - ) -> AccessTokenResponse: + ( + f"{scope.resource_type.value}.{scope.resource_id}" + if scope.resource_id is not None + else scope.resource_type + ) + for scope in scopes + ] + return ( + f"https://api.divar.ir/oauth2/auth?response_type=code&" + f"client_id={urllib.parse.quote(self._app_slug)}&" + f"state={state}&" + f"redirect_uri={urllib.parse.quote(self._oauth_redirect_url)}&" + f'scope={urllib.parse.quote_plus(" ".join(scope))}' + ) + + def get_access_token( + self, + authorization_token: str, + max_retry=3, + retry_delay=1, + ) -> AccessTokenResponse: @retry(max_retries=max_retry, delay=retry_delay) def send_request(): return self._client.post( - url='/oauth2/token', + url="/oauth2/token", data=OAuthAccessTokenRequest( client_id=self._app_slug, client_secret=self._oauth_secret, code=authorization_token, - redirect_uri=self._oauth_redirect_url + redirect_uri=self._oauth_redirect_url, ).dict(), - headers={'Content-Type': 'application/x-www-form-urlencoded'} + headers={"Content-Type": "application/x-www-form-urlencoded"}, ) rsp = send_request() @@ -287,8 +336,9 @@ def send_request(): @staticmethod def get_send_message_resource_id(params: SendChatMessageResourceIdParams) -> str: - return base64.b64encode(f'{params.user_id}:{params.post_token}:{params.peer_id}'.encode('utf-8')).decode( - "utf-8") + return base64.b64encode( + f"{params.user_id}:{params.post_token}:{params.peer_id}".encode("utf-8") + ).decode("utf-8") class KenarApp: @@ -298,7 +348,9 @@ def __init__(self, conf: AppConfig): if not conf.app_slug: raise ValueError("the KENAR_APP_SLUG environment variable must be set") if not conf.oauth_redirect_url: - raise ValueError("the KENAR_OAUTH_REDIRECT_URL environment variable must be set") + raise ValueError( + "the KENAR_OAUTH_REDIRECT_URL environment variable must be set" + ) if not conf.oauth_secret: raise ValueError("the KENAR_OAUTH_SECRET environment variable must be set") @@ -306,12 +358,19 @@ def __init__(self, conf: AppConfig): self._client = httpx.Client( timeout=1, - headers={'KenarDivarSDK-Version': version('Kenar'), 'x-api-key': conf.api_key, - 'Content-Type': 'application/json'}, - base_url='https://api.divar.ir') - self._oauth = OAuthService(client=self._client, app_slug=self.app_config.app_slug, - oauth_redirect_url=conf.oauth_redirect_url, - oauth_secret=conf.oauth_secret) + headers={ + "KenarDivarSDK-Version": version("Kenar"), + "x-api-key": conf.api_key, + "Content-Type": "application/json", + }, + base_url="https://api.divar.ir", + ) + self._oauth = OAuthService( + client=self._client, + app_slug=self.app_config.app_slug, + oauth_redirect_url=conf.oauth_redirect_url, + oauth_secret=conf.oauth_secret, + ) self._finder = FinderService(self._client) self._chat = ChatService(self._client) self._addon = AddonService(self._client) diff --git a/kenar/chatmessage.py b/kenar/chatmessage.py index fdfddd7..2e80bc9 100644 --- a/kenar/chatmessage.py +++ b/kenar/chatmessage.py @@ -6,8 +6,8 @@ class BotButton(BaseModel): class Action(Enum): - LINK = 'LINK' - DIRECT_LINK = 'DIRECT_LINK' + LINK = "LINK" + DIRECT_LINK = "DIRECT_LINK" class ButtonData(BaseModel): icon_name: str @@ -33,7 +33,7 @@ class SendMessageV2Request(BaseModel): user_id: str peer_id: str post_token: str - type: str = 'TEXT' + type: str = "TEXT" message: str sender_btn: Optional[BotButton] receiver_btn: Optional[BotButton] @@ -42,3 +42,14 @@ class SendMessageV2Request(BaseModel): class SendMessageV2Response(BaseModel): status: int message: str + + +class PostConversationsNotificationRegisterPayload(BaseModel): + post_token: str + phone: str = None + endpoint: str + + +class PostConversationsNotificationPayload(BaseModel): + registration_payload: PostConversationsNotificationRegisterPayload + identification_key: str diff --git a/kenar/finder.py b/kenar/finder.py index 8a1ac33..7b6f380 100644 --- a/kenar/finder.py +++ b/kenar/finder.py @@ -20,11 +20,11 @@ class GetPostRequest(BaseModel): class PostExtState(str, Enum): - UNKNOWN = 'UNKNOWN' - PUBLISHED = 'PUBLISHED' - REVIEW_REQ = 'REVIEW_REQ' - PAYMENT_REQ = 'PAYMENT_REQ' - RETIRED = 'RETIRED' + UNKNOWN = "UNKNOWN" + PUBLISHED = "PUBLISHED" + REVIEW_REQ = "REVIEW_REQ" + PAYMENT_REQ = "PAYMENT_REQ" + RETIRED = "RETIRED" class GetPostResponse(BaseModel): diff --git a/kenar/icons.py b/kenar/icons.py index ed92429..f487455 100644 --- a/kenar/icons.py +++ b/kenar/icons.py @@ -4,349 +4,349 @@ class IconName(str, Enum): - UNKNOWN = 'UNKNOWN' - ACCESS_TIME_OUTLINE = 'ACCESS_TIME_OUTLINE' - ACCESS_TIME = 'ACCESS_TIME' - ADD_CIRCLE_OUTLINE = 'ADD_CIRCLE_OUTLINE' - ADD_CIRCLE = 'ADD_CIRCLE' - ADD = 'ADD' - ADVERT_OUTLINE = 'ADVERT_OUTLINE' - ADVERT = 'ADVERT' - ANALYTICS = 'ANALYTICS' - ARROW_FORWARD = 'ARROW_FORWARD' - ARTICLE_OUTLINE = 'ARTICLE_OUTLINE' - ASSIGNMENT_IND = 'ASSIGNMENT_IND' - BABY = 'BABY' - BACKPACK = 'BACKPACK' - BAGUETTE = 'BAGUETTE' - BALCONY = 'BALCONY' - BANK = 'BANK' - BINDER = 'BINDER' - BLOCK = 'BLOCK' - BOOKMARK_BORDER = 'BOOKMARK_BORDER' - BOOKMARK = 'BOOKMARK' - BRAND_ACER = 'BRAND_ACER' - BRAND_ALCATEL = 'BRAND_ALCATEL' - BRAND_AMAZON = 'BRAND_AMAZON' - BRAND_AMICO = 'BRAND_AMICO' - BRAND_APPLE = 'BRAND_APPLE' - BRAND_ARCHOS = 'BRAND_ARCHOS' - BRAND_ARIO = 'BRAND_ARIO' - BRAND_ARISAN = 'BRAND_ARISAN' - BRAND_ASUS = 'BRAND_ASUS' - BRAND_AUDI = 'BRAND_AUDI' - BRAND_BAIC = 'BRAND_BAIC' - BRAND_BESTURN = 'BRAND_BESTURN' - BRAND_BISU = 'BRAND_BISU' - BRAND_BLACKBERRY = 'BRAND_BLACKBERRY' - BRAND_BLU = 'BRAND_BLU' - BRAND_BMW = 'BRAND_BMW' - BRAND_BORGWARD = 'BRAND_BORGWARD' - BRAND_BRILLIANCE = 'BRAND_BRILLIANCE' - BRAND_BUICK = 'BRAND_BUICK' - BRAND_BYD = 'BRAND_BYD' - BRAND_CAPRA = 'BRAND_CAPRA' - BRAND_CATERPILLAR = 'BRAND_CATERPILLAR' - BRAND_CHANGAN = 'BRAND_CHANGAN' - BRAND_CHERY = 'BRAND_CHERY' - BRAND_CHEVROLET = 'BRAND_CHEVROLET' - BRAND_CHRYSLER = 'BRAND_CHRYSLER' - BRAND_CITROEN = 'BRAND_CITROEN' - BRAND_DAEWOO = 'BRAND_DAEWOO' - BRAND_DAIHATSU = 'BRAND_DAIHATSU' - BRAND_DATSUN = 'BRAND_DATSUN' - BRAND_DAYUN = 'BRAND_DAYUN' - BRAND_DEER = 'BRAND_DEER' - BRAND_DELICA = 'BRAND_DELICA' - BRAND_DENA = 'BRAND_DENA' - BRAND_DIGNITY = 'BRAND_DIGNITY' - BRAND_DODGE = 'BRAND_DODGE' - BRAND_DOMY = 'BRAND_DOMY' - BRAND_DS = 'BRAND_DS' - BRAND_ENERGIZER = 'BRAND_ENERGIZER' - BRAND_FARDA = 'BRAND_FARDA' - BRAND_FIAT = 'BRAND_FIAT' - BRAND_FIDELITY = 'BRAND_FIDELITY' - BRAND_FORD = 'BRAND_FORD' - BRAND_FOTON = 'BRAND_FOTON' - BRAND_FOWNIX = 'BRAND_FOWNIX' - BRAND_GAC_GONOW = 'BRAND_GAC_GONOW' - BRAND_GEELY = 'BRAND_GEELY' - BRAND_GIGABYTE = 'BRAND_GIGABYTE' - BRAND_GIONEE = 'BRAND_GIONEE' - BRAND_GLX = 'BRAND_GLX' - BRAND_GOOGLE = 'BRAND_GOOGLE' - BRAND_GPLUS = 'BRAND_GPLUS' - BRAND_GREATWALL = 'BRAND_GREATWALL' - BRAND_HAFEI_LOBO = 'BRAND_HAFEI_LOBO' - BRAND_HAIMA = 'BRAND_HAIMA' - BRAND_HANTENG = 'BRAND_HANTENG' - BRAND_HAVAL = 'BRAND_HAVAL' - BRAND_HILLMAN = 'BRAND_HILLMAN' - BRAND_HONDA = 'BRAND_HONDA' - BRAND_HONOR = 'BRAND_HONOR' - BRAND_HTC = 'BRAND_HTC' - BRAND_HUAWEI = 'BRAND_HUAWEI' - BRAND_HUMMER = 'BRAND_HUMMER' - BRAND_HYOSOW = 'BRAND_HYOSOW' - BRAND_HYUNDAI = 'BRAND_HYUNDAI' - BRAND_INROADS = 'BRAND_INROADS' - BRAND_IRANKHODRO_VAN = 'BRAND_IRANKHODRO_VAN' - BRAND_ISUZU = 'BRAND_ISUZU' - BRAND_IVECO = 'BRAND_IVECO' - BRAND_JAC = 'BRAND_JAC' - BRAND_JAGUAR = 'BRAND_JAGUAR' - BRAND_JEEP = 'BRAND_JEEP' - BRAND_JMC = 'BRAND_JMC' - BRAND_JOYLONG = 'BRAND_JOYLONG' - BRAND_KIA = 'BRAND_KIA' - BRAND_KMC = 'BRAND_KMC' - BRAND_LADA = 'BRAND_LADA' - BRAND_LAMARI = 'BRAND_LAMARI' - BRAND_LAMBORGHINI = 'BRAND_LAMBORGHINI' - BRAND_LAND_ROVER = 'BRAND_LAND_ROVER' - BRAND_LANDMARK = 'BRAND_LANDMARK' - BRAND_LENOVO = 'BRAND_LENOVO' - BRAND_LEXUS = 'BRAND_LEXUS' - BRAND_LG = 'BRAND_LG' - BRAND_LIFAN = 'BRAND_LIFAN' - BRAND_LOTUS = 'BRAND_LOTUS' - BRAND_LUXGEN = 'BRAND_LUXGEN' - BRAND_MASERATI = 'BRAND_MASERATI' - BRAND_MAXMOTOR = 'BRAND_MAXMOTOR' - BRAND_MAXUS = 'BRAND_MAXUS' - BRAND_MAZDA = 'BRAND_MAZDA' - BRAND_MEIZU = 'BRAND_MEIZU' - BRAND_MG = 'BRAND_MG' - BRAND_MICROMAX = 'BRAND_MICROMAX' - BRAND_MICROSOFT = 'BRAND_MICROSOFT' - BRAND_MINI = 'BRAND_MINI' - BRAND_MITSUBISHI = 'BRAND_MITSUBISHI' - BRAND_MOTOROLA = 'BRAND_MOTOROLA' - BRAND_MVM = 'BRAND_MVM' - BRAND_NARVAN = 'BRAND_NARVAN' - BRAND_NISSAN = 'BRAND_NISSAN' - BRAND_NOKIA = 'BRAND_NOKIA' - BRAND_OLDSMOBILE = 'BRAND_OLDSMOBILE' - BRAND_ONEPLUS = 'BRAND_ONEPLUS' - BRAND_OPEL = 'BRAND_OPEL' - BRAND_OPPO = 'BRAND_OPPO' - BRAND_PANASONIC = 'BRAND_PANASONIC' - BRAND_PAYKAN = 'BRAND_PAYKAN' - BRAND_PAZHAN = 'BRAND_PAZHAN' - BRAND_PEUGEOT = 'BRAND_PEUGEOT' - BRAND_PHILIPS = 'BRAND_PHILIPS' - BRAND_PIXEL = 'BRAND_PIXEL' - BRAND_PONTIAC = 'BRAND_PONTIAC' - BRAND_PORSCHE = 'BRAND_PORSCHE' - BRAND_PRESTIGIO = 'BRAND_PRESTIGIO' - BRAND_PRIDE = 'BRAND_PRIDE' - BRAND_PROTON = 'BRAND_PROTON' - BRAND_QUICK = 'BRAND_QUICK' - BRAND_RAYEN = 'BRAND_RAYEN' - BRAND_RAZER = 'BRAND_RAZER' - BRAND_REALME = 'BRAND_REALME' - BRAND_RENAULT = 'BRAND_RENAULT' - BRAND_RESPECT = 'BRAND_RESPECT' - BRAND_RICH = 'BRAND_RICH' - BRAND_RIGAN = 'BRAND_RIGAN' - BRAND_ROLLSROYCE = 'BRAND_ROLLSROYCE' - BRAND_RUNNA = 'BRAND_RUNNA' - BRAND_SAINA = 'BRAND_SAINA' - BRAND_SAMSUNG = 'BRAND_SAMSUNG' - BRAND_SEAT = 'BRAND_SEAT' - BRAND_SHAHIN = 'BRAND_SHAHIN' - BRAND_SHARP = 'BRAND_SHARP' - BRAND_SINAD = 'BRAND_SINAD' - BRAND_SMART = 'BRAND_SMART' - BRAND_SONY_ERICSSON = 'BRAND_SONY_ERICSSON' - BRAND_SONY = 'BRAND_SONY' - BRAND_SOUEAST = 'BRAND_SOUEAST' - BRAND_SSANGYONG = 'BRAND_SSANGYONG' - BRAND_SUBARU = 'BRAND_SUBARU' - BRAND_SUZUKI = 'BRAND_SUZUKI' - BRAND_SWM = 'BRAND_SWM' - BRAND_TARA = 'BRAND_TARA' - BRAND_TIBA = 'BRAND_TIBA' - BRAND_TIGARD = 'BRAND_TIGARD' - BRAND_TOYOTA = 'BRAND_TOYOTA' - BRAND_UAZ = 'BRAND_UAZ' - BRAND_VERTU = 'BRAND_VERTU' - BRAND_VIVO = 'BRAND_VIVO' - BRAND_VOLKSWAGEN = 'BRAND_VOLKSWAGEN' - BRAND_VOLVO = 'BRAND_VOLVO' - BRAND_XIAOMI = 'BRAND_XIAOMI' - BRAND_YOTA = 'BRAND_YOTA' - BRAND_ZAMYAD = 'BRAND_ZAMYAD' - BRAND_ZOTYE = 'BRAND_ZOTYE' - BRAND_ZTE = 'BRAND_ZTE' - BUS = 'BUS' - CABINET = 'CABINET' - CALL = 'CALL' - CANCEL = 'CANCEL' - CAPSULE = 'CAPSULE' - CAR_AMENITY = 'CAR_AMENITY' - CAR_AUCTION = 'CAR_AUCTION' - CAR_BODY = 'CAR_BODY' - CAR_DOCUMENTS = 'CAR_DOCUMENTS' - CAR_ELECTRONICS = 'CAR_ELECTRONICS' - CAR_ENGINE = 'CAR_ENGINE' - CAR_EQUIPMENT = 'CAR_EQUIPMENT' - CAR_HYDRAULICS = 'CAR_HYDRAULICS' - CAR_OPTIONS = 'CAR_OPTIONS' - CAR_SAFETY = 'CAR_SAFETY' - CAR_TIRES = 'CAR_TIRES' - CART = 'CART' - CAT_ELECTRONIC_DEVICES = 'CAT_ELECTRONIC_DEVICES' - CAT_FOR_THE_HOME = 'CAT_FOR_THE_HOME' - CAT_JOBS = 'CAT_JOBS' - CAT_LEISURE_HOBBIES = 'CAT_LEISURE_HOBBIES' - CAT_PERSONAL = 'CAT_PERSONAL' - CAT_SERVICES = 'CAT_SERVICES' - CHART = 'CHART' - CHAT_DOUBLE = 'CHAT_DOUBLE' - CHECK_BOX_OUTLINE_BLANK = 'CHECK_BOX_OUTLINE_BLANK' - CHECK_BOX = 'CHECK_BOX' - CHECK_CIRCLE = 'CHECK_CIRCLE' - CHECKED = 'CHECKED' - CLOSE = 'CLOSE' - COFFEE = 'COFFEE' - COMMUNITY = 'COMMUNITY' - CONCIERGE_SALE = 'CONCIERGE_SALE' - CONTACT_PHONE = 'CONTACT_PHONE' - CONTENT_COPY = 'CONTENT_COPY' - CREDIT_ACCOUNT = 'CREDIT_ACCOUNT' - DELETE = 'DELETE' - DOWNLOAD = 'DOWNLOAD' - EARNEST = 'EARNEST' - EDIT = 'EDIT' - ELEVATOR = 'ELEVATOR' - EMAIL_OUTLINE = 'EMAIL_OUTLINE' - EVENT_NOTE = 'EVENT_NOTE' - EXCHANGE = 'EXCHANGE' - EXIT_TO_APP = 'EXIT_TO_APP' - EYE_OFF = 'EYE_OFF' - FILTER = 'FILTER' - FRUIT = 'FRUIT' - FULLSCREEN = 'FULLSCREEN' - GAS_STATION = 'GAS_STATION' - GAVEL = 'GAVEL' - GIFT = 'GIFT' - GYM = 'GYM' - HAMBURGER = 'HAMBURGER' - HELP_OUTLINE = 'HELP_OUTLINE' - HELP = 'HELP' - HIGHWAY = 'HIGHWAY' - HISTORY = 'HISTORY' - HOSPITAL = 'HOSPITAL' - IMAGE_OUTLINE = 'IMAGE_OUTLINE' - INFO_OUTLINE = 'INFO_OUTLINE' - INFO = 'INFO' - INSPECT = 'INSPECT' - INSTAGRAM = 'INSTAGRAM' - KEYBOARD_ARROW_LEFT = 'KEYBOARD_ARROW_LEFT' - KEYBOARD_ARROW_RIGHT = 'KEYBOARD_ARROW_RIGHT' - LADDER_COLLECTION = 'LADDER_COLLECTION' - LADDER_GROUP = 'LADDER_GROUP' - LAUNCH = 'LAUNCH' - LOCAL_SHIPPING = 'LOCAL_SHIPPING' - LOCK = 'LOCK' - LOGOUT = 'LOGOUT' - MEDIC = 'MEDIC' - METRO = 'METRO' - MOBILE_FRIENDLY = 'MOBILE_FRIENDLY' - MONEY = 'MONEY' - MOPED = 'MOPED' - MORE_VERT = 'MORE_VERT' - MOSQUE = 'MOSQUE' - NOTE_ADD_OUTLINE = 'NOTE_ADD_OUTLINE' - NOTE_OUTLINE = 'NOTE_OUTLINE' - NOTE = 'NOTE' - NUM_1 = 'NUM_1' - NUM_2 = 'NUM_2' - NUM_3 = 'NUM_3' - NUM_4 = 'NUM_4' - NUM_5 = 'NUM_5' - NUM_6 = 'NUM_6' - NUM_7 = 'NUM_7' - NUM_8 = 'NUM_8' - NUM_9 = 'NUM_9' - PARKING = 'PARKING' - PERSON_ADD = 'PERSON_ADD' - PERSON = 'PERSON' - PHOTO_LIBRARY = 'PHOTO_LIBRARY' - PLACE = 'PLACE' - REAL_ESTATE = 'REAL_ESTATE' - REFRESH = 'REFRESH' - REMOVE = 'REMOVE' - REPORT = 'REPORT' - RESTAURANT = 'RESTAURANT' - SCHOOL_OUTLINE = 'SCHOOL_OUTLINE' - SCHOOL = 'SCHOOL' - SEND = 'SEND' - SETTINGS = 'SETTINGS' - SHARE = 'SHARE' - SHIELD_PHONE = 'SHIELD_PHONE' - SHOPPING = 'SHOPPING' - SHOW_CHART = 'SHOW_CHART' - SNOWFLAKE = 'SNOWFLAKE' - STAR_BORDER = 'STAR_BORDER' - STAR = 'STAR' - STETHOSCOPE = 'STETHOSCOPE' - STORE_OUTLINE = 'STORE_OUTLINE' - STORE = 'STORE' - SUNNY = 'SUNNY' - SUPPORT_AGENT = 'SUPPORT_AGENT' - SUPPORT = 'SUPPORT' - TAG_CHECK_CIRCLE = 'TAG_CHECK_CIRCLE' - TAXI = 'TAXI' - TELEPHONE = 'TELEPHONE' - TERMS = 'TERMS' - TEXT_SMS_OUTLINE = 'TEXT_SMS_OUTLINE' - TEXTURE = 'TEXTURE' - THERMOMETER = 'THERMOMETER' - TIMER = 'TIMER' - TOC = 'TOC' - TREES = 'TREES' - TRENDING_UP = 'TRENDING_UP' - TUNE = 'TUNE' - VERIFIED_USER = 'VERIFIED_USER' - VERIFIED = 'VERIFIED' - VIDEOCAM = 'VIDEOCAM' - VISIBILITY = 'VISIBILITY' - VR = 'VR' - WARNING = 'WARNING' - WC = 'WC' - BRAND_ALFA_ROMEO = 'BRAND_ALFA_ROMEO' - BRAND_MERCEDESBENZ = 'BRAND_MERCEDESBENZ' - BRAND_DONGFENG = 'BRAND_DONGFENG' - POST_FEEDBACK = 'POST_FEEDBACK' - PAYMENT_OUTLINE = 'PAYMENT_OUTLINE' - CAMERA = 'CAMERA' - CAMERA_O = 'CAMERA_O' - VIDEOCAM_O = 'VIDEOCAM_O' - ARCHWAY = 'ARCHWAY' - CAR_INSPECTED = 'CAR_INSPECTED' - CAR_INSPECTION = 'CAR_INSPECTION' - CAT_BUSINESSES = 'CAT_BUSINESSES' - CHART_O = 'CHART_O' - CONTACT_PHONE_O = 'CONTACT_PHONE_O' - FILE_O = 'FILE_O' - FILE = 'FILE' - IMAGE_OUTLINE_O = 'IMAGE_OUTLINE_O' - INDICATOR = 'INDICATOR' - MARKETPLACE_ELECTRONIC_DEVICES = 'MARKETPLACE_ELECTRONIC_DEVICES' - MARKETPLACE_GENERAL = 'MARKETPLACE_GENERAL' - MARKETPLACE_HOME = 'MARKETPLACE_HOME' - MARKETPLACE_PERSONAL = 'MARKETPLACE_PERSONAL' - PLACE_F = 'PLACE_F' - POI = 'POI' - PUZZLE_OUTLINE = 'PUZZLE_OUTLINE' - PUZZLE = 'PUZZLE' - SHIELD_PHONE_O = 'SHIELD_PHONE_O' - STREET_SIGN = 'STREET_SIGN' - VERIFIED_GREEN = 'VERIFIED_GREEN' - WALLET = 'WALLET' + UNKNOWN = "UNKNOWN" + ACCESS_TIME_OUTLINE = "ACCESS_TIME_OUTLINE" + ACCESS_TIME = "ACCESS_TIME" + ADD_CIRCLE_OUTLINE = "ADD_CIRCLE_OUTLINE" + ADD_CIRCLE = "ADD_CIRCLE" + ADD = "ADD" + ADVERT_OUTLINE = "ADVERT_OUTLINE" + ADVERT = "ADVERT" + ANALYTICS = "ANALYTICS" + ARROW_FORWARD = "ARROW_FORWARD" + ARTICLE_OUTLINE = "ARTICLE_OUTLINE" + ASSIGNMENT_IND = "ASSIGNMENT_IND" + BABY = "BABY" + BACKPACK = "BACKPACK" + BAGUETTE = "BAGUETTE" + BALCONY = "BALCONY" + BANK = "BANK" + BINDER = "BINDER" + BLOCK = "BLOCK" + BOOKMARK_BORDER = "BOOKMARK_BORDER" + BOOKMARK = "BOOKMARK" + BRAND_ACER = "BRAND_ACER" + BRAND_ALCATEL = "BRAND_ALCATEL" + BRAND_AMAZON = "BRAND_AMAZON" + BRAND_AMICO = "BRAND_AMICO" + BRAND_APPLE = "BRAND_APPLE" + BRAND_ARCHOS = "BRAND_ARCHOS" + BRAND_ARIO = "BRAND_ARIO" + BRAND_ARISAN = "BRAND_ARISAN" + BRAND_ASUS = "BRAND_ASUS" + BRAND_AUDI = "BRAND_AUDI" + BRAND_BAIC = "BRAND_BAIC" + BRAND_BESTURN = "BRAND_BESTURN" + BRAND_BISU = "BRAND_BISU" + BRAND_BLACKBERRY = "BRAND_BLACKBERRY" + BRAND_BLU = "BRAND_BLU" + BRAND_BMW = "BRAND_BMW" + BRAND_BORGWARD = "BRAND_BORGWARD" + BRAND_BRILLIANCE = "BRAND_BRILLIANCE" + BRAND_BUICK = "BRAND_BUICK" + BRAND_BYD = "BRAND_BYD" + BRAND_CAPRA = "BRAND_CAPRA" + BRAND_CATERPILLAR = "BRAND_CATERPILLAR" + BRAND_CHANGAN = "BRAND_CHANGAN" + BRAND_CHERY = "BRAND_CHERY" + BRAND_CHEVROLET = "BRAND_CHEVROLET" + BRAND_CHRYSLER = "BRAND_CHRYSLER" + BRAND_CITROEN = "BRAND_CITROEN" + BRAND_DAEWOO = "BRAND_DAEWOO" + BRAND_DAIHATSU = "BRAND_DAIHATSU" + BRAND_DATSUN = "BRAND_DATSUN" + BRAND_DAYUN = "BRAND_DAYUN" + BRAND_DEER = "BRAND_DEER" + BRAND_DELICA = "BRAND_DELICA" + BRAND_DENA = "BRAND_DENA" + BRAND_DIGNITY = "BRAND_DIGNITY" + BRAND_DODGE = "BRAND_DODGE" + BRAND_DOMY = "BRAND_DOMY" + BRAND_DS = "BRAND_DS" + BRAND_ENERGIZER = "BRAND_ENERGIZER" + BRAND_FARDA = "BRAND_FARDA" + BRAND_FIAT = "BRAND_FIAT" + BRAND_FIDELITY = "BRAND_FIDELITY" + BRAND_FORD = "BRAND_FORD" + BRAND_FOTON = "BRAND_FOTON" + BRAND_FOWNIX = "BRAND_FOWNIX" + BRAND_GAC_GONOW = "BRAND_GAC_GONOW" + BRAND_GEELY = "BRAND_GEELY" + BRAND_GIGABYTE = "BRAND_GIGABYTE" + BRAND_GIONEE = "BRAND_GIONEE" + BRAND_GLX = "BRAND_GLX" + BRAND_GOOGLE = "BRAND_GOOGLE" + BRAND_GPLUS = "BRAND_GPLUS" + BRAND_GREATWALL = "BRAND_GREATWALL" + BRAND_HAFEI_LOBO = "BRAND_HAFEI_LOBO" + BRAND_HAIMA = "BRAND_HAIMA" + BRAND_HANTENG = "BRAND_HANTENG" + BRAND_HAVAL = "BRAND_HAVAL" + BRAND_HILLMAN = "BRAND_HILLMAN" + BRAND_HONDA = "BRAND_HONDA" + BRAND_HONOR = "BRAND_HONOR" + BRAND_HTC = "BRAND_HTC" + BRAND_HUAWEI = "BRAND_HUAWEI" + BRAND_HUMMER = "BRAND_HUMMER" + BRAND_HYOSOW = "BRAND_HYOSOW" + BRAND_HYUNDAI = "BRAND_HYUNDAI" + BRAND_INROADS = "BRAND_INROADS" + BRAND_IRANKHODRO_VAN = "BRAND_IRANKHODRO_VAN" + BRAND_ISUZU = "BRAND_ISUZU" + BRAND_IVECO = "BRAND_IVECO" + BRAND_JAC = "BRAND_JAC" + BRAND_JAGUAR = "BRAND_JAGUAR" + BRAND_JEEP = "BRAND_JEEP" + BRAND_JMC = "BRAND_JMC" + BRAND_JOYLONG = "BRAND_JOYLONG" + BRAND_KIA = "BRAND_KIA" + BRAND_KMC = "BRAND_KMC" + BRAND_LADA = "BRAND_LADA" + BRAND_LAMARI = "BRAND_LAMARI" + BRAND_LAMBORGHINI = "BRAND_LAMBORGHINI" + BRAND_LAND_ROVER = "BRAND_LAND_ROVER" + BRAND_LANDMARK = "BRAND_LANDMARK" + BRAND_LENOVO = "BRAND_LENOVO" + BRAND_LEXUS = "BRAND_LEXUS" + BRAND_LG = "BRAND_LG" + BRAND_LIFAN = "BRAND_LIFAN" + BRAND_LOTUS = "BRAND_LOTUS" + BRAND_LUXGEN = "BRAND_LUXGEN" + BRAND_MASERATI = "BRAND_MASERATI" + BRAND_MAXMOTOR = "BRAND_MAXMOTOR" + BRAND_MAXUS = "BRAND_MAXUS" + BRAND_MAZDA = "BRAND_MAZDA" + BRAND_MEIZU = "BRAND_MEIZU" + BRAND_MG = "BRAND_MG" + BRAND_MICROMAX = "BRAND_MICROMAX" + BRAND_MICROSOFT = "BRAND_MICROSOFT" + BRAND_MINI = "BRAND_MINI" + BRAND_MITSUBISHI = "BRAND_MITSUBISHI" + BRAND_MOTOROLA = "BRAND_MOTOROLA" + BRAND_MVM = "BRAND_MVM" + BRAND_NARVAN = "BRAND_NARVAN" + BRAND_NISSAN = "BRAND_NISSAN" + BRAND_NOKIA = "BRAND_NOKIA" + BRAND_OLDSMOBILE = "BRAND_OLDSMOBILE" + BRAND_ONEPLUS = "BRAND_ONEPLUS" + BRAND_OPEL = "BRAND_OPEL" + BRAND_OPPO = "BRAND_OPPO" + BRAND_PANASONIC = "BRAND_PANASONIC" + BRAND_PAYKAN = "BRAND_PAYKAN" + BRAND_PAZHAN = "BRAND_PAZHAN" + BRAND_PEUGEOT = "BRAND_PEUGEOT" + BRAND_PHILIPS = "BRAND_PHILIPS" + BRAND_PIXEL = "BRAND_PIXEL" + BRAND_PONTIAC = "BRAND_PONTIAC" + BRAND_PORSCHE = "BRAND_PORSCHE" + BRAND_PRESTIGIO = "BRAND_PRESTIGIO" + BRAND_PRIDE = "BRAND_PRIDE" + BRAND_PROTON = "BRAND_PROTON" + BRAND_QUICK = "BRAND_QUICK" + BRAND_RAYEN = "BRAND_RAYEN" + BRAND_RAZER = "BRAND_RAZER" + BRAND_REALME = "BRAND_REALME" + BRAND_RENAULT = "BRAND_RENAULT" + BRAND_RESPECT = "BRAND_RESPECT" + BRAND_RICH = "BRAND_RICH" + BRAND_RIGAN = "BRAND_RIGAN" + BRAND_ROLLSROYCE = "BRAND_ROLLSROYCE" + BRAND_RUNNA = "BRAND_RUNNA" + BRAND_SAINA = "BRAND_SAINA" + BRAND_SAMSUNG = "BRAND_SAMSUNG" + BRAND_SEAT = "BRAND_SEAT" + BRAND_SHAHIN = "BRAND_SHAHIN" + BRAND_SHARP = "BRAND_SHARP" + BRAND_SINAD = "BRAND_SINAD" + BRAND_SMART = "BRAND_SMART" + BRAND_SONY_ERICSSON = "BRAND_SONY_ERICSSON" + BRAND_SONY = "BRAND_SONY" + BRAND_SOUEAST = "BRAND_SOUEAST" + BRAND_SSANGYONG = "BRAND_SSANGYONG" + BRAND_SUBARU = "BRAND_SUBARU" + BRAND_SUZUKI = "BRAND_SUZUKI" + BRAND_SWM = "BRAND_SWM" + BRAND_TARA = "BRAND_TARA" + BRAND_TIBA = "BRAND_TIBA" + BRAND_TIGARD = "BRAND_TIGARD" + BRAND_TOYOTA = "BRAND_TOYOTA" + BRAND_UAZ = "BRAND_UAZ" + BRAND_VERTU = "BRAND_VERTU" + BRAND_VIVO = "BRAND_VIVO" + BRAND_VOLKSWAGEN = "BRAND_VOLKSWAGEN" + BRAND_VOLVO = "BRAND_VOLVO" + BRAND_XIAOMI = "BRAND_XIAOMI" + BRAND_YOTA = "BRAND_YOTA" + BRAND_ZAMYAD = "BRAND_ZAMYAD" + BRAND_ZOTYE = "BRAND_ZOTYE" + BRAND_ZTE = "BRAND_ZTE" + BUS = "BUS" + CABINET = "CABINET" + CALL = "CALL" + CANCEL = "CANCEL" + CAPSULE = "CAPSULE" + CAR_AMENITY = "CAR_AMENITY" + CAR_AUCTION = "CAR_AUCTION" + CAR_BODY = "CAR_BODY" + CAR_DOCUMENTS = "CAR_DOCUMENTS" + CAR_ELECTRONICS = "CAR_ELECTRONICS" + CAR_ENGINE = "CAR_ENGINE" + CAR_EQUIPMENT = "CAR_EQUIPMENT" + CAR_HYDRAULICS = "CAR_HYDRAULICS" + CAR_OPTIONS = "CAR_OPTIONS" + CAR_SAFETY = "CAR_SAFETY" + CAR_TIRES = "CAR_TIRES" + CART = "CART" + CAT_ELECTRONIC_DEVICES = "CAT_ELECTRONIC_DEVICES" + CAT_FOR_THE_HOME = "CAT_FOR_THE_HOME" + CAT_JOBS = "CAT_JOBS" + CAT_LEISURE_HOBBIES = "CAT_LEISURE_HOBBIES" + CAT_PERSONAL = "CAT_PERSONAL" + CAT_SERVICES = "CAT_SERVICES" + CHART = "CHART" + CHAT_DOUBLE = "CHAT_DOUBLE" + CHECK_BOX_OUTLINE_BLANK = "CHECK_BOX_OUTLINE_BLANK" + CHECK_BOX = "CHECK_BOX" + CHECK_CIRCLE = "CHECK_CIRCLE" + CHECKED = "CHECKED" + CLOSE = "CLOSE" + COFFEE = "COFFEE" + COMMUNITY = "COMMUNITY" + CONCIERGE_SALE = "CONCIERGE_SALE" + CONTACT_PHONE = "CONTACT_PHONE" + CONTENT_COPY = "CONTENT_COPY" + CREDIT_ACCOUNT = "CREDIT_ACCOUNT" + DELETE = "DELETE" + DOWNLOAD = "DOWNLOAD" + EARNEST = "EARNEST" + EDIT = "EDIT" + ELEVATOR = "ELEVATOR" + EMAIL_OUTLINE = "EMAIL_OUTLINE" + EVENT_NOTE = "EVENT_NOTE" + EXCHANGE = "EXCHANGE" + EXIT_TO_APP = "EXIT_TO_APP" + EYE_OFF = "EYE_OFF" + FILTER = "FILTER" + FRUIT = "FRUIT" + FULLSCREEN = "FULLSCREEN" + GAS_STATION = "GAS_STATION" + GAVEL = "GAVEL" + GIFT = "GIFT" + GYM = "GYM" + HAMBURGER = "HAMBURGER" + HELP_OUTLINE = "HELP_OUTLINE" + HELP = "HELP" + HIGHWAY = "HIGHWAY" + HISTORY = "HISTORY" + HOSPITAL = "HOSPITAL" + IMAGE_OUTLINE = "IMAGE_OUTLINE" + INFO_OUTLINE = "INFO_OUTLINE" + INFO = "INFO" + INSPECT = "INSPECT" + INSTAGRAM = "INSTAGRAM" + KEYBOARD_ARROW_LEFT = "KEYBOARD_ARROW_LEFT" + KEYBOARD_ARROW_RIGHT = "KEYBOARD_ARROW_RIGHT" + LADDER_COLLECTION = "LADDER_COLLECTION" + LADDER_GROUP = "LADDER_GROUP" + LAUNCH = "LAUNCH" + LOCAL_SHIPPING = "LOCAL_SHIPPING" + LOCK = "LOCK" + LOGOUT = "LOGOUT" + MEDIC = "MEDIC" + METRO = "METRO" + MOBILE_FRIENDLY = "MOBILE_FRIENDLY" + MONEY = "MONEY" + MOPED = "MOPED" + MORE_VERT = "MORE_VERT" + MOSQUE = "MOSQUE" + NOTE_ADD_OUTLINE = "NOTE_ADD_OUTLINE" + NOTE_OUTLINE = "NOTE_OUTLINE" + NOTE = "NOTE" + NUM_1 = "NUM_1" + NUM_2 = "NUM_2" + NUM_3 = "NUM_3" + NUM_4 = "NUM_4" + NUM_5 = "NUM_5" + NUM_6 = "NUM_6" + NUM_7 = "NUM_7" + NUM_8 = "NUM_8" + NUM_9 = "NUM_9" + PARKING = "PARKING" + PERSON_ADD = "PERSON_ADD" + PERSON = "PERSON" + PHOTO_LIBRARY = "PHOTO_LIBRARY" + PLACE = "PLACE" + REAL_ESTATE = "REAL_ESTATE" + REFRESH = "REFRESH" + REMOVE = "REMOVE" + REPORT = "REPORT" + RESTAURANT = "RESTAURANT" + SCHOOL_OUTLINE = "SCHOOL_OUTLINE" + SCHOOL = "SCHOOL" + SEND = "SEND" + SETTINGS = "SETTINGS" + SHARE = "SHARE" + SHIELD_PHONE = "SHIELD_PHONE" + SHOPPING = "SHOPPING" + SHOW_CHART = "SHOW_CHART" + SNOWFLAKE = "SNOWFLAKE" + STAR_BORDER = "STAR_BORDER" + STAR = "STAR" + STETHOSCOPE = "STETHOSCOPE" + STORE_OUTLINE = "STORE_OUTLINE" + STORE = "STORE" + SUNNY = "SUNNY" + SUPPORT_AGENT = "SUPPORT_AGENT" + SUPPORT = "SUPPORT" + TAG_CHECK_CIRCLE = "TAG_CHECK_CIRCLE" + TAXI = "TAXI" + TELEPHONE = "TELEPHONE" + TERMS = "TERMS" + TEXT_SMS_OUTLINE = "TEXT_SMS_OUTLINE" + TEXTURE = "TEXTURE" + THERMOMETER = "THERMOMETER" + TIMER = "TIMER" + TOC = "TOC" + TREES = "TREES" + TRENDING_UP = "TRENDING_UP" + TUNE = "TUNE" + VERIFIED_USER = "VERIFIED_USER" + VERIFIED = "VERIFIED" + VIDEOCAM = "VIDEOCAM" + VISIBILITY = "VISIBILITY" + VR = "VR" + WARNING = "WARNING" + WC = "WC" + BRAND_ALFA_ROMEO = "BRAND_ALFA_ROMEO" + BRAND_MERCEDESBENZ = "BRAND_MERCEDESBENZ" + BRAND_DONGFENG = "BRAND_DONGFENG" + POST_FEEDBACK = "POST_FEEDBACK" + PAYMENT_OUTLINE = "PAYMENT_OUTLINE" + CAMERA = "CAMERA" + CAMERA_O = "CAMERA_O" + VIDEOCAM_O = "VIDEOCAM_O" + ARCHWAY = "ARCHWAY" + CAR_INSPECTED = "CAR_INSPECTED" + CAR_INSPECTION = "CAR_INSPECTION" + CAT_BUSINESSES = "CAT_BUSINESSES" + CHART_O = "CHART_O" + CONTACT_PHONE_O = "CONTACT_PHONE_O" + FILE_O = "FILE_O" + FILE = "FILE" + IMAGE_OUTLINE_O = "IMAGE_OUTLINE_O" + INDICATOR = "INDICATOR" + MARKETPLACE_ELECTRONIC_DEVICES = "MARKETPLACE_ELECTRONIC_DEVICES" + MARKETPLACE_GENERAL = "MARKETPLACE_GENERAL" + MARKETPLACE_HOME = "MARKETPLACE_HOME" + MARKETPLACE_PERSONAL = "MARKETPLACE_PERSONAL" + PLACE_F = "PLACE_F" + POI = "POI" + PUZZLE_OUTLINE = "PUZZLE_OUTLINE" + PUZZLE = "PUZZLE" + SHIELD_PHONE_O = "SHIELD_PHONE_O" + STREET_SIGN = "STREET_SIGN" + VERIFIED_GREEN = "VERIFIED_GREEN" + WALLET = "WALLET" class Icon(BaseModel): diff --git a/kenar/oauth.py b/kenar/oauth.py index 06aa924..25710f7 100644 --- a/kenar/oauth.py +++ b/kenar/oauth.py @@ -1,26 +1,26 @@ from enum import Enum -from typing import Dict +from typing import Dict, Optional from pydantic import BaseModel class OauthResourceType(str, Enum): - UNKNOWN = 'UNKNOWN' - POST_ADDON_CREATE = 'POST_ADDON_CREATE' - USER_PHONE = 'USER_PHONE' - USER_ADDON_CREATE = 'USER_ADDON_CREATE' - CHAT_MESSAGE_SEND = 'CHAT_MESSAGE_SEND' - CHAT_CONVERSATION_READ = 'CHAT_CONVERSATION_READ' - USER_POSTS_GET = 'USER_POSTS_GET' - CHAT_POST_CONVERSATIONS_READ = 'CHAT_POST_CONVERSATIONS_READ' - CHAT_POST_CONVERSATIONS_MESSAGE_SEND = 'CHAT_POST_CONVERSATIONS_MESSAGE_SEND' - USER_VERIFICATION_CREATE = 'USER_VERIFICATION_CREATE' - OFFLINE_ACCESS = 'OFFLINE_ACCESS' + UNKNOWN = "UNKNOWN" + POST_ADDON_CREATE = "POST_ADDON_CREATE" + USER_PHONE = "USER_PHONE" + USER_ADDON_CREATE = "USER_ADDON_CREATE" + CHAT_MESSAGE_SEND = "CHAT_MESSAGE_SEND" + CHAT_CONVERSATION_READ = "CHAT_CONVERSATION_READ" + USER_POSTS_GET = "USER_POSTS_GET" + CHAT_POST_CONVERSATIONS_READ = "CHAT_POST_CONVERSATIONS_READ" + CHAT_POST_CONVERSATIONS_MESSAGE_SEND = "CHAT_POST_CONVERSATIONS_MESSAGE_SEND" + USER_VERIFICATION_CREATE = "USER_VERIFICATION_CREATE" + OFFLINE_ACCESS = "OFFLINE_ACCESS" - MANAGEMENT_APPS_READ = 'MANAGEMENT_APPS_READ' - MANAGEMENT_APPS_WRITE = 'MANAGEMENT_APPS_WRITE' + MANAGEMENT_APPS_READ = "MANAGEMENT_APPS_READ" + MANAGEMENT_APPS_WRITE = "MANAGEMENT_APPS_WRITE" - POST_ONGOING_IMAGES_GET = 'POST_ONGOING_IMAGES_GET' + POST_ONGOING_IMAGES_GET = "POST_ONGOING_IMAGES_GET" class AccessTokenResponse(BaseModel): @@ -38,6 +38,17 @@ class OAuthAccessTokenRequest(BaseModel): def dict(self, *args, **kwargs) -> Dict: object_dict = super().dict(*args, **kwargs) - object_dict['grant_type'] = 'authorization_code' + object_dict["grant_type"] = "authorization_code" return object_dict + + +class Scope(BaseModel): + resource_type: OauthResourceType + resource_id: Optional[str] = None + + +class SendChatMessageResourceIdParams(BaseModel): + user_id: str + post_token: str + peer_id: str diff --git a/kenar/request.py b/kenar/request.py index 032a7c0..353c99e 100644 --- a/kenar/request.py +++ b/kenar/request.py @@ -28,8 +28,10 @@ def wrapper_retry(*args, **kwargs): if retries > max_retries: error_details = response.text raise Exception( - f"HTTP error occurred: {e}. Error Detail: {error_details}") from None + f"HTTP error occurred: {e}. Error Detail: {error_details}" + ) from None time.sleep(delay) + return wrapper_retry return decorator_retry diff --git a/kenar/widgets/action.py b/kenar/widgets/action.py index a37e1ea..847db3a 100644 --- a/kenar/widgets/action.py +++ b/kenar/widgets/action.py @@ -2,10 +2,21 @@ def get_action(link: str) -> Dict: - return {"action": {"type": "LOAD_WEB_VIEW_PAGE", "fallback_link": link, - "payload": {"@type": "type.googleapis.com/widgets.LoadWebViewPagePayload", "url": link}} - } if len(link) > 0 else {} + return ( + { + "action": { + "type": "LOAD_WEB_VIEW_PAGE", + "fallback_link": link, + "payload": { + "@type": "type.googleapis.com/widgets.LoadWebViewPagePayload", + "url": link, + }, + } + } + if len(link) > 0 + else {} + ) def get_link_from_action(action: Dict) -> str: - return action['payload']['url'] + return action["payload"]["url"] diff --git a/kenar/widgets/color.py b/kenar/widgets/color.py index fd2199d..5c59328 100644 --- a/kenar/widgets/color.py +++ b/kenar/widgets/color.py @@ -2,17 +2,17 @@ class Color(Enum): - SUCCESS_PRIMARY = 'SUCCESS_PRIMARY' - SUCCESS_SECONDARY = 'SUCCESS_SECONDARY' - WARNING_PRIMARY = 'WARNING_PRIMARY' - WARNING_SECONDARY = 'WARNING_SECONDARY' - ERROR_PRIMARY = 'ERROR_PRIMARY' - TEXT_PRIMARY = 'TEXT_PRIMARY' - TEXT_SECONDARY = 'TEXT_SECONDARY' - TEXT_HINT = 'TEXT_HINT' - TEXT_DIVIDER = 'TEXT_DIVIDER' - ICON_PRIMARY = 'ICON_PRIMARY' - ICON_SECONDARY = 'ICON_SECONDARY' - ICON_HINT = 'ICON_HINT' - ICON_DIVIDER = 'ICON_DIVIDER' - WHITE_PRIMARY = 'WHITE_PRIMARY' + SUCCESS_PRIMARY = "SUCCESS_PRIMARY" + SUCCESS_SECONDARY = "SUCCESS_SECONDARY" + WARNING_PRIMARY = "WARNING_PRIMARY" + WARNING_SECONDARY = "WARNING_SECONDARY" + ERROR_PRIMARY = "ERROR_PRIMARY" + TEXT_PRIMARY = "TEXT_PRIMARY" + TEXT_SECONDARY = "TEXT_SECONDARY" + TEXT_HINT = "TEXT_HINT" + TEXT_DIVIDER = "TEXT_DIVIDER" + ICON_PRIMARY = "ICON_PRIMARY" + ICON_SECONDARY = "ICON_SECONDARY" + ICON_HINT = "ICON_HINT" + ICON_DIVIDER = "ICON_DIVIDER" + WHITE_PRIMARY = "WHITE_PRIMARY" diff --git a/kenar/widgets/description_row.py b/kenar/widgets/description_row.py index 5eb3c72..ca1dc37 100644 --- a/kenar/widgets/description_row.py +++ b/kenar/widgets/description_row.py @@ -14,22 +14,25 @@ class DescriptionRow(BaseModel, BaseWidget): padded: bool = False preview_max_line: int = 0 - @model_validator(mode='after') + @model_validator(mode="after") def check_preview_max_line(self) -> Self: expandable_ = self.expandable preview_max_line_ = self.preview_max_line if expandable_ is False and preview_max_line_ > 0: - raise ValueError('Can not set preview_max_line when field expandable is set to False') + raise ValueError( + "Can not set preview_max_line when field expandable is set to False" + ) return self def serialize_model(self) -> dict: return { "widget_type": "DESCRIPTION_ROW", - "data": {"@type": "type.googleapis.com/widgets.DescriptionRowData"} | self.model_dump(), + "data": {"@type": "type.googleapis.com/widgets.DescriptionRowData"} + | self.model_dump(), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/evaluation_row.py b/kenar/widgets/evaluation_row.py index 342b0b1..a073917 100644 --- a/kenar/widgets/evaluation_row.py +++ b/kenar/widgets/evaluation_row.py @@ -24,22 +24,22 @@ class Section(BaseModel): middle: Section right: Section - @field_validator('indicator_percentage') + @field_validator("indicator_percentage") @classmethod def check_indicator_percentage(cls, indicator_percentage: int) -> int: if indicator_percentage < 0 or indicator_percentage > 100: - raise ValueError('Field indicator_percentage should be in range [0,100]') + raise ValueError("Field indicator_percentage should be in range [0,100]") return indicator_percentage def serialize_model(self) -> dict: return { "widget_type": "EVALUATION_ROW", - "data": {"@type": "type.googleapis.com/widgets.EvaluationRowData"} | - self.model_dump() + "data": {"@type": "type.googleapis.com/widgets.EvaluationRowData"} + | self.model_dump(), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/event_row.py b/kenar/widgets/event_row.py index 4c8bcb6..a70fded 100644 --- a/kenar/widgets/event_row.py +++ b/kenar/widgets/event_row.py @@ -10,28 +10,28 @@ class EventRow(BaseModel, BaseWidget): title: str - subtitle: str = '' + subtitle: str = "" has_indicator: bool = False - image_url: str = '' - label: str = '' + image_url: str = "" + label: str = "" has_divider: bool = False - link: str = '' + link: str = "" padded: bool = False icon: Icon def serialize_model(self) -> dict: return { "widget_type": "EVENT_ROW", - "data": {"@type": "type.googleapis.com/widgets.EventRowData"} | - self.dict(exclude={'link'}) | - get_action(link=self.link) + "data": {"@type": "type.googleapis.com/widgets.EventRowData"} + | self.dict(exclude={"link"}) + | get_action(link=self.link), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) - if 'action' in widget_data: - widget_data['link'] = get_link_from_action(widget_data['action']) - widget_data.pop('action', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) + if "action" in widget_data: + widget_data["link"] = get_link_from_action(widget_data["action"]) + widget_data.pop("action", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/group_info_row.py b/kenar/widgets/group_info_row.py index f8a694c..ea361cf 100644 --- a/kenar/widgets/group_info_row.py +++ b/kenar/widgets/group_info_row.py @@ -13,23 +13,21 @@ class GroupInfoItem(BaseModel): items: List[GroupInfoItem] has_divider: bool = False - - @field_validator('items') + @field_validator("items") @classmethod def check_items_length(cls, items: List[GroupInfoItem]) -> List[GroupInfoItem]: if not 1 < len(items) < 4: - raise ValueError('Number of items in GroupInfo should be 2 or 3') + raise ValueError("Number of items in GroupInfo should be 2 or 3") return items def serialize_model(self) -> dict: return { "widget_type": "GROUP_INFO_ROW", - "data": {"@type": "type.googleapis.com/widgets.GroupInfoRow"} | - self.dict() + "data": {"@type": "type.googleapis.com/widgets.GroupInfoRow"} | self.dict(), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/legend_title_row.py b/kenar/widgets/legend_title_row.py index 98cc9af..65f57eb 100644 --- a/kenar/widgets/legend_title_row.py +++ b/kenar/widgets/legend_title_row.py @@ -10,9 +10,9 @@ class LegendTitleRow(BaseModel, BaseWidget): class Tag(BaseModel): class BackgroundColor(str, Enum): - TRANSPARENT = 'TRANSPARENT' - GRAY = 'GRAY' - RED = 'RED' + TRANSPARENT = "TRANSPARENT" + GRAY = "GRAY" + RED = "RED" text: str icon: Icon @@ -27,11 +27,12 @@ class BackgroundColor(str, Enum): def serialize_model(self) -> dict: return { "widget_type": "LEGEND_TITLE_ROW", - "data": {"@type": "type.googleapis.com/widgets.LegendTitleRowData"} | self.dict() + "data": {"@type": "type.googleapis.com/widgets.LegendTitleRowData"} + | self.dict(), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/score_row.py b/kenar/widgets/score_row.py index d2c6e78..8802f17 100644 --- a/kenar/widgets/score_row.py +++ b/kenar/widgets/score_row.py @@ -20,26 +20,30 @@ class ScoreRow(BaseModel, BaseWidget): has_divider: bool = False icon: Icon = None - @model_validator(mode='after') + @model_validator(mode="after") def check_score(self) -> Self: - filled_descriptive_score = self.descriptive_score is not None and len(self.descriptive_score) > 0 + filled_descriptive_score = ( + self.descriptive_score is not None and len(self.descriptive_score) > 0 + ) if filled_descriptive_score == bool(self.percentage_score): - raise ValueError('Exactly one of descriptive_score or percentage_score must be set') + raise ValueError( + "Exactly one of descriptive_score or percentage_score must be set" + ) return self def serialize_model(self) -> dict: return { "widget_type": "SCORE_ROW", - "data": {"@type": "type.googleapis.com/widgets.ScoreRowData"} | - self.dict(exclude={'link'}) | - get_action(link=self.link) + "data": {"@type": "type.googleapis.com/widgets.ScoreRowData"} + | self.dict(exclude={"link"}) + | get_action(link=self.link), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) - if 'action' in widget_data: - widget_data['link'] = get_link_from_action(widget_data['action']) - widget_data.pop('action', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) + if "action" in widget_data: + widget_data["link"] = get_link_from_action(widget_data["action"]) + widget_data.pop("action", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/selector_row.py b/kenar/widgets/selector_row.py index 62dd879..95b9a02 100644 --- a/kenar/widgets/selector_row.py +++ b/kenar/widgets/selector_row.py @@ -22,17 +22,17 @@ class SelectorRow(BaseModel, BaseWidget): def serialize_model(self) -> dict: return { "widget_type": "SELECTOR_ROW", - "data": {"@type": "type.googleapis.com/widgets.SelectorRowData"} | - self.dict(exclude={'link'}) | - {"small": True} | - get_action(link=self.link) + "data": {"@type": "type.googleapis.com/widgets.SelectorRowData"} + | self.dict(exclude={"link"}) + | {"small": True} + | get_action(link=self.link), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) - if 'action' in widget_data: - widget_data['link'] = get_link_from_action(widget_data['action']) - widget_data.pop('action', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) + if "action" in widget_data: + widget_data["link"] = get_link_from_action(widget_data["action"]) + widget_data.pop("action", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/subtitle_row.py b/kenar/widgets/subtitle_row.py index 7ee9117..6d16813 100644 --- a/kenar/widgets/subtitle_row.py +++ b/kenar/widgets/subtitle_row.py @@ -12,11 +12,12 @@ class SubtitleRow(BaseModel, BaseWidget): def serialize_model(self) -> dict: return { "widget_type": "SUBTITLE_ROW", - "data": {"@type": "type.googleapis.com/widgets.SubtitleRowData"} | self.dict() + "data": {"@type": "type.googleapis.com/widgets.SubtitleRowData"} + | self.dict(), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/title_row.py b/kenar/widgets/title_row.py index b3a22b7..7533e70 100644 --- a/kenar/widgets/title_row.py +++ b/kenar/widgets/title_row.py @@ -13,11 +13,12 @@ class TitleRow(BaseModel, BaseWidget): def serialize_model(self) -> dict: return { "widget_type": "TITLE_ROW", - "data": {"@type": "type.googleapis.com/widgets.TitleRowData"} | self.model_dump() + "data": {"@type": "type.googleapis.com/widgets.TitleRowData"} + | self.model_dump(), } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) return cls.parse_obj(widget_data) diff --git a/kenar/widgets/wide_button_bar.py b/kenar/widgets/wide_button_bar.py index b4bd99e..be7afb0 100644 --- a/kenar/widgets/wide_button_bar.py +++ b/kenar/widgets/wide_button_bar.py @@ -13,14 +13,14 @@ class Button(BaseModel): @model_serializer def ser_model(self) -> dict: - return {'title': self.title} | get_action(link=self.link) + return {"title": self.title} | get_action(link=self.link) - @model_validator(mode='before') + @model_validator(mode="before") @classmethod def deserialize_button(cls, data: Dict) -> Dict: - if 'action' in data: - data['link'] = get_link_from_action(data.get('action', {})) - data.pop('action', None) + if "action" in data: + data["link"] = get_link_from_action(data.get("action", {})) + data.pop("action", None) return data button: Button @@ -28,12 +28,13 @@ def deserialize_button(cls, data: Dict) -> Dict: def serialize_model(self) -> dict: return { "widget_type": "WIDE_BUTTON_BAR", - "data": {"@type": "type.googleapis.com/widgets.WideButtonBarWidgetData"} | - self.dict(exclude={'style'}) | {'style': 'SECONDARY'} + "data": {"@type": "type.googleapis.com/widgets.WideButtonBarWidgetData"} + | self.dict(exclude={"style"}) + | {"style": "SECONDARY"}, } @classmethod def deserialize_model(cls, data: Dict): - widget_data = data.get('data', {}) - widget_data.pop('@type', None) + widget_data = data.get("data", {}) + widget_data.pop("@type", None) return cls.parse_obj(widget_data) diff --git a/samples/sample_addon.py b/samples/sample_addon.py index 989ed9f..8898e4f 100644 --- a/samples/sample_addon.py +++ b/samples/sample_addon.py @@ -1,13 +1,12 @@ -from kenar.addon import ( +from kenar import ( CreatePostAddonRequest, GetUserAddonsRequest, DeleteUserAddonRequest, GetPostAddonsRequest, DeletePostAddonRequest, CreateUserAddonRequest, -) -from kenar.icons import IconName, Icon -from kenar.widgets import ( + IconName, + Icon, TitleRow, SubtitleRow, SelectorRow, @@ -145,7 +144,7 @@ resp = app.addon.create_post_addon( access_token="ACCESS_TOKEN_HERE", data=CreatePostAddonRequest( - token="gZW5uQcs", + token="POST_TOKEN_HERE", widgets=[ title_row, subtitle_row, @@ -160,13 +159,15 @@ ) print(resp) - resp = app.addon.get_post_addons(data=GetPostAddonsRequest(token="gZW5uQcs")) + resp = app.addon.get_post_addons(data=GetPostAddonsRequest(token="POST_TOKEN_HERE")) print(resp) - resp = app.addon.delete_post_addon(data=DeletePostAddonRequest(token="gZW5uQcs")) + resp = app.addon.delete_post_addon( + data=DeletePostAddonRequest(token="POST_TOKEN_HERE") + ) print(resp) - resp = app.addon.get_post_addons(data=GetPostAddonsRequest(token="gZW5uQcs")) + resp = app.addon.get_post_addons(data=GetPostAddonsRequest(token="POST_TOKEN_HERE")) print(resp) resp = app.addon.create_user_addon( diff --git a/samples/sample_app.py b/samples/sample_app.py index 714a701..81ce18b 100644 --- a/samples/sample_app.py +++ b/samples/sample_app.py @@ -3,16 +3,17 @@ from dotenv import load_dotenv -from kenar.app import AppConfig, KenarApp +from kenar import AppConfig, KenarApp load_dotenv() logging.basicConfig(level=logging.INFO) -app_conf = AppConfig(app_slug=os.environ.get("KENAR_APP_SLUG"), - api_key=os.environ.get("KENAR_API_KEY"), - oauth_secret=os.environ.get("KENAR_OAUTH_SECRET"), - oauth_redirect_url=os.environ.get("KENAR_OAUTH_REDIRECT_URL"), - ) +app_conf = AppConfig( + app_slug=os.environ.get("KENAR_APP_SLUG"), + api_key=os.environ.get("KENAR_API_KEY"), + oauth_secret=os.environ.get("KENAR_OAUTH_SECRET"), + oauth_redirect_url=os.environ.get("KENAR_OAUTH_REDIRECT_URL"), +) app = KenarApp(app_conf) diff --git a/samples/sample_chat.py b/samples/sample_chat.py index 0956269..e8fecef 100644 --- a/samples/sample_chat.py +++ b/samples/sample_chat.py @@ -1,25 +1,43 @@ -from kenar.chatmessage import SendMessageV2Request, BotButton, SetNotifyChatPostConversationsRequest +from kenar import ( + SendMessageV2Request, + BotButton, + SetNotifyChatPostConversationsRequest, +) from samples.sample_app import app -if __name__ == '__main__': +if __name__ == "__main__": app.chat.send_message( data=SendMessageV2Request( - user_id='USER_UUID', - peer_id='PEER_UUID', - post_token='gZ6QmeWD', - type='TEXT', - message='سلام این پیام تستی است', + user_id="USER_UUID", + peer_id="PEER_UUID", + post_token="gZ6QmeWD", + type="TEXT", + message="سلام این پیام تستی است", sender_btn=BotButton( - data=BotButton.ButtonData(icon_name='SEND', caption='direct link', direct_link='https://divar.ir'), - action=BotButton.Action.DIRECT_LINK), + data=BotButton.ButtonData( + icon_name="SEND", + caption="direct link", + direct_link="https://divar.ir", + ), + action=BotButton.Action.DIRECT_LINK, + ), receiver_btn=BotButton( - data=BotButton.ButtonData(icon_name='DELETE', caption='dynamic link', direct_link='https://divar2.ir'), - action=BotButton.Action.LINK) - + data=BotButton.ButtonData( + icon_name="DELETE", + caption="dynamic link", + direct_link="https://divar2.ir", + ), + action=BotButton.Action.LINK, + ), ), - access_token='ACCESS_TOKEN_HERE') + access_token="ACCESS_TOKEN_HERE", + ) app.chat.set_notify_chat_post_conversations( - data=SetNotifyChatPostConversationsRequest(post_token='gZ6QmeWD', endpoint='https://test2.com', - identification_key='thest-identification-key'), - access_token='ACCESS_TOKEN_HERE') + data=SetNotifyChatPostConversationsRequest( + post_token="gZ6QmeWD", + endpoint="https://test2.com", + identification_key="thest-identification-key", + ), + access_token="ACCESS_TOKEN_HERE", + ) diff --git a/samples/sample_finder.py b/samples/sample_finder.py index b85a448..a14a502 100644 --- a/samples/sample_finder.py +++ b/samples/sample_finder.py @@ -1,24 +1,32 @@ -from kenar.finder import SearchPostRequest, GetUserRequest, GetUserPostsRequest, GetPostRequest +from kenar import ( + SearchPostRequest, + GetUserRequest, + GetUserPostsRequest, + GetPostRequest, +) from samples.sample_app import app -if __name__ == '__main__': - resp = app.finder.get_post(GetPostRequest(token='wYIw8OJp')) +if __name__ == "__main__": + resp = app.finder.get_post(GetPostRequest(token="wYIw8OJp")) print(resp) resp = app.finder.search_post( - SearchPostRequest(city='tehran', category='light', districts=['abshar', 'nazi-abad'], query={ - 'brand_model': { - 'value': ["Pride 111 EX", "MVM 110"] + SearchPostRequest( + city="tehran", + category="light", + districts=["abshar", "nazi-abad"], + query={ + "brand_model": {"value": ["Pride 111 EX", "MVM 110"]}, + "production-year": {"min": 1385, "max": 1390}, }, - 'production-year': { - 'min': 1385, - 'max': 1390 - } - })) + ) + ) print(resp) - resp = app.finder.get_user(data=GetUserRequest(), access_token='ACCESS_TOKEN_HERE') + resp = app.finder.get_user(data=GetUserRequest(), access_token="ACCESS_TOKEN_HERE") print(resp) - resp = app.finder.get_user_posts(data=GetUserPostsRequest(), access_token='ACCESS_TOKEN_HERE') + resp = app.finder.get_user_posts( + data=GetUserPostsRequest(), access_token="ACCESS_TOKEN_HERE" + ) print(resp) diff --git a/samples/sample_oauth.py b/samples/sample_oauth.py index ef62a0e..770dabb 100644 --- a/samples/sample_oauth.py +++ b/samples/sample_oauth.py @@ -1,28 +1,33 @@ import httpx -from kenar.oauth import OauthResourceType -from kenar.app import Scope, SendChatMessageResourceIdParams +from kenar import OauthResourceType, Scope, SendChatMessageResourceIdParams from samples.sample_app import app - -if __name__ == '__main__': +if __name__ == "__main__": try: - state = '348656686' - scopes = [Scope(resource_type=OauthResourceType.POST_ADDON_CREATE, resource_id='POST_TOKEN_HERE'), - Scope(resource_type=OauthResourceType.USER_ADDON_CREATE), - Scope(resource_type=OauthResourceType.USER_POSTS_GET), - Scope(resource_type=OauthResourceType.USER_PHONE), - Scope(resource_type=OauthResourceType.CHAT_MESSAGE_SEND, - resource_id=app.oauth.get_send_message_resource_id( - SendChatMessageResourceIdParams(user_id='USER_UUID', - peer_id='PEER_UUID', - post_token='POST_TOKEN_HERE')), - ), - ] + state = "348656686" + scopes = [ + Scope( + resource_type=OauthResourceType.POST_ADDON_CREATE, + resource_id="POST_TOKEN_HERE", + ), + Scope(resource_type=OauthResourceType.USER_ADDON_CREATE), + Scope(resource_type=OauthResourceType.USER_POSTS_GET), + Scope(resource_type=OauthResourceType.USER_PHONE), + Scope( + resource_type=OauthResourceType.CHAT_MESSAGE_SEND, + resource_id=app.oauth.get_send_message_resource_id( + SendChatMessageResourceIdParams( + user_id="USER_UUID", + peer_id="PEER_UUID", + post_token="POST_TOKEN_HERE", + ) + ), + ), + ] print(app.oauth.get_oauth_redirect(scopes=scopes, state=state)) - code = input('code here') + code = input("code here") print(app.oauth.get_access_token(authorization_token=code)) except (httpx.HTTPStatusError, httpx.RequestError) as e: print(e) -