diff --git a/vue-apps-py/src/vue_apps_py/client.py b/vue-apps-py/src/vue_apps_py/client.py index d5d2957..5a6b28e 100644 --- a/vue-apps-py/src/vue_apps_py/client.py +++ b/vue-apps-py/src/vue_apps_py/client.py @@ -4,7 +4,11 @@ from typing import Optional, Any, Dict from oauthlib.oauth2 import BackendApplicationClient from requests_oauthlib import OAuth2Session -vue_apps_url: str = 'https://apps-vue.ru' +from .models import PongModel, PostModel + +oauth_url: str = 'https://sso.arbina.com/oauth' +vue_client_url: str = 'https://vue-client-api.arbina.com' +vue_interact_url: str = 'https://vue-app-interaction-api.arbina.com' class ClientAPI: @@ -12,12 +16,16 @@ class ClientAPI: client_secret: str token: Optional[Any] session: OAuth2Session - endpoints: Dict[str, str] = {'access': '/auth', 'refresh': '/refresh', 'ping': '/ping'} + endpoints: Dict[str, str] = {'create': '/api/pages/{page_id}/posts', 'remove': '/api/posts/{post_id}', + 'ping': f'{vue_interact_url}/api/app/interactions/ping', 'token': f'{oauth_url}/token'} def build_url(self, endpoint: str) -> str: - return f'{self.vue_apps_url}{self.endpoints[endpoint]}' + if self.endpoints[endpoint].startswith('/'): + return f'{self.vue_apps_url}{self.endpoints[endpoint]}' + else: + return self.endpoints[endpoint] - def __init__(self, client_id: str, client_secret: str, vue_url: str = vue_apps_url): + def __init__(self, client_id: str, client_secret: str, vue_url: str = vue_client_url): """ Constructor of Vue Apps Client API @@ -32,7 +40,7 @@ class ClientAPI: self.client_secret = client_secret oauth = OAuth2Session(client=BackendApplicationClient(client_id=self.client_id)) - client_token = oauth.fetch_token(token_url=self.build_url('access'), client_id=self.client_id, + client_token = oauth.fetch_token(token_url=self.build_url('token'), client_id=self.client_id, client_secret=self.client_secret) self.token = client_token @@ -49,7 +57,7 @@ class ClientAPI: auto_refresh_info = {'client_id': self.client_id, 'client_secret': self.client_secret} self.session = OAuth2Session(token=self.token, client_id=self.client_id, - auto_refresh_url=self.build_url('refresh'), + auto_refresh_url=self.build_url('token'), auto_refresh_kwargs=auto_refresh_info, token_updater=save_token) def acquire_token(self) -> Optional[Any]: @@ -59,6 +67,16 @@ class ClientAPI: """ return self.session.access_token + def ping_server(self) -> Optional[PongModel]: + query_url = self.build_url('ping') + response = self.session.get(query_url) + + if response.status_code != 200: + return None + + model = response.json() + return PongModel(ping_ttl_seconds=model['ping_ttl_seconds']) + def refresh_token(self) -> bool: """ Forces token to be refreshed and sends requests to /ping @@ -66,5 +84,9 @@ class ClientAPI: """ self.token['expires_at'] = time() - 10 self.session.token = self.token - response = self.session.get(self.build_url('ping')) - return response.status_code == 200 + pong = self.ping_server() + return pong is not None + + def create_post(self, post: PostModel) -> bool: + url = self.build_url('/create').format(page_id=post.page_uin) + return True diff --git a/vue-apps-py/src/vue_apps_py/models.py b/vue-apps-py/src/vue_apps_py/models.py index 34ff4e7..6e99faa 100644 --- a/vue-apps-py/src/vue_apps_py/models.py +++ b/vue-apps-py/src/vue_apps_py/models.py @@ -1,15 +1,12 @@ -from typing import Optional - from pydantic import BaseModel, Field -class PingModel(BaseModel): - nickname: str = Field(title='Nickname', description="Vue App's nickname to use at service") - - class PongModel(BaseModel): - message: str = Field(default='pong', title='Message', description='Message answered on pings') - token: Optional[str] = Field(default=None, title='Token', description='Token for API to check') + ping_ttl_seconds: int = Field(default='pong', title='Time To Live', description='Time To Live of the ping') + + +class PostModel(BaseModel): + page_uin: str = Field(title='Page Author', description='ID of page that published the post') class AutoModel(BaseModel): diff --git a/vue-apps-py/src/vue_apps_py/server.py b/vue-apps-py/src/vue_apps_py/server.py index abf95d7..82ba6b3 100644 --- a/vue-apps-py/src/vue_apps_py/server.py +++ b/vue-apps-py/src/vue_apps_py/server.py @@ -3,7 +3,7 @@ from typing import Dict, List from fastapi import FastAPI, Request, HTTPException, status from .client import ClientAPI -from .models import AutoModel, InteractionModel, MentionModel, PageModel, PongModel, SuggestionsModel +from .models import AutoModel, InteractionModel, MentionModel, PageModel, SuggestionsModel from .server_utils.intents import Intent, PageApp, InlineQuery, PageMentions, Interactions from .server_utils.security import SecurityHelper @@ -31,24 +31,19 @@ def VueApp(client_api: ClientAPI, if not security_helper.is_valid(timestamped_body=timestamp + body_to_verify, signature=signature): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail='Verification of signature failed') - @app.post(path='/ping', response_model=PongModel) - async def handle_ping(request: Request) -> PongModel: - await check_request(request) - return PongModel(message='pong', token=client_api.get_token()) - if PageApp.intent_name in named_intents and isinstance(named_intents[PageApp.intent_name], PageApp): page_app_intent: PageApp = named_intents[PageApp.intent_name] start_handler = page_app_intent.added_page_handler stop_handler = page_app_intent.removed_page_handler - @app.post(path='/start', status_code=status.HTTP_201_CREATED) + @app.post(path='/interactions/pages/add', status_code=status.HTTP_202_ACCEPTED) async def handle_integration(request: Request, model: PageModel): await check_request(request) acknowledged = start_handler(model) if not acknowledged: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST) - @app.post(path='/stop', status_code=status.HTTP_204_NO_CONTENT) + @app.post(path='/interactions/pages/remove', status_code=status.HTTP_202_ACCEPTED) async def handle_disconnect(request: Request, model: PageModel): await check_request(request) acknowledged = stop_handler(model) @@ -59,7 +54,7 @@ def VueApp(client_api: ClientAPI, inline_query_intent: InlineQuery = named_intents[InlineQuery.intent_name] auto_handler = inline_query_intent.query_handler - @app.post(path='/auto', response_model=SuggestionsModel) + @app.post(path='/interactions/inline-query', response_model=SuggestionsModel) async def handle_autocomplete(request: Request, model: AutoModel) -> SuggestionsModel: await check_request(request) return auto_handler(model) @@ -68,7 +63,7 @@ def VueApp(client_api: ClientAPI, page_mentions_intent: PageMentions = named_intents[PageMentions.intent_name] mentions_handler = page_mentions_intent.query_handler - @app.post(path='/mention', status_code=status.HTTP_202_ACCEPTED) + @app.post(path='/interactions/pages/mention', status_code=status.HTTP_202_ACCEPTED) async def handle_mentions(request: Request, model: MentionModel): await check_request(request) acknowledged = mentions_handler(model) @@ -79,7 +74,7 @@ def VueApp(client_api: ClientAPI, interactions_intent: Interactions = named_intents[Interactions.intent_name] interactions_handler = interactions_intent.query_handler - @app.post(path='/interact', status_code=status.HTTP_202_ACCEPTED) + @app.post(path='/interactions/posts/interact', status_code=status.HTTP_202_ACCEPTED) async def handle_interactions(request: Request, model: InteractionModel): await check_request(request) acknowledged = interactions_handler(model)