Added logic to register by discord #70

This commit is contained in:
2022-10-20 09:47:23 +02:00
parent 0c42c6554c
commit d778bd2719
17 changed files with 725 additions and 452 deletions

View File

@@ -7,6 +7,7 @@ from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO
from bot_api.model.email_string_dto import EMailStringDTO
from bot_api.model.o_auth_dto import OAuthDTO
from bot_api.model.reset_password_dto import ResetPasswordDTO
from bot_api.model.token_dto import TokenDTO
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
@@ -37,7 +38,7 @@ class AuthServiceABC(ABC):
async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass
@abstractmethod
async def get_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass
async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO: pass
@abstractmethod
async def find_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass
@@ -46,7 +47,10 @@ class AuthServiceABC(ABC):
async def add_auth_user_async(self, user_dto: AuthUserDTO): pass
@abstractmethod
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO): pass
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO): pass
@abstractmethod
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO) -> OAuthDTO: pass
@abstractmethod
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass

View File

@@ -13,7 +13,8 @@
},
"DiscordAuthentication": {
"ClientSecret": "V3FTb3JYVFBiVktEeHZxdWJDWW4xcnBCbXRwdmpwcy0=",
"RedirectURL": "http://localhost:5000/api/auth/discord/register",
"_RedirectURL": "http://localhost:5000/api/auth/discord/register",
"RedirectURL": "http://localhost:4200/auth/register",
"Scope": [
"identify",
"email"

View File

@@ -7,15 +7,17 @@ from cpl_core.mailing import EMailClientABC, EMailClientSettings
from cpl_core.utils import CredentialManager
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from flask import jsonify
from flask import jsonify, Response
from flask import request, session
from requests_oauthlib import OAuth2Session
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.api import Api
from bot_api.configuration.discord_authentication_settings import DiscordAuthenticationSettings
from bot_api.json_processor import JSONProcessor
from bot_api.logging.api_logger import ApiLogger
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.model.o_auth_dto import OAuthDTO
from bot_api.route.route import Route
from bot_data.model.auth_role_enum import AuthRoleEnum
@@ -50,27 +52,26 @@ class AuthDiscordController:
self._mailer = mailer
self._auth_service = auth_service
@Route.get(f'{BasePath}/get-url')
async def get_url(self):
oauth = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, scope=self._auth_settings.scope)
login_url, state = oauth.authorization_url(self._auth_settings.auth_url)
session['state'] = state
# return jsonify({'loginURL': login_url})
return '<a href="' + login_url + '">Login with Discord</a>'
@Route.get(f'{BasePath}/register')
async def discord_register(self):
discord = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, state=session['state'], scope=self._auth_settings.scope)
def _get_user_from_discord_response(self) -> dict:
discord = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, state=request.args.get('state'), scope=self._auth_settings.scope)
token = discord.fetch_token(
self._auth_settings.token_url,
client_secret=CredentialManager.decrypt(self._auth_settings.client_secret),
authorization_response=request.url,
)
session['discord_token'] = token
discord = OAuth2Session(self._bot.user.id, token=token)
response = discord.get('https://discordapp.com/api' + '/users/@me').json()
return discord.get('https://discordapp.com/api' + '/users/@me').json()
await self._auth_service.add_auth_user_by_discord_async(AuthUserDTO(
@Route.get(f'{BasePath}/get-url')
async def get_url(self):
oauth = OAuth2Session(self._bot.user.id, redirect_uri=self._auth_settings.redirect_url, scope=self._auth_settings.scope)
login_url, state = oauth.authorization_url(self._auth_settings.auth_url)
return jsonify({'loginUrl': login_url})
@Route.get(f'{BasePath}/create-user')
async def discord_create_user(self) -> Response:
response = self._get_user_from_discord_response()
result = await self._auth_service.add_auth_user_by_discord_async(AuthUserDTO(
0,
response['username'],
response['discriminator'],
@@ -80,4 +81,10 @@ class AuthDiscordController:
AuthRoleEnum.normal,
response['id']
))
return jsonify(result.to_dict())
@Route.post(f'{BasePath}/register')
async def discord_register(self):
dto: OAuthDTO = JSONProcessor.process(OAuthDTO, request.get_json(force=True, silent=True))
await self._auth_service.add_auth_user_by_oauth_async(dto)
return '', 200

View File

@@ -8,14 +8,14 @@ class AuthUserDTO(DtoABC):
def __init__(
self,
id: int,
first_name: str,
last_name: str,
email: str,
password: str,
confirmation_id: Optional[str],
auth_role: AuthRoleEnum,
user_id: Optional[int],
id: int = None,
first_name: str = None,
last_name: str = None,
email: str = None,
password: str = None,
confirmation_id: Optional[str] = None,
auth_role: AuthRoleEnum = None,
user_id: Optional[int] = None,
):
DtoABC.__init__(self)
@@ -27,7 +27,7 @@ class AuthUserDTO(DtoABC):
self._is_confirmed = confirmation_id is None
self._auth_role = auth_role
self._user_id = user_id
@property
def id(self) -> int:
return self._id

View File

@@ -0,0 +1,44 @@
from typing import Optional
from bot_api.abc.dto_abc import DtoABC
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_data.model.auth_role_enum import AuthRoleEnum
class OAuthDTO(DtoABC):
def __init__(
self,
user: AuthUserDTO,
o_auth_id: Optional[str],
):
DtoABC.__init__(self)
self._user = user
self._oauth_id = o_auth_id
@property
def user(self) -> AuthUserDTO:
return self._user
@user.setter
def user(self, value: AuthUserDTO):
self._user = value
@property
def oauth_id(self) -> Optional[str]:
return self._oauth_id
@oauth_id.setter
def oauth_id(self, value: Optional[str]):
self._oauth_id = value
def from_dict(self, values: dict):
self._user = AuthUserDTO().from_dict(values['user'])
self._oauth_id = values['oAuthId']
def to_dict(self) -> dict:
return {
'user': self._user.to_dict(),
'oAuthId': self._oauth_id
}

View File

@@ -25,6 +25,7 @@ from bot_api.mail.mail_thread import MailThread
from bot_api.model.auth_user_dto import AuthUserDTO
from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO
from bot_api.model.email_string_dto import EMailStringDTO
from bot_api.model.o_auth_dto import OAuthDTO
from bot_api.model.reset_password_dto import ResetPasswordDTO
from bot_api.model.token_dto import TokenDTO
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
@@ -190,9 +191,10 @@ class AuthService(AuthServiceABC):
users.total_count
)
async def get_auth_user_by_email_async(self, email: str) -> AuthUserDTO:
async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO:
try:
return AUT.to_dto(self._auth_users.get_auth_user_by_email(email))
user = self._auth_users.get_auth_user_by_email(email)
return AUT.to_dto(user, password=user.password if with_password else None)
except Exception as e:
self._logger.error(__name__, f'AuthUser not found', e)
raise ServiceException(ServiceErrorCode.InvalidData, f'User not found {email}')
@@ -225,24 +227,54 @@ class AuthService(AuthServiceABC):
self._logger.error(__name__, f'Cannot add user with E-Mal {user_dto.email}', e)
raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail")
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO):
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO):
db_user = self._auth_users.find_auth_user_by_email(dto.user.email)
if db_user is None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found')
if db_user.oauth_id != dto.oauth_id:
raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong OAuthId')
db_user.first_name = dto.user.first_name
db_user.last_name = dto.user.last_name
db_user.password_salt = uuid.uuid4()
db_user.password = self._hash_sha256(dto.user.password, db_user.password_salt)
db_user.oauth_id = None
self._auth_users.update_auth_user(db_user)
self._db.save_changes()
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO) -> OAuthDTO:
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
# user exists
if db_user is not None and db_user.user_id is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
# raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
self._logger.debug(__name__, f'Discord user already exists')
return OAuthDTO(AUT.to_dto(db_user), None)
# user exists but discord user id not set
elif db_user is not None and db_user.user_id is None:
self._logger.debug(__name__, f'Auth user exists but not linked with discord')
user = self._users.get_users_by_discord_id(user_dto.user_id).single()
db_user.user_id = user.user_id
self._auth_users.update_auth_user(db_user)
self._db.save_changes()
return AUT.to_dto(db_user)
db_user.oauth_id = None
# user does not exists
await self.add_auth_user_async(user_dto)
db_user = self._auth_users.get_auth_user_by_email(user_dto.email)
return AUT.to_dto(db_user, password=db_user.password)
else:
# user does not exists
self._logger.debug(__name__, f'Auth user does not exist')
try:
user_dto.user_id = self._users.get_users_by_discord_id(user_dto.user_id).single().user_id
except Exception as e:
self._logger.error(__name__, f'User not found')
user_dto.user_id = None
await self.add_auth_user_async(user_dto)
db_user = self._auth_users.get_auth_user_by_email(user_dto.email)
db_user.oauth_id = uuid.uuid4()
self._auth_users.update_auth_user(db_user)
self._db.save_changes()
return OAuthDTO(AUT.to_dto(db_user), db_user.oauth_id)
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
if update_user_dto is None:

View File

@@ -19,6 +19,7 @@ class AuthUserTransformer(TransformerABC):
None,
None,
None,
None,
datetime.now(tz=timezone.utc),
AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role),
dto.user_id,