From da08bcf1b2d21a38d7a1f657b7307149ae4e506f Mon Sep 17 00:00:00 2001 From: iIronside Date: Tue, 24 Oct 2023 13:34:23 +0300 Subject: [PATCH] add Telegram bot tokens table and API methods --- common/config/params.php | 2 + common/models/UserTgBotToken.php | 75 ++++++++++ ...231023_122338_create_user_tg_bot_token.php | 33 +++++ .../api/controllers/UserController.php | 1 - .../api/controllers/UserTgBotController.php | 107 ++++++++++++++ .../modules/api/models/UserTgBotToken.php | 69 +++++++++ .../api/services/UserTgBotTokenService.php | 131 ++++++++++++++++++ 7 files changed, 417 insertions(+), 1 deletion(-) create mode 100644 common/models/UserTgBotToken.php create mode 100644 console/migrations/m231023_122338_create_user_tg_bot_token.php create mode 100644 frontend/modules/api/controllers/UserTgBotController.php create mode 100644 frontend/modules/api/models/UserTgBotToken.php create mode 100644 frontend/modules/api/services/UserTgBotTokenService.php diff --git a/common/config/params.php b/common/config/params.php index c6ecfb3..00b7415 100755 --- a/common/config/params.php +++ b/common/config/params.php @@ -6,4 +6,6 @@ return [ 'senderName' => 'Chancellery ITguild mailer', 'user.passwordResetTokenExpire' => 3600, 'user.passwordMinLength' => 8, + 'tgBotTokenLength' => 6, + 'tgBotTokenValidityTime' => 180, ]; diff --git a/common/models/UserTgBotToken.php b/common/models/UserTgBotToken.php new file mode 100644 index 0000000..0c3f905 --- /dev/null +++ b/common/models/UserTgBotToken.php @@ -0,0 +1,75 @@ + 255], + [['token'], 'unique'], + [['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'user_id' => 'User ID', + 'token' => 'Token', + 'created_at' => 'Created At', + 'updated_at' => 'Updated At', + 'expired_at' => 'Expired At', + ]; + } + + /** + * @return ActiveQuery + */ + public function getUser() + { + return $this->hasOne(User::className(), ['id' => 'user_id']); + } + + /** + * @param string $tokenValue + * @return bool + */ + public static function checkExistsByToken(string $tokenValue): bool + { + return self::find()->where(['token' => $tokenValue])->exists(); + } +} diff --git a/console/migrations/m231023_122338_create_user_tg_bot_token.php b/console/migrations/m231023_122338_create_user_tg_bot_token.php new file mode 100644 index 0000000..43f51de --- /dev/null +++ b/console/migrations/m231023_122338_create_user_tg_bot_token.php @@ -0,0 +1,33 @@ +createTable('{{%user_tg_bot_token}}', [ + 'id' => $this->primaryKey(), + 'user_id' => $this->integer(), + 'token' => $this->string()->notNull()->unique(), + 'created_at' => $this->dateTime(), + 'updated_at' => $this->dateTime(), + 'expired_at' => $this->dateTime(), + ]); + $this->addForeignKey('user_user_tg_bot_token', 'user_tg_bot_token', 'user_id', 'user', 'id'); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropTable('user_tg_bot_token'); + } +} diff --git a/frontend/modules/api/controllers/UserController.php b/frontend/modules/api/controllers/UserController.php index 81dd374..60f27af 100755 --- a/frontend/modules/api/controllers/UserController.php +++ b/frontend/modules/api/controllers/UserController.php @@ -25,7 +25,6 @@ class UserController extends ApiController return $behaviors; } - private UserService $userService; public function __construct( diff --git a/frontend/modules/api/controllers/UserTgBotController.php b/frontend/modules/api/controllers/UserTgBotController.php new file mode 100644 index 0000000..4a9b4ed --- /dev/null +++ b/frontend/modules/api/controllers/UserTgBotController.php @@ -0,0 +1,107 @@ + [ + 'class' => \yii\filters\VerbFilter::class, + 'actions' => [ + 'get-token' => ['get'], + 'get-user-by-token' => ['get'], + ], + ] + ]); + } + + /** + * @var UserTgBotTokenService + */ + private UserTgBotTokenService $userTgBotTokenService; + + public function __construct( + $id, + $module, + UserTgBotTokenService $userTgBotTokenService, + $config = [] + ) + { + $this->userTgBotTokenService = $userTgBotTokenService; + parent::__construct($id, $module, $config); + } + + /** + * @OA\Get(path="/user-tg-bot/get-token", + * summary="Токен ТГ бота", + * description="Метод для возвращает токен для ТГ бота", + * security={ + * {"bearerAuth": {}} + * }, + * tags={"UserTgBotToken"}, + * @OA\Response( + * response=200, + * description="Возвращает объект токен ТГ бота", + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema(ref="#/components/schemas/UserTgBotTokenExample"), + * ), + * ), + * ) + * + * @return UserTgBotToken + * @throws Exception + */ + public function actionGetToken() + { + return $this->userTgBotTokenService->getToken(Yii::$app->user->id); + } + + /** + * + * @OA\Get(path="/user-tg-bot/get-user", + * summary="Получить данные пользователя", + * description="Метод для получения данныех пользователя по токену ТГ бота", + * security={ + * {"bearerAuth": {}} + * }, + * tags={"UserTgBotToken"}, + * @OA\Parameter( + * name="token", + * in="query", + * example="HDAS7J", + * required=true, + * description="Токен ТГ бота", + * @OA\Schema( + * type="string", + * ) + * ), + * @OA\Response( + * response=200, + * description="Возвращает данные пользователя", + * @OA\MediaType( + * mediaType="application/json", + * ), + * ), + * ) + * + * @param string $token + * @return User|string[] + * @throws Exception + */ + public function actionGetUser(string $token) + { + return $this->userTgBotTokenService->getUserByToken($token); + } +} diff --git a/frontend/modules/api/models/UserTgBotToken.php b/frontend/modules/api/models/UserTgBotToken.php new file mode 100644 index 0000000..66d7082 --- /dev/null +++ b/frontend/modules/api/models/UserTgBotToken.php @@ -0,0 +1,69 @@ +hasOne(User::class, ['id' => 'user_id']); + } +} \ No newline at end of file diff --git a/frontend/modules/api/services/UserTgBotTokenService.php b/frontend/modules/api/services/UserTgBotTokenService.php new file mode 100644 index 0000000..8f32d80 --- /dev/null +++ b/frontend/modules/api/services/UserTgBotTokenService.php @@ -0,0 +1,131 @@ + $userId]); + if (!empty($model)) { + return $this->checkExpiredAtTime($model); + } + + return $this->createToken($userId); + } + + /** + * @param string $token + * @return User|string[] + * @throws Exception + */ + public function getUserByToken(string $token) + { + $model = UserTgBotToken::findOne(['token' => $token]); + if (!empty($model) ) { + + $currentTime = new DateTime(); + + if ($currentTime < new DateTime($model->expired_at)) { + return $model->user; + } else { + return ['error' => 'The token is expired!']; + } + + } + + return ['error' => 'Token not found!']; + } + + /** + * @return string + * @throws Exception + */ + private function generateToken(): string + { + $length = Yii::$app->params['tgBotTokenLength']; + $charactersLength = strlen($this::CHARACTERS); + do { + $value = ''; + for ($i = 0; $i < $length; $i++) { + $value .= $this::CHARACTERS[random_int(0, $charactersLength - 1)]; + } + } while ( UserTgBotToken::checkExistsByToken($value)); + + return $value; + } + + /** + * @param int $userId + * @return UserTgBotToken + * @throws Exception + */ + private function createToken(int $userId): UserTgBotToken + { + $model = new UserTgBotToken(); + $model->user_id = $userId; + $model->token = $this->generateToken(); + $model->expired_at = $this->generateExpiredAtTime(); + + if (!$model->save()) { + throw new \Exception('Токен не сохранен'); + } + + return $model; + } + + /** + * @return false|string + */ + private function generateExpiredAtTime() + { + return date("Y-m-d H:i:s",strtotime(date("Y-m-d H:i:s")) + Yii::$app->params['tgBotTokenValidityTime']); + } + + /** + * @param UserTgBotToken $model + * @return UserTgBotToken + * @throws Exception + */ + private function checkExpiredAtTime(UserTgBotToken $model) + { + $currentTime = new DateTime(); + + if ($currentTime > new DateTime($model->expired_at)) { + $this->updateExpiredAtTime($model); + } + + return $model; + } + + /** + * @param UserTgBotToken $model + * @return UserTgBotToken + * @throws Exception + */ + private function updateExpiredAtTime(UserTgBotToken $model) + { + $model->token = $this->generateToken(); + $model->expired_at = $this->generateExpiredAtTime(); + + if (!$model->save()) { + throw new \Exception('Токен не сохранен'); + } + + return $model; + } +} \ No newline at end of file