Skip to content

Commit

Permalink
Added Decorator support
Browse files Browse the repository at this point in the history
  • Loading branch information
Shritesh99 committed Nov 23, 2023
1 parent 4aa833b commit 1463f92
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 35 deletions.
15 changes: 15 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,20 @@ class SocialAuthMixin(BaseMixin)
> Social Auth takes OAuth Provider and OAuth Access Token
>
> Allow user to perform social auth for the given OAuth provider and OAuth Access token
> :returns
> user: Entire User Object (Get your social data using user.social_user)
> errors: Any error occurred in the process of getting the Social User

## social\_auth

```python
def social_auth(f)
```

> Decorator for Getting social User. Use this decorator if you want to customize the SocialAuthMixin.
> :param f: Input: SocialAuthInput(provider, accessToken)
> :return: function with two additional arguments
> user: Entire User Object (Get your social data using user.social_user)
> errors: Any error occurred in the process of getting the Social User

3 changes: 1 addition & 2 deletions docs/pre_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@
for index, file in enumerate(files):
shutil.copyfile(root_dir / file, root_dir / "docs" / dest[index])

print(src)
context = Context(directory=str(src))
loader = PythonLoader(
search_path=[str(src)],
modules=[
"mixins",
"mixins", "decorators"
],
)
renderer = MarkdownRenderer(
Expand Down
2 changes: 1 addition & 1 deletion gql_social_auth/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.1.0"
__version__ = "0.2.0"
60 changes: 60 additions & 0 deletions gql_social_auth/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from functools import wraps
from promise import Promise, is_thenable

from strawberry.types import Info
from social_django.utils import load_backend, load_strategy
from social_core.exceptions import MissingBackend
from gqlauth.core.constants import Messages as GQLMessages

from .types import SocialAuthInput
from .constants import Messages


def psa(f):
@wraps(f)
def wrapper(cls, info: Info, input_: SocialAuthInput, **kwargs):
strategy = load_strategy()
try:
backend = load_backend(strategy, input_.provider, redirect_uri=None)

user = backend.do_auth(input_.access_token)

if user is None:
return f(cls, info, input_, None, GQLMessages.INVALID_TOKEN, **kwargs)

user_model = strategy.storage.user.user_model()

if not isinstance(user, user_model):
raise f(cls, info, input_, None, Messages.user_instance_error(user), **kwargs)

return f(cls, info, input_, user, None, **kwargs)
except MissingBackend:
return f(cls, info, input_, None, Messages.NO_PROVIDER, **kwargs)
except Exception as e:
return f(cls, info, input_, None, Messages.exception(e), **kwargs)
return wrapper


def social_auth(f):
"""
Decorator for Getting social User. Use this decorator if you want to customize the SocialAuthMixin.
:param f: Input: SocialAuthInput(provider, accessToken)
:return: function with two additional arguments
user: Entire User Object (Get your social data using user.social_user)
errors: Any error occurred in the process of getting the Social User
"""
@psa
@wraps(f)
def wrapper(cls, info, _input, user, errors, **kwargs):
def on_resolve(payload):
payload.user = user
payload.errors = errors
return payload

result = f(cls, info, _input, user, errors, **kwargs)

if is_thenable(result):
return Promise.resolve(result).then(on_resolve)
return on_resolve(result)

return wrapper
36 changes: 10 additions & 26 deletions gql_social_auth/mixins.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,22 @@
from strawberry.types import Info
from gqlauth.user.resolvers import BaseMixin
from gqlauth.core.constants import Messages as GQLMessages
from .decorators import social_auth
from .types import SocialAuthInput
from social_django.utils import load_backend, load_strategy
from social_core.exceptions import MissingBackend

from .types import SocialType
from .constants import Messages


class SocialAuthMixin(BaseMixin):
"""Social Auth takes OAuth Provider and OAuth Access Token
Allow user to perform social auth for the given OAuth provider and OAuth Access token
:returns
user: Entire User Object (Get your social data using user.social_user)
errors: Any error occurred in the process of getting the Social User
"""
@classmethod
def resolve_mutation(cls, info: Info, input_: SocialAuthInput) -> SocialType:
strategy = load_strategy()
try:
backend = load_backend(strategy, input_.provider, redirect_uri=None)

user = backend.do_auth(input_.access_token)

if user is None:
return SocialType(success=False, errors=GQLMessages.INVALID_TOKEN)

user_model = strategy.storage.user.user_model()

if not isinstance(user, user_model):
return SocialType(success=False, errors=Messages.user_instance_error(user))

return SocialType.from_social_user(user)

except MissingBackend:
return SocialType(success=False, errors=Messages.NO_PROVIDER)
except Exception as e:
return SocialType(success=False, errors=Messages.exception(e))
@classmethod
@social_auth
def resolve_mutation(cls, info: Info, input_: SocialAuthInput, user, errors) -> SocialType:
if errors is not None:
return SocialType(success=False, errors=errors)
return SocialType.from_social_user(user)
18 changes: 17 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "strawberry-django-social-auth"
version = "0.1.0"
version = "0.2.0"
description = "Graphql Social authentication system with Strawberry for Django."
license = "MIT"
authors = ["Shritesh Jamulkar <shritesh.sj@gmail.com>"]
Expand Down Expand Up @@ -30,6 +30,7 @@ PyJWT = ">=2.6.0,<3.0"
strawberry-graphql-django = ">=0.10.5"
social-auth-app-django= ">=2.1.0"
strawberry-django-auth = ">=0.373.1"
promise = "^2.3"

[tool.poetry.group.dev.dependencies]
pre-commit = "^3.3.3"
Expand Down
2 changes: 1 addition & 1 deletion testproject/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from gqlauth.core.middlewares import JwtSchema
from gqlauth.user.queries import UserQueries


@strawberry.type
class Mutation:
social_auth = mutations.SocialAuth.field
Expand All @@ -14,4 +15,3 @@ class Query(UserQueries):


arg_schema = JwtSchema(query=Query, mutation=Mutation)

6 changes: 3 additions & 3 deletions tests/test_social_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
from google.auth.transport.requests import Request
from google.oauth2 import service_account

from .conftest import SchemaHelper
from gql_social_auth.constants import Messages

scopes = ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile']
credentials = service_account.Credentials.from_service_account_file(
'key.json', scopes=scopes
)


@pytest.fixture
def login_query():
def inner() -> str:
Expand Down Expand Up @@ -87,7 +87,7 @@ def test_login_success(transactional_db, anonymous_schema, get_variables, login_


def test_invalid_provider(transactional_db, anonymous_schema, get_variables, login_query):
res = anonymous_schema.execute(login_query(), arguments={"provider": "a", "accessToken":""})
res = anonymous_schema.execute(login_query(), arguments={"provider": "a", "accessToken": ""})
assert not res.errors
res = res.data["socialAuth"]
assert not res["success"]
Expand All @@ -99,4 +99,4 @@ def test_invalid_access_token(transactional_db, anonymous_schema, get_variables,
assert not res.errors
res = res.data["socialAuth"]
assert not res["success"]
assert res["errors"]["nonFieldErrors"]
assert res["errors"]["nonFieldErrors"]

0 comments on commit 1463f92

Please sign in to comment.