From 1c83715de67fb80ff93ad8afb5193d4d60e81d1f Mon Sep 17 00:00:00 2001 From: Rhilip Date: Sat, 16 Mar 2019 12:55:04 +0800 Subject: [PATCH] feat(Favour): Add full favour support --- README.md | 2 +- apps/config/http_base.php | 11 +++- apps/controllers/api/IndexController.php | 18 ------ .../controllers/api/v1/TorrentsController.php | 37 ++++++++++++ apps/middleware/ApiMiddleware.php | 8 +++ .../api/v1/form/TorrentsBookmarkForm.php | 60 +++++++++++++++++++ apps/public/static/css/main.css | 3 +- apps/public/static/js/main.js | 35 +++++++---- apps/views/torrents/details.php | 32 ++++++++-- apps/views/torrents/helper.php | 13 +++- framework/Http/ApiController.php | 42 +++++++++++++ framework/Http/BaseResponse.php | 12 ---- framework/Http/Error.php | 1 - framework/User/User.php | 4 +- framework/User/UserTrait.php | 2 +- framework/Validators/Validator.php | 7 ++- 16 files changed, 226 insertions(+), 61 deletions(-) delete mode 100644 apps/controllers/api/IndexController.php create mode 100644 apps/controllers/api/v1/TorrentsController.php create mode 100644 apps/models/api/v1/form/TorrentsBookmarkForm.php create mode 100644 framework/Http/ApiController.php diff --git a/README.md b/README.md index f06cc1a..bb9dae2 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ Some rule or Docs May help you when you rebuild this project, Or you can join our chat group on Telegram -- [@ridpt](https://t.me/ridpt) | Name | Used As | Docs | -|:--|:--:|:--:|:--:| +|:--|:--:|:--:| | [MixPHP](https://github.com/mix-php/mix-framework/tree/v1) | Framework | https://www.kancloud.cn/onanying/mixphp1/379324 ( Chinese Version ) | | [siriusphp/validation](https://github.com/siriusphp/validation) | Validator | http://www.sirius.ro/php/sirius/validation/ | | [league/plates](https://github.com/thephpleague/plates) | Template system | http://platesphp.com/ | diff --git a/apps/config/http_base.php b/apps/config/http_base.php index 78a3b8b..5fbc074 100644 --- a/apps/config/http_base.php +++ b/apps/config/http_base.php @@ -36,12 +36,19 @@ 'rules' => [ 'GET tracker/{tracker_action}' => ['tracker','index'], 'GET captcha' => ['captcha', 'index'], + + // Auth By Passkey Route 'GET rss' => ['rss', 'index','middleware' => [ apps\middleware\AuthByPasskeyMiddleware::class ]], - 'api/v1/{controller}/{action}' => ['api/{controller}', '{action}', 'middleware' => [ - apps\middleware\ApiMiddleware::class + + // API version 1 + 'api/v1/{controller}/{action}' => ['api/v1/{controller}', '{action}', 'middleware' => [ + apps\middleware\ApiMiddleware::class, + apps\middleware\AuthByCookiesMiddleware::class ]], + + // Web view '{controller}/{action}' => ['{controller}', '{action}', 'middleware' => [ apps\middleware\AuthByCookiesMiddleware::class ]], diff --git a/apps/controllers/api/IndexController.php b/apps/controllers/api/IndexController.php deleted file mode 100644 index bbef352..0000000 --- a/apps/controllers/api/IndexController.php +++ /dev/null @@ -1,18 +0,0 @@ - "world"]; - } -} diff --git a/apps/controllers/api/v1/TorrentsController.php b/apps/controllers/api/v1/TorrentsController.php new file mode 100644 index 0000000..58d0577 --- /dev/null +++ b/apps/controllers/api/v1/TorrentsController.php @@ -0,0 +1,37 @@ +checkMethod('POST')) { + $bookmark = new TorrentsBookmarkForm(); + $bookmark->setData(app()->request->post()); + $success = $bookmark->validate(); + if (!$success) { + return [ + 'success' => false, + 'errors' => $bookmark->getErrors() + ]; + } else { + $ret = $bookmark->updateRecord(); + return array_merge( + ['success' => true], + $ret + ); + } + } else { + return $this->buildMethodFailMsg('POST'); + } + } +} diff --git a/apps/middleware/ApiMiddleware.php b/apps/middleware/ApiMiddleware.php index bedc290..6ad8dff 100644 --- a/apps/middleware/ApiMiddleware.php +++ b/apps/middleware/ApiMiddleware.php @@ -14,9 +14,17 @@ class ApiMiddleware public function handle($callable, \Closure $next) { app()->response->format = \Rid\Http\Response::FORMAT_JSON; + + // No cache for api response + app()->response->setHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT'); + app()->response->setHeader('Last-Modified', gmdate("D, d M Y H:i:s") . " GMT"); + app()->response->setHeader('Cache-Control', 'no-cache, must-revalidate'); + app()->response->setHeader('Pragma', 'no-cache'); + if (env("APP_DEBUG")) { app()->response->setHeader("access-control-allow-origin","*"); } + return $next(); } } diff --git a/apps/models/api/v1/form/TorrentsBookmarkForm.php b/apps/models/api/v1/form/TorrentsBookmarkForm.php new file mode 100644 index 0000000..7ac8796 --- /dev/null +++ b/apps/models/api/v1/form/TorrentsBookmarkForm.php @@ -0,0 +1,60 @@ + 'required | Integer' + ]; + } + + public static function callbackRules() { + return ['isExistTorrent']; + } + + protected function isExistTorrent() { + $torrent_exist = app()->pdo->createCommand('SELECT COUNT(`id`) FROM `torrents` WHERE `id` = :tid')->bindParams([ + 'tid' => $this->tid + ])->queryScalar(); + if ($torrent_exist == 0) { + $this->buildCallbackFailMsg('Torrent', 'The torrent id ('. $this->tid. ') is not exist in our database'); + } + } + + public function updateRecord() { + $bookmark_exist = app()->pdo->createCommand('SELECT `id` FROM `bookmarks` WHERE `uid` = :uid AND `tid` = :tid ')->bindParams([ + 'uid' => app()->user->getId(), + 'tid' => $this->tid + ])->queryScalar() ?: 0; + if ($bookmark_exist > 0) { // Delete the exist record + app()->pdo->createCommand('DELETE FROM `bookmarks` WHERE `id` = :bid')->bindParams([ + 'bid' => $bookmark_exist + ])->execute(); + app()->redis->del('User:' . app()->user->getId() . ':bookmark_array'); + + return ['msg' => 'Delete Old Bookmark Success', 'result' => 'deleted']; + } else { // Add new record + app()->pdo->createCommand('INSERT INTO `bookmarks` (`uid`, `tid`) VALUES (:uid, :tid)')->bindParams([ + 'uid' => app()->user->getId(), + 'tid' => $this->tid + ])->execute(); + app()->redis->del('User:' . app()->user->getId() . ':bookmark_array'); + + return ['msg' => 'Add New Bookmark Success', 'result' => 'added']; + } + } +} diff --git a/apps/public/static/css/main.css b/apps/public/static/css/main.css index 692b973..b779b84 100644 --- a/apps/public/static/css/main.css +++ b/apps/public/static/css/main.css @@ -78,4 +78,5 @@ nav#menu .layui-nav-item{line-height:45px} .icon-leeching {color: red} -.torrent-title-block {margin: 15px} +.torrent-title-block{margin:15px} +.torrent-action-item{padding:3px} diff --git a/apps/public/static/js/main.js b/apps/public/static/js/main.js index ff89fdf..00e9849 100644 --- a/apps/public/static/js/main.js +++ b/apps/public/static/js/main.js @@ -1,16 +1,25 @@ ;layui.use(['layer', 'form','element','laypage','jquery'], function(){ - let $=layui.jquery; + let $ = layui.jquery; + let layer = layui.layer; + let api_point = '/api/v1'; - // Add favour action - $('.torrent-favour > i').click(function () { - let star = $(this); - // TODO Do ajax to api, if success then change the star - let old_is_stared = star.hasClass('fas'); - star.toggleClass('fas',!old_is_stared).toggleClass('far',old_is_stared); - new NoticeJs({ - text: 'Torrent add/remove from your favour', - position: 'bottomRight', - }).show(); - // TODO Notice user - }) + // Add/Remove favour action + $('.torrent-favour').click(function () { + let that = $(this); + let tid = that.attr('data-tid'); + let star = that.find(' > i'); + + $.post(api_point + '/torrents/bookmark', {'tid': tid}, function (res) { + if (res.success) { + let old_is_stared = star.hasClass('fas'); + star.toggleClass('fas', !old_is_stared).toggleClass('far', old_is_stared); + layer.msg(`Torrent(${tid}) ${res.result} from your favour successfully`, { + icon: 6, + offset: 'rb', + }); + } else { + layer.alert(res.errors.join(', '), {icon: 2}); + } + }); + }); }); diff --git a/apps/views/torrents/details.php b/apps/views/torrents/details.php index c8b3417..85cd528 100644 --- a/apps/views/torrents/details.php +++ b/apps/views/torrents/details.php @@ -42,19 +42,39 @@
Torrent Action
Torrent Information
-
Date: getAddedAt() ?>
+
Uploaded Date: getAddedAt() ?>
File size: e($torrent->getTorrentSize(),'format_bytes') ?>
-
Uploader:
+
Uploader:
- Peers: getComplete() ?> / getIncomplete() ?> / getDownloaded() ?> + Peers: getComplete() ?> / getIncomplete() ?> / getDownloaded() ?>
Info Hash: getInfoHash() ?>
diff --git a/apps/views/torrents/helper.php b/apps/views/torrents/helper.php index 0005e8b..6059633 100644 --- a/apps/views/torrents/helper.php +++ b/apps/views/torrents/helper.php @@ -14,9 +14,20 @@ * @param \apps\models\Torrent $torrent * @return string */ -function get_torrent_uploader(\apps\models\Torrent $torrent) + +function get_torrent_uploader_id(\apps\models\Torrent $torrent) { if ($torrent->getUplver() == 'yes' and app()->user->getClass(true) < app()->config->get('authority.see_anonymous_uploader')) { + return 0; + } else { + return $torrent->getOwnerId(); + } +} + +function get_torrent_uploader(\apps\models\Torrent $torrent) +{ + $owner_id = get_torrent_uploader_id($torrent); + if ($owner_id == 0) { return 'Anonymous'; } else { return "getOwnerId()}\" data-toggle=\"tooltip\" title=\"User\">{$torrent->getOwner()->getUsername()}"; diff --git a/framework/Http/ApiController.php b/framework/Http/ApiController.php new file mode 100644 index 0000000..0052193 --- /dev/null +++ b/framework/Http/ApiController.php @@ -0,0 +1,42 @@ +request->method()) == strtolower($method)) + return true; + } + return false; + } + + protected function buildMethodFailMsg($want_methods) + { + if (is_array($want_methods)) $want_methods = implode(',', $want_methods); + + app()->response->setStatusCode(405); + $method = app()->request->method(); + + return [ + 'error' => 'Method Not Allowed', + 'detail' => [ + 'method' => "The method `$method` is not allowed, You should use `$want_methods` in this action." + ] + ]; + } +} diff --git a/framework/Http/BaseResponse.php b/framework/Http/BaseResponse.php index c6a3e33..cd2c7d2 100644 --- a/framework/Http/BaseResponse.php +++ b/framework/Http/BaseResponse.php @@ -14,17 +14,11 @@ class BaseResponse extends Component const FORMAT_HTML = 'html'; const FORMAT_JSON = 'json'; const FORMAT_JSONP = 'jsonp'; - const FORMAT_XML = 'xml'; const FORMAT_RAW = 'raw'; // 默认输出格式 public $defaultFormat = self::FORMAT_HTML; - /** - * @var \Rid\Http\Xml - */ - public $xml; - // 当前输出格式 public $format; @@ -71,9 +65,6 @@ protected function prepare() case self::FORMAT_JSONP: $this->setHeader('Content-Type', 'application/json; charset=utf-8'); break; - case self::FORMAT_XML: - $this->setHeader('Content-Type', 'text/xml; charset=utf-8'); - break; } } // 转换内容为字符型 @@ -91,9 +82,6 @@ protected function prepare() $content = $callback_key . '(' . $content . ')'; break; } - case self::FORMAT_XML: - $content = $this->xml->encode($content); - break; } } $this->content = $content; diff --git a/framework/Http/Error.php b/framework/Http/Error.php index c69cdb1..9bf6706 100644 --- a/framework/Http/Error.php +++ b/framework/Http/Error.php @@ -13,7 +13,6 @@ class Error extends Component // 格式值 const FORMAT_HTML = 'html'; const FORMAT_JSON = 'json'; - const FORMAT_XML = 'xml'; // 输出格式 public $format = self::FORMAT_HTML; diff --git a/framework/User/User.php b/framework/User/User.php index 1a80eae..c9ebe13 100644 --- a/framework/User/User.php +++ b/framework/User/User.php @@ -93,12 +93,12 @@ public function getBookmarkList() if (!is_null($this->bookmark_list)) return $this->bookmark_list; - $bookmaks = app()->redis->hGet($this->infoCacheKey, 'bookmark_array'); + $bookmaks = app()->redis->get('User:' . $this->id . ':bookmark_array'); if ($bookmaks === false) { $bookmaks = app()->pdo->createCommand('SELECT `tid` FROM `bookmarks` WHERE `uid` = :uid')->bindParams([ 'uid' => $this->id ])->queryColumn() ?: [0]; - app()->redis->hSet($this->infoCacheKey, 'bookmark_array', $bookmaks); + app()->redis->set('User:' . $this->id . ':bookmark_array', $bookmaks, 132800); } $this->bookmark_list = $bookmaks; // Store in avg to reduce the cache call diff --git a/framework/User/UserTrait.php b/framework/User/UserTrait.php index c68d3d6..3efa4c7 100644 --- a/framework/User/UserTrait.php +++ b/framework/User/UserTrait.php @@ -48,7 +48,7 @@ trait UserTrait public function loadUserContentById($id) { - $this->infoCacheKey = 'User:id_' . $id . '_content'; + $this->infoCacheKey = 'User:' . $id . ':base_content'; $self = app()->redis->hGetAll($this->infoCacheKey); if (empty($self)) { $self = app()->pdo->createCommand("SELECT * FROM `users` WHERE id = :id;")->bindParams([ diff --git a/framework/Validators/Validator.php b/framework/Validators/Validator.php index 272ef26..1ad453b 100644 --- a/framework/Validators/Validator.php +++ b/framework/Validators/Validator.php @@ -43,9 +43,10 @@ public static function callbackRules() { } - private function validateCallbackRules() { - foreach ($this->callbackRules() as $rule) { - call_user_func([$this,$rule]); + private function validateCallbackRules() + { + foreach (static::callbackRules() as $rule) { + call_user_func([$this, $rule]); if (!$this->_success) break; } }