diff --git a/examples/simple_auth.py b/examples/simple_auth.py new file mode 100644 index 0000000..8001ec2 --- /dev/null +++ b/examples/simple_auth.py @@ -0,0 +1,19 @@ +from gitflic import Gitflic, GitflicAuth + +# Your authentication token. +# See: https://gitflic.ru/settings/oauth/token/create +token = "token_here" + +# Creating authorized session with our token. +gf_session = GitflicAuth(token) +gf = Gitflic(gf_session) + + +def main(): + # Call method to get authorized user from API. + user_me = gf.call("/user/me") + print(user_me) + + +if __name__ == '__main__': + main() diff --git a/gitflic/__version__.py b/gitflic/__version__.py index dddd5c4..ddb13d4 100644 --- a/gitflic/__version__.py +++ b/gitflic/__version__.py @@ -1,5 +1,5 @@ __title__ = "gitflic" -__version__ = "0.9" +__version__ = "0.10" __description__ = "GitflicApi wrapper" __author__ = "SantaSpeen" __author_email__ = "dir@sssr.dev" diff --git a/gitflic/api.py b/gitflic/api.py index f344717..2fe4d02 100644 --- a/gitflic/api.py +++ b/gitflic/api.py @@ -1,38 +1,61 @@ +""" +Main Gitflic API wrapper. +""" + +from enum import Enum + from .auth import GitflicAuth -from .exceptions import NotFound, NoRights, GitflicExceptions +from .exceptions import ( + NotFound, NoRights, GitflicExceptions +) + API_URL = 'https://api.gitflic.ru' +class GitflicAPIMethods(Enum): + """ Methods that you may use for calling API. """ + USER_ME = "/user/me" + USER = "/user" + # There is not all methods, please expand if you need some other method. + + class Gitflic: + """ + Gitflic API wrapper. + """ def __init__(self, gf_session: GitflicAuth): """ - - :param gf_session: + :param gf_session: Authorized session from GitflicAuth. """ self.session = gf_session.session @staticmethod def _response_handler(response): + """ + Handles HTTP response from Gitflic API. + :param response: HTTP response. + :return: Exception or valid JSON. + """ code = response.status_code + if code == 200: return response.json() + url = response.url if code == 403: - raise NoRights(f"No rights for '{url}'") + raise NoRights(f"Access denied for '{url}'") elif code == 404: - raise NotFound(f"Response '{url}' not found") + raise NotFound(f"Location '{url}' not found") - raise GitflicExceptions(f"Gitflic send error: {code}. {response.text}") + raise GitflicExceptions(f"Gitflic sent unknown error with HTTP code: {code}. Response: {response.text}") - def call(self, method, *args, **kwargs): + def call(self, method: str, *args, **kwargs): """ - - :param method: - :param args: - :param kwargs: - :return: + Calls API method on server side. + :param method: API method of Gitflic to call. + :return: Exception or valid JSON. """ response = self.session.get(API_URL + method, *args, **kwargs) return self._response_handler(response) diff --git a/gitflic/auth.py b/gitflic/auth.py index 4e1f3de..3e9360b 100644 --- a/gitflic/auth.py +++ b/gitflic/auth.py @@ -1,17 +1,21 @@ +""" +Gitflic authentication wrapper. +""" + from enum import Enum -import logging from typing import Union -import webbrowser -import urllib.parse +import logging import requests from .exceptions import AuthError, GitflicExceptions -oauth_url = "https://oauth.gitflic.ru/oauth/authorize?scope={}&clientId={}&redirectUrl={}&state={}" + +OAUTH_URL = "https://oauth.gitflic.ru/oauth/authorize?scope={}&clientId={}&redirectUrl={}&state={}" class GitflicAuthScopes(Enum): + """ Authentication scopes from Gitflic. """ USER_READ = "USER_READ" USER_WRITE = "USER_WRITE" PROJECT_READ = "PROJECT_READ" @@ -22,7 +26,10 @@ class GitflicAuthScopes(Enum): class GitflicAuth: - + """ + Gitflic authentication wrapper. + """ + # noinspection PyTypeChecker def __init__(self, access_token: str = None, @@ -31,67 +38,97 @@ class GitflicAuth: redirect_url: str = None, state: str = None): """ - - :param access_token: - :param scope: - :param client_id: - :param redirect_url: + :param access_token: Raw token for raw AUTH. + :param scope: OAUTH field. + :param client_id: OAUTH field. + :param redirect_url: OAUTH field. + :param state: OAUTH field. """ + # Logging. self.log: logging.Logger = logging.getLogger(__name__) + # Requests. self.session: requests.Session = requests.Session() + # Auth. + + # Token fields. self.access_token: str = access_token + # OAUTH fields. self.scope: str = scope if not isinstance(scope, GitflicAuthScopes) else scope.value self.client_id: str = client_id self.redirect_url: str = redirect_url - self.state = state - + self.state: str = state self.refresh_token: str = None - if any((access_token, scope, client_id, redirect_url, state)): - if access_token: - pass - elif not (scope and client_id and redirect_url, state): - raise GitflicExceptions( - "Cannot auth without 'scope', 'client_id', 'redirect_url', 'state' parameters. " - "See doc: https://gitflic.ru/help/api/access-token." - ) + self._try_login() + + def _try_login(self): + """ + Tries to login user with token or OAUTH. + """ + if self.access_token: + # Raw authorization. + self._token_login() else: - raise GitflicExceptions( - "Cannot auth without 'token' or 'scope' and 'client_id' and 'redirect_url' and 'state' parameters. " - "See doc: https://gitflic.ru/help/api/access-token." - ) + if self.scope and self.client_id and self.redirect_url and self.state: + # OAUTH authorization. + self._oauth_login() + else: + if any(self.scope, self.client_id, self.redirect_url, self.state): + raise GitflicExceptions( + "Not found one of params for OAUTH, you are required to send ALL params from ('scope', 'client_id', 'redirect_url', 'state')!" + "See docs: https://gitflic.ru/help/api/access-token." + ) + raise GitflicExceptions( + "Please pass 'token' param for raw auth or ('scope', 'client_id', 'redirect_url', 'state') params for OAUTH " + "See docs: https://gitflic.ru/help/api/access-token." + ) + + def _oauth_login(self): + """ + Tries to login user with OAUTH. + """ + + self.log.debug("Trying to login with OAUTH...") - self._login() + # OAUTH authorization. + raise GitflicExceptions("OAUTH not implemented yet! Use raw access_token authorization.") - def _login(self): - self.log.debug("Trying to login.") + # redirect_url = urllib.parse.quote_plus(self.redirect_url) + # webbrowser.open(OAUTH_URL.format(self.scope, self.client_id, redirect_url, self.state)) + # url = input("Paste redirect url: ") + # r = self.session.get("").json() + # print(r) + # self.session.headers.update({"Authorization": "token " + "null"}) + # self.check_token() + + def _token_login(self): + """ + Tries to login user with given access token. + """ + + self.log.debug("Trying to login with token...") if self.access_token: - self.session.headers.update({"Authorization": "token " + self.access_token}) - else: - - raise GitflicExceptions("Oauth not ready. Use access_token.") - - # redirect_url = urllib.parse.quote_plus(self.redirect_url) - # webbrowser.open(oauth_url.format(self.scope, self.client_id, redirect_url, self.state)) - # url = input("Paste redirect url: ") - # r = self.session.get("").json() - # print(r) - - # self.session.headers.update({"Authorization": "token " + "null"}) + self.session.headers.update({ + "Authorization": "token " + self.access_token + }) self.check_token() - + def check_token(self): - self.log.debug("Check token.") + """ + Checks that current auth session token is valid or not (by making request to get current user). + """ + + self.log.debug("Checking token....") r = self.session.get("https://api.gitflic.ru/user/me") if r.status_code == 403: - raise AuthError("Authentication failed.") + raise AuthError("Authentication failed. Invalid token?") else: r = r.json() - self.log.debug(f"Logged as {r.get('username')} {r.get('id')}") + self.log.debug(f"Successfully logged as {r.get('username')} {r.get('id')}") diff --git a/gitflic/exceptions.py b/gitflic/exceptions.py index 44fe072..9cbd0f8 100644 --- a/gitflic/exceptions.py +++ b/gitflic/exceptions.py @@ -1,3 +1,7 @@ +""" +All exceptions that may be raised from Gitflic API wrapper. +""" + class GitflicExceptions(Exception): error_code: int = 1 reason: str = None @@ -12,8 +16,8 @@ class AuthError(GitflicExceptions): class NoRights(GitflicExceptions): error_code = 403 - reason = "Нет прав для доступа." - reason_ru = "There are no access rights." + reason = "There are no access rights." + reason_ru = "Нет прав для доступа." class NotFound(GitflicExceptions):