Skip to content
This repository has been archived by the owner on Nov 2, 2020. It is now read-only.

Commit

Permalink
refactor(InviteAction): Use InviteActionFrom instead of func in Contr…
Browse files Browse the repository at this point in the history
…oller

Signed-off-by: Rhilip <rhilipruan@gmail.com>
  • Loading branch information
Rhilip committed Jun 15, 2019
1 parent d263c6c commit 7fa7069
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 100 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
- **Error:** Fix Error Handler
- **Invite:** Add Fine-grained control of recycle pending
- **Register:** Add captcha checker
- **TorrentUpload:** Fix length 0 file cause ParseErrorException
- **Tracker:** Add miss port check for field ipv6_port
- **View:** Fix Conversion::setDefault()
- **View:** remove view helper function `get_torrent_uploader_id`
Expand Down
70 changes: 10 additions & 60 deletions apps/controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use apps\models\User;
use apps\models\form\UserInviteForm;
use apps\models\form\UserInviteActionForm;

use Rid\Http\Controller;

Expand Down Expand Up @@ -42,7 +43,7 @@ public function actionInvite()
}

$user = app()->user;
$uid = app()->request->get('id');
$uid = app()->request->get('uid');
if (!is_null($uid) && $uid != app()->user->getId()) {
if (app()->user->isPrivilege('view_invite')) {
$user = new User($uid);
Expand All @@ -52,65 +53,14 @@ public function actionInvite()
}

// FIXME By using Form Class
if (app()->request->get('action') == 'confirm' && app()->user->isPrivilege('invite_manual_confirm')) {
$uid = app()->request->get('uid');
if ($uid) {
app()->pdo->createCommand("UPDATE `users` SET `status` = 'confirmed' WHERE `id` = :invitee_id AND `status` = 'pending'")->bindParams([
'invitee_id' => $uid
])->execute();
if (app()->pdo->getRowCount() > 1) {
$msg = 'Confirm Pending User Success!';
} else {
$msg = 'You can\'t confirm a confirmed user.';
}
}
}

if (app()->request->get('action') == 'recycle' && (
$user->getId() === app()->user->getId() ?
app()->user->isPrivilege('invite_recycle_self_pending') :
app()->user->isPrivilege('invite_recycle_other_pending')
)) {
$invite_id = app()->request->get('invite_id');
if ($invite_id) {
// Get unused invite info
$invite_info = app()->pdo->createCommand('SELECT * FROM `invite` WHERE `id` = :invite_id AND `inviter_id` = :inviter_id AND `used` = 0')->bindParams([
'invite_id' => $invite_id, 'inviter_id' => $user->getId()
])->queryOne();
if ($invite_info) {
app()->pdo->beginTransaction();
try {
// Set this record used
app()->pdo->createCommand('UPDATE `invite` SET `used` = 1 WHERE `id` = :id')->bindParams([
'id' => $invite_info['id'],
])->execute();
$msg = 'Recycle invite success!';

// Recycle or not ?
if (app()->config->get('invite.recycle_return_invite')) {
// TODO Add recycle limit so that user can't make a temporarily invite like 'permanent'
if ($invite_info['invite_type'] == 'permanent') {
app()->pdo->createCommand('UPDATE `users` SET `invites` = `invites` + 1 WHERE id = :uid')->bindParams([
'uid' => $invite_id['inviter_id']
])->execute();
$msg .= ' And return you a permanent invite';
} elseif ($invite_info['invite_type'] == 'temporarily') {
app()->pdo->createCommand('INSERT INTO `user_invitations` (`user_id`,`total`,`create_at`,`expire_at`) VALUES (:uid,:total,CURRENT_TIMESTAMP,DATE_ADD(NOW(),INTERVAL :life_time SECOND ))')->bindParams([
'uid' => $invite_id['inviter_id'], 'total' => 1,
'life_time' => app()->config->get('invite.recycle_invite_lifetime')
])->execute();
$msg .= ' And return you a temporarily invite with ' . app()->config->get('invite.recycle_invite_lifetime') . ' seconds lifetime.';
app()->redis->hDel( 'User:' . $invite_id['inviter_id'] . ':base_content','temp_invite');
}
}
app()->pdo->commit();
} catch (\Exception $e) {
$msg = '500 Error.....' . $e->getMessage();
app()->pdo->rollback();
}
} else {
$msg = 'Can\'t Found this invite record.';
}
if (!is_null(app()->request->get('action'))) {
$action_form = new UserInviteActionForm();
$action_form->setData(app()->request->get());
$success = $action_form->validate();
if ($success) {
$msg = $action_form->flush();
} else {
return $this->render('errors/action_fail', ['title' => 'Invite Failed', 'msg' => $action_form->getError()]);
}
}

Expand Down
6 changes: 3 additions & 3 deletions apps/models/form/NewEditForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ class NewEditForm extends Validator
public $notify = 0;
public $force_read = 0;

public function __construct(array $config = [])
public function buildDefaultValue()
{
parent::__construct($config);
$this->user_id = app()->user->getId();
}

Expand All @@ -41,7 +40,8 @@ public static function inputRules()
];
}

public function flush() {
public function flush()
{
if ($this->id == 0) { // This is new news
app()->pdo->createCommand('INSERT INTO news (user_id,create_at,title,body,notify,force_read) VALUES (:uid,CURRENT_TIMESTAMP,:title,:body,:notify,:fread);')->bindParams([
'uid' => $this->user_id, 'title' => $this->title, 'body' => $this->body,
Expand Down
32 changes: 21 additions & 11 deletions apps/models/form/UserConfirmForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ class UserConfirmForm extends Validator
public $secret;
public $action;

protected static $action_list = ['register', 'recover'];
const ACTION_REGISTER = 'register';
const ACTION_RECOVER = 'recover';


protected $id;
private $uid;
Expand All @@ -34,7 +36,7 @@ public static function inputRules()
'secret' => 'Required',
'action' => [
['Required'],
['InList', ['list' => self::$action_list], 'Unknown confirm action.']
['InList', ['list' => [self::ACTION_REGISTER, self::ACTION_RECOVER]], 'Unknown confirm action.']
],
];
}
Expand All @@ -53,7 +55,7 @@ protected function validConfirmSecret()
'SELECT `user_confirm`.`id`,`user_confirm`.`uid`,`users`.`status`,`users`.`username`,`users`.`email` FROM `user_confirm`
LEFT JOIN `users` ON `users`.`id` = `user_confirm`.`uid`
WHERE `secret` = :secret AND `action` = :action AND used = 0 LIMIT 1;')->bindParams([
'secret' => $this->secret , 'action' => $this->action
'secret' => $this->secret, 'action' => $this->action
])->queryOne();

if ($record == false) { // It means this confirm key is not exist
Expand All @@ -68,14 +70,16 @@ protected function validConfirmSecret()
$this->user_status = $record['status'];
}

protected function update_confirm_status() {
private function update_confirm_status()
{
app()->pdo->createCommand('UPDATE `user_confirm` SET `used` = 1 WHERE id = :id')->bindParams([
'id' => $this->id
])->execute();
}

public function flush_register() {
if ($this->user_status !== UserInterface::STATUS_PENDING) {
private function flush_register()
{
if ($this->user_status !== UserInterface::STATUS_PENDING) {
return 'user status is not pending , they may already confirmed or banned'; // FIXME msg
}

Expand All @@ -87,15 +91,16 @@ public function flush_register() {
return true;
}

public function flush_recover() {
if ($this->user_status !== UserInterface::STATUS_CONFIRMED) {
private function flush_recover()
{
if ($this->user_status !== UserInterface::STATUS_CONFIRMED) {
return 'user status is not confirmed , they may in pending or banned'; // FIXME msg
}

// generate new password
$new_password = StringHelper::getRandomString(10);
app()->pdo->createCommand('UPDATE `users` SET `password` = :new_password WHERE `id` = :uid')->bindParams([
'new_password'=> password_hash($new_password, PASSWORD_DEFAULT), 'uid'=>$this->uid
'new_password' => password_hash($new_password, PASSWORD_DEFAULT), 'uid' => $this->uid
])->execute();
$this->update_confirm_status();

Expand All @@ -110,7 +115,12 @@ public function flush_recover() {
return true;
}

public function flush() {
return $this->{'flush_' . $this->action}(); // Magic function call
public function flush()
{
if ($this->action == self::ACTION_REGISTER) {
return $this->flush_register();
} elseif ($this->action == self::ACTION_RECOVER) {
return $this->flush_recover();
}
}
}
161 changes: 161 additions & 0 deletions apps/models/form/UserInviteActionForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?php
/**
* Created by PhpStorm.
* User: Rhilip
* Date: 2019/6/7
* Time: 17:59
*/

namespace apps\models\form;


use apps\components\User\UserInterface;
use Rid\Validators\Validator;

class UserInviteActionForm extends Validator
{
public $uid;

public $action;

// $action = 'confirm'
public $invitee_id; // The user id of invitee
private $confirm_info;

// $action = 'recycle'
public $invite_id;
private $invite_info;

const ACTION_CONFIRM = 'confirm';
const ACTION_RECYCLE = 'recycle';

public function buildDefaultValue()
{
if (is_null($this->uid)) $this->uid = app()->user->getId();
}

public static function inputRules()
{
return [
'action' => [
['required'],
['InList', ['list' => [self::ACTION_CONFIRM, self::ACTION_RECYCLE]]]
],
'username' => [
['required'],
['MaxLength', ['max' => 12], 'User name is too log, Max length {max}']
],
'email' => 'required | email',

'temp_id' => 'Integer',
];
}

public static function callbackRules()
{
return [
'checkActionPrivilege',
'checkConfirmInfo','checkRecycleInfo'
];
}

protected function checkActionPrivilege() {
if ($this->action == self::ACTION_CONFIRM) {
if (!app()->user->isPrivilege('invite_manual_confirm')) {
$this->buildCallbackFailMsg('action:privilege', 'privilege is not enough to confirm pending user.');
}
} elseif ($this->action == self::ACTION_RECYCLE) {
$check_recycle_privilege_name = ($this->uid == app()->user->getId() ? 'invite_recycle_self_pending' : 'invite_recycle_other_pending');
if (!app()->user->isPrivilege($check_recycle_privilege_name)) {
$this->buildCallbackFailMsg('action:privilege', 'privilege is not enough to recycle user pending invites.');
}
}
}

protected function checkConfirmInfo() {
if ($this->action == self::ACTION_CONFIRM) {
$this->confirm_info = app()->pdo->createCommand('SELECT `status` FROM users WHERE id= :invitee_id')->bindParams([
'invitee_id' => $this->invitee_id
])->queryScalar();
if ($this->confirm_info === false || $this->confirm_info !== UserInterface::STATUS_PENDING) {
$this->buildCallbackFailMsg('user:confirm','The user to confirm is not exist or already confirmed');
}
}
}

protected function checkRecycleInfo() {
if ($this->action == self::ACTION_RECYCLE) {
// Get unused invite info
$this->invite_info = app()->pdo->createCommand('SELECT * FROM `invite` WHERE `id` = :invite_id AND `inviter_id` = :inviter_id AND `used` = 0')->bindParams([
'invite_id' => $this->invite_id, 'inviter_id' => $this->uid
])->queryOne();

if (!$this->invite_info) {
$this->buildCallbackFailMsg('invite_info', 'this invite info is not exit');
return;
}

// TODO Add recycle limit so that user can't make a temporarily invite like 'permanent'
if ($this->invite_info['invite_type'] == UserInviteForm::INVITE_TYPE_TEMPORARILY) {
if (app()->redis->get('invite_recycle_limit:user_' . $this->invite_info['inviter_id']) !== false) {
$this->buildCallbackFailMsg('invite_recycle_limit','Hit recycle limit');
return;
};
}
}
}

private function flush_confirm() {
app()->pdo->createCommand('UPDATE `users` SET `status` = :new_status WHERE `id` = :invitee_id')->bindParams([
'new_status' => UserInterface::STATUS_CONFIRMED, 'invitee_id' => $this->invitee_id
])->execute();
if (app()->pdo->getRowCount() > 1) {
return 'Confirm Pending User Success!';
} else {
return 'You can\'t confirm a confirmed user.';
}
}

private function flush_recycle() {
app()->pdo->beginTransaction();
try {
// Set this invite record's status as recycled
app()->pdo->createCommand('UPDATE `invite` SET `used` = -2 WHERE `id` = :id')->bindParams([
'id' => $this->invite_info['id'],
])->execute();
$msg = 'Recycle invite success!';

// Recycle or not ?
if (app()->config->get('invite.recycle_return_invite')) {
if ($this->invite_info['invite_type'] == UserInviteForm::INVITE_TYPE_PERMANENT) {
app()->pdo->createCommand('UPDATE `users` SET `invites` = `invites` + 1 WHERE id = :uid')->bindParams([
'uid' => $this->invite_info['inviter_id']
])->execute();
$msg .= ' And return you a permanent invite';
} elseif ($this->invite_info['invite_type'] == UserInviteForm::INVITE_TYPE_TEMPORARILY) {
app()->pdo->createCommand('INSERT INTO `user_invitations` (`user_id`,`total`,`create_at`,`expire_at`) VALUES (:uid,:total,CURRENT_TIMESTAMP,DATE_ADD(NOW(),INTERVAL :life_time SECOND ))')->bindParams([
'uid' => $this->invite_info['inviter_id'], 'total' => 1,
'life_time' => app()->config->get('invite.recycle_invite_lifetime')
])->execute();
$msg .= ' And return you a temporarily invite with ' . app()->config->get('invite.recycle_invite_lifetime') . ' seconds lifetime.';
app()->redis->hDel( 'User:' . $this->invite_info['inviter_id'] . ':base_content','temp_invite');
}
}
app()->pdo->commit();
} catch (\Exception $e) {
$msg = '500 Error.....' . $e->getMessage();
app()->pdo->rollback();
}
return $msg;
}

public function flush()
{
if ($this->action == self::ACTION_CONFIRM) {
return $this->flush_confirm();
} elseif ($this->action == self::ACTION_RECYCLE) {
return $this->flush_recycle();
}
}

}
Loading

0 comments on commit 7fa7069

Please sign in to comment.