From f93c6972456be01629a890cb0e20004e4073280d Mon Sep 17 00:00:00 2001 From: OldHawk Date: Thu, 11 Jan 2018 16:03:01 +0800 Subject: [PATCH] feat(requests): request owner or oper can edit desc and remove it --- config/env/torrents.js | 3 +- modules/core/client/app/trans-string-en.js | 16 +- modules/core/client/app/trans-string-zh.js | 14 +- .../client/config/requests.client.routes.js | 7 + .../requests-view.client.controller.js | 204 +++++++++++++++++- modules/requests/client/less/requests.less | 36 +++- .../views/requests-list.client.view.html | 14 +- .../client/views/requests-my.client.view.html | 14 +- .../views/requests-res.client.view.html | 14 +- .../views/requests-view.client.view.html | 91 ++++++++ .../client/config/torrents.client.routes.js | 2 +- 11 files changed, 375 insertions(+), 40 deletions(-) create mode 100644 modules/requests/client/views/requests-view.client.view.html diff --git a/config/env/torrents.js b/config/env/torrents.js index bf686a59..a8caf66c 100644 --- a/config/env/torrents.js +++ b/config/env/torrents.js @@ -971,7 +971,8 @@ module.exports = { uploaderUserListPerPage: 15, messageBoxListPerPage: 10, followListPerPage: 30, - requestListPerPage: 15 + requestListPerPage: 15, + requestCommentsPerPage: 10 }, /** diff --git a/modules/core/client/app/trans-string-en.js b/modules/core/client/app/trans-string-en.js index 964750fb..c595e58d 100644 --- a/modules/core/client/app/trans-string-en.js +++ b/modules/core/client/app/trans-string-en.js @@ -20,6 +20,7 @@ VALUE_NULL: 'NULL', VALUE_CUSTOM: 'CUSTOM', VALUE_SELECT_ALL: 'Select All', + BTN_REMOVE: 'Remove', //client topbar menu MENU_CHAT: 'Chat', @@ -187,6 +188,7 @@ REQUESTS_MY: 'My Requests', REQUESTS_RES: 'My Responses', REQUESTS_ADD: 'Add Requests', + REQUESTS_VIEW: 'Requests Detail', ADMIN_USER_LIST: 'User List', ADMIN_USER_VIEW: 'View User', ADMIN_USER_EDIT: 'Edit User', @@ -722,17 +724,27 @@ STATUS_GETTING_ERROR: 'Getting requests ERROR!', POST_REQUEST_SUCCESSFULLY: 'Create request successfully', POST_REQUEST_FAILED: 'Create request failed', - FIELD_TITLE: 'Title', + FIELD_TITLE: 'Title & Desc', FIELD_TYPE: 'Type', FIELD_LIFE: 'Life', FIELD_REWARDS: 'Rewards', FIELD_COMMENTS: 'Comments', FIELD_RESPONSES: 'responses', FIELD_USER: 'User', + BTN_EDIT_DESC: 'Edit Desc', + EDIT_SUCCESSFULLY: 'Edit request successfully', + EDIT_FAILED: 'Edit request failed', + DELETE_CONFIRM_OK: 'Delete', + DELETE_CONFIRM_CANCEL: 'Cancel', + DELETE_CONFIRM_HEADER_TEXT: 'Delete Confirm', + DELETE_CONFIRM_BODY_TEXT: 'Are you sure want to delete this request?', + DELETE_SUCCESSFULLY: 'Request deleted successfully', + DELETE_FAILED: 'Request deleted failed', DESC_LIST: '### NOTE: \n - The list contains only the last `{{days}}` days of the requests. \n - If your response is accepted, the requestor\'s reward score will be automatically transferred to your account. \n - Only the torrents reviewed by the administrator can be accepted by the requestor. \n - The requester can only accept one of the responses. \n - If your response is complains, your account may be punished, Please respond to the user\'s request carefully.', DESC_MY: '### NOTE: \n - If you accept a response, your reward score will be transferred to the respondent\'s account that you accept. \n - Only the torrents reviewed by the administrator can be accepted by you. \n - You can only accept one of the responses. \n - The request over `{{days}}` days has expired and cannot accept the response, you can only post the request again. \n - If your score is maliciously damaged, please mail to the [administrator](mailto:{{admin}})', DESC_ADD: '### NOTE: \n - Each request will be automatically deducted from `{{add_score}}` points, but your reward score will only be transferred to the responder\'s account that you eventually accept. \n - Only the torrents reviewed by the administrator can be accepted by you. \n - Each request is only valid for `{{days}}` days. After expiry, you can only post the request again. \n - Please give a clear resources description of your request when you post the request.', - DESC_RES: '### NOTE: \n - If requestor accept your response, the reward score will be transferred to your account. \n - Only the torrents reviewed by the administrator can be accepted by requestor. \n - Requestor can only accept one of the responses.' + DESC_RES: '### NOTE: \n - If requestor accept your response, the reward score will be transferred to your account. \n - Only the torrents reviewed by the administrator can be accepted by requestor. \n - Requestor can only accept one of the responses.', + DESC_VIEW: '### NOTE: \n - If you want to response a request, please upload the torrent file and seed, Please respond to the user\'s request carefully. \n - If you are a requestor, you can choose a responder and accept it, and only the torrents reviewed by the administrator can be accepted. \n - If you accept a response, your reward score will be transferred to the respondent\'s account that you accept. \n - The request over `{{days}}` days has expired and cannot accept or response(upload).' }, //user status diff --git a/modules/core/client/app/trans-string-zh.js b/modules/core/client/app/trans-string-zh.js index 247a9ded..021a506b 100644 --- a/modules/core/client/app/trans-string-zh.js +++ b/modules/core/client/app/trans-string-zh.js @@ -20,6 +20,7 @@ VALUE_NULL: '无', VALUE_CUSTOM: '自定义', VALUE_SELECT_ALL: '全选', + BTN_REMOVE: '删除', //client topbar menu MENU_CHAT: '聊天室', @@ -187,6 +188,7 @@ REQUESTS_MY: '我的求种', REQUESTS_RES: '我的响应', REQUESTS_ADD: '我要求种', + REQUESTS_VIEW: '求种详情', ADMIN_USER_LIST: '用户管理', ADMIN_USER_VIEW: '查看用户', ADMIN_USER_EDIT: '编辑用户', @@ -722,17 +724,19 @@ STATUS_GETTING_ERROR: '获取求种请求失败!', POST_REQUEST_SUCCESSFULLY: '创建求种请求成功!', POST_REQUEST_FAILED: '创建求种请求失败!', - FIELD_TITLE: '求种标题', + FIELD_TITLE: '求种标题与描述', FIELD_TYPE: '求种类型', FIELD_LIFE: '创建时间', FIELD_REWARDS: '悬赏积分', FIELD_COMMENTS: '留言', FIELD_RESPONSES: '响应', FIELD_USER: '求种用户', - DESC_LIST: '### 提示: \n - 此列表只包含最近 `{{days}}` 天内发布的求种请求. \n - 如果你的回应被采纳,请求者悬赏的积分将自动转入你的帐户. \n - 只有被管理员审核通过的种子才能被请求者接受. \n - 请求者只能接受多个响应中的一个. \n - 如果你的响应被请求者投诉,你的帐号就可能会受到惩罚, 请认真响应用户的请求.', - DESC_MY: '### 提示: \n - 如果您接受一个响应,你的悬赏积分就会转入你接受的响应者的帐户. \n - 只有被管理员审核通过的种子才能被您接受. \n - 您只能接受多个响应中的一个. \n - 超过 `{{days}}` 天的请求已经过期且不能接受响应, 如果需要你只能再次发起请求. \n - 如果您的积分受到恶意损害,请向管理员[投诉](mailto:{{admin}}).', - DESC_ADD: '### 提示: \n - 每发布一个请求会被自动扣除 `{{add_score}}` 积分,而你的悬赏积分会转入你最终接受的响应者的帐户. \n - 只有被管理员审核通过的种子才能被您接受. \n - 每一个发布的请求只有 `{{days}}` 天的有效期,过期后你只能再次发起请求. \n - 请在发布请求时明确描述您对资源的要求.', - DESC_RES: '### NOTE: \n - 如果请求者接受了您的响应, 悬赏积分将自动转入您的帐户. \n - 只有被管理员审核通过的种子才能被请求者接受. \n - 请求者只会接受多个响应中的一个.' + BTN_EDIT_DESC: '编辑描述', + DESC_LIST: '### 提示: \n - 此列表只包含最近 `{{days}}` 天内发布的求种请求. \n - 如果你的回应被采纳, 请求者悬赏的积分将自动转入你的帐户. \n - 只有被管理员审核通过的种子才能被请求者接受. \n - 请求者只能接受多个响应中的一个. \n - 如果你的响应被请求者投诉,你的帐号就可能会受到惩罚, 请认真响应用户的请求.', + DESC_MY: '### 提示: \n - 如果您接受一个响应, 你的悬赏积分就会转入你接受的响应者的帐户. \n - 只有被管理员审核通过的种子才能被您接受. \n - 您只能接受多个响应中的一个. \n - 超过 `{{days}}` 天的请求已经过期且不能接受响应, 如果需要你只能再次发起请求. \n - 如果您的积分受到恶意损害, 请向管理员[投诉](mailto:{{admin}}).', + DESC_ADD: '### 提示: \n - 每发布一个请求会被自动扣除 `{{add_score}}` 积分, 而你的悬赏积分会转入你最终接受的响应者的帐户. \n - 只有被管理员审核通过的种子才能被您接受. \n - 每一个发布的请求只有 `{{days}}` 天的有效期, 过期后你只能再次发起请求. \n - 请在发布请求时明确描述您对资源的要求.', + DESC_RES: '### NOTE: \n - 如果请求者接受了您的响应, 悬赏积分将自动转入您的帐户. \n - 只有被管理员审核通过的种子才能被请求者接受. \n - 请求者只会接受多个响应中的一个.', + DESC_VIEW: '### NOTE: \n - 如果你是一个响应者, 请上传您的种子文件并开始做种, 请认真响应用户的请求. \n - 如果你是一个请求者, 您可以选择一个响应并接受它, 只有被管理员审核通过的种子才能被您接受. \n - 如果您接受一个响应, 你的悬赏积分就会转入你接受的响应者的帐户. \n - 超过 `{{days}}` 天的请求已经过期且不能接受响应或上传种子.' }, //user status diff --git a/modules/requests/client/config/requests.client.routes.js b/modules/requests/client/config/requests.client.routes.js index 1c2370a6..771af027 100644 --- a/modules/requests/client/config/requests.client.routes.js +++ b/modules/requests/client/config/requests.client.routes.js @@ -44,6 +44,13 @@ data: { pageTitle: 'PAGETITLE.REQUESTS_ADD' } + }) + .state('requests.view', { + url: '/:requestId', + templateUrl: '/modules/requests/client/views/requests-view.client.view.html', + data: { + pageTitle: 'PAGETITLE.REQUESTS_VIEW' + } }); } }()); diff --git a/modules/requests/client/controllers/requests-view.client.controller.js b/modules/requests/client/controllers/requests-view.client.controller.js index 33bcf5b7..72d7747b 100644 --- a/modules/requests/client/controllers/requests-view.client.controller.js +++ b/modules/requests/client/controllers/requests-view.client.controller.js @@ -5,22 +5,23 @@ .module('requests') .controller('RequestsViewController', RequestsViewController); - RequestsViewController.$inject = ['$scope', '$rootScope', '$state', '$timeout', '$translate', 'Authentication', 'RequestsService', 'ScoreLevelService', 'MeanTorrentConfig', 'DebugConsoleService', - 'NotifycationService', 'uibButtonConfig', 'marked']; + RequestsViewController.$inject = ['$scope', '$rootScope', '$state', '$timeout', '$translate', 'Authentication', 'RequestsService', 'localStorageService', 'MeanTorrentConfig', 'DebugConsoleService', + 'NotifycationService', '$stateParams', 'marked', 'ModalConfirmService', '$compile']; - function RequestsViewController($scope, $rootScope, $state, $timeout, $translate, Authentication, RequestsService, ScoreLevelService, MeanTorrentConfig, mtDebug, - NotifycationService, uibButtonConfig, marked) { + function RequestsViewController($scope, $rootScope, $state, $timeout, $translate, Authentication, RequestsService, localStorageService, MeanTorrentConfig, mtDebug, + NotifycationService, $stateParams, marked, ModalConfirmService, $compile) { var vm = this; vm.user = Authentication.user; vm.itemsPerPageConfig = MeanTorrentConfig.meanTorrentConfig.itemsPerPage; vm.requestsConfig = MeanTorrentConfig.meanTorrentConfig.requests; + vm.inputLengthConfig = MeanTorrentConfig.meanTorrentConfig.inputLength; /** * getRequestsDesc * @returns {*} */ vm.getRequestsDesc = function () { - var ts = $translate.instant('REQUESTS.DESC_LIST', { + var ts = $translate.instant('REQUESTS.DESC_VIEW', { days: vm.requestsConfig.requestExpires / (60 * 60 * 1000 * 24) }); @@ -28,12 +29,201 @@ }; /** - * getRequestItemDescContent + * getRequestDescContent * @param q * @returns {*} */ - vm.getRequestItemDescContent = function (q) { + vm.getRequestDescContent = function (q) { return q ? marked(q.desc, {sanitize: true}) : ''; }; + + /** + * init + */ + vm.init = function () { + RequestsService.get({ + requestId: $stateParams.requestId + }, function (res) { + vm.request = res; + mtDebug.info(vm.request); + vm.commentBuildPager(); + }); + + }; + + /** + * commentBuildPager + * pagination init + */ + vm.commentBuildPager = function () { + vm.commentPagedItems = []; + vm.commentItemsPerPage = vm.itemsPerPageConfig.requestCommentsPerPage; + vm.commentCurrentPage = 1; + vm.commentFigureOutItemsToDisplay(); + }; + + /** + * commentFigureOutItemsToDisplay + * @param callback + */ + vm.commentFigureOutItemsToDisplay = function (callback) { + vm.commentFilterLength = vm.request.comments.length; + var begin = ((vm.commentCurrentPage - 1) * vm.commentItemsPerPage); + var end = begin + vm.commentItemsPerPage; + vm.commentPagedItems = vm.request.comments.slice(begin, end); + + if (callback) callback(); + }; + + /** + * commentPageChanged + * @param autoScroll, some time not scroll to top + */ + vm.commentPageChanged = function (autoScroll) { + var element = angular.element('#top_of_comments'); + + $('#comment-list-div').fadeTo(100, 0.01, function () { + vm.commentFigureOutItemsToDisplay(function () { + $timeout(function () { + $('#comment-list-div').fadeTo(400, 1, function () { + if (autoScroll) { + //window.scrollTo(0, element[0].offsetTop - 30); + $('html,body').animate({scrollTop: element[0].offsetTop - 30}, 200); + } + }); + }, 100); + }); + }); + }; + + /** + * beginEditMakerDesc + * @param m + */ + vm.beginEditMakerDesc = function (m) { + var el = $('#' + m._id); + + el.markdown({ + autofocus: true, + savable: true, + hideable: true, + iconlibrary: 'fa', + resize: 'vertical', + language: localStorageService.get('storage_user_lang'), + fullscreen: {enable: false}, + onSave: function (e) { + if (e.isDirty()) { + vm.request.desc = e.getContent(); + vm.request.$update(function (res) { + vm.request = res; + NotifycationService.showSuccessNotify('REQUESTS.EDIT_DESC_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'REQUESTS.EDIT_DESC_FAILED'); + }); + + e.$options.hideable = true; + e.blur(); + } else { + e.$options.hideable = true; + e.blur(); + } + }, + onChange: function (e) { + e.$options.hideable = false; + }, + onShow: function (e) { + $('#' + e.$editor.attr('id') + ' .md-input').textcomplete([ + { // emoji strategy + match: /\B:([\-+\w]*)$/, + search: function (term, callback) { + callback($.map(window.emojies, function (emoji) { + return emoji.indexOf(term) === 0 ? emoji : null; + })); + }, + template: function (value) { + return '' + '' + value + ''; + }, + replace: function (value) { + return ':' + value + ': '; + }, + index: 1 + } + ]); + + e.setContent(m.desc); + $('#' + e.$editor.attr('id') + ' .md-input').attr('maxlength', vm.inputLengthConfig.requestDescLength); + + var elei = $('#' + e.$editor.attr('id') + ' .md-input'); + angular.element(elei).css('height', '200px'); + angular.element(elei).css('color', '#333'); + + var inputInfo = angular.element(''); + inputInfo.addClass('pull-right'); + inputInfo.addClass('input-length'); + inputInfo.text(e.getContent().length + '/' + vm.inputLengthConfig.requestDescLength); + $('#' + e.$editor.attr('id') + ' .md-header').append(inputInfo); + $('#' + e.$editor.attr('id') + ' .md-input').on('input propertychange', function (evt) { + inputInfo.text(e.getContent().length + '/' + vm.inputLengthConfig.requestDescLength); + }); + + var ele = $('#' + e.$editor.attr('id') + ' .md-footer'); + angular.element(ele).addClass('text-right'); + angular.element(ele[0].childNodes[0]).addClass('btn-width-80'); + ele[0].childNodes[0].innerText = $translate.instant('FORUMS.BTN_SAVE'); + + var cbtn = angular.element(''); + cbtn.bind('click', function (evt) { + e.setContent(m.desc); + e.$options.hideable = true; + e.blur(); + }); + ele.append(cbtn); + $compile(e.$editor.contents())($scope); + }, + onPreview: function (e) { + $('#' + e.$editor.attr('id') + ' .md-footer').css('display', 'none'); + }, + onPreviewEnd: function (e) { + $('#' + e.$editor.attr('id') + ' .md-footer').css('display', 'block'); + } + }); + }; + + /** + * removeRequest + */ + vm.removeRequest = function () { + var modalOptions = { + closeButtonText: $translate.instant('REQUESTS.DELETE_CONFIRM_CANCEL'), + actionButtonText: $translate.instant('REQUESTS.DELETE_CONFIRM_OK'), + headerText: $translate.instant('REQUESTS.DELETE_CONFIRM_HEADER_TEXT'), + bodyText: $translate.instant('REQUESTS.DELETE_CONFIRM_BODY_TEXT') + }; + + ModalConfirmService.showModal({}, modalOptions) + .then(function (result) { + vm.request.$remove(function (res) { + NotifycationService.showSuccessNotify('REQUESTS.DELETE_SUCCESSFULLY'); + $state.go($state.previous.state.name || 'requests.list'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'REQUESTS.DELETE_FAILED'); + }); + }); + }; + + /** + * onRequestTitleEdited + */ + $scope.onRequestTitleEdited = function (modifyed) { + if (vm.request && modifyed) { + vm.request.$update(function (res) { + vm.request = res; + NotifycationService.showSuccessNotify('REQUESTS.EDIT_SUCCESSFULLY'); + }, function (res) { + NotifycationService.showErrorNotify(res.data.message, 'REQUESTS.EDIT_FAILED'); + }); + } + }; + } }()); diff --git a/modules/requests/client/less/requests.less b/modules/requests/client/less/requests.less index 013c4701..adf67e2d 100644 --- a/modules/requests/client/less/requests.less +++ b/modules/requests/client/less/requests.less @@ -20,6 +20,7 @@ border-radius: 4px !important; min-width: 160px !important; } + .visible-xxs-block { margin-bottom: 10px; } @@ -65,7 +66,36 @@ margin: 5px 0; font-size: 16px; } - .item-desc { - color: #999; + .request-item { + .item-desc { + color: #999; + } + .item-marked-desc { + color: #999; + margin-top: 10px; + } } -} \ No newline at end of file +} + +.request-wrapper { + padding: 20px 0; + .request-avatar { + img { + cursor: pointer; + float: left; + border-radius: 3px; + height: 60px; + width: 60px; + @media (max-width: @screen-xs-max) { + height: 40px; + width: 40px; + } + } + } + .request-list { + margin-left: 80px; + @media (max-width: @screen-xs-max) { + margin-left: 60px; + } + } +} diff --git a/modules/requests/client/views/requests-list.client.view.html b/modules/requests/client/views/requests-list.client.view.html index 79c7cdff..37145013 100644 --- a/modules/requests/client/views/requests-list.client.view.html +++ b/modules/requests/client/views/requests-list.client.view.html @@ -69,18 +69,18 @@ - +

{{item.title}}

{{item.desc}}
- {{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}} - {{item.createdAt | life }} - {{item.rewards}} - {{item.torrents.length}} - {{item.comments.length}} - + {{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}} + {{item.createdAt | life }} + {{item.rewards}} + {{item.torrents.length}} + {{item.comments.length}} + diff --git a/modules/requests/client/views/requests-my.client.view.html b/modules/requests/client/views/requests-my.client.view.html index e05fda91..36ef784b 100644 --- a/modules/requests/client/views/requests-my.client.view.html +++ b/modules/requests/client/views/requests-my.client.view.html @@ -69,18 +69,18 @@ - +

{{item.title}}

{{item.desc}}
- {{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}} - {{item.createdAt | life }} - {{item.rewards}} - {{item.comments.length}} - {{item.torrents.length}} - + {{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}} + {{item.createdAt | life }} + {{item.rewards}} + {{item.comments.length}} + {{item.torrents.length}} + diff --git a/modules/requests/client/views/requests-res.client.view.html b/modules/requests/client/views/requests-res.client.view.html index 37006bd6..8bc689f9 100644 --- a/modules/requests/client/views/requests-res.client.view.html +++ b/modules/requests/client/views/requests-res.client.view.html @@ -69,18 +69,18 @@ - +

{{item.title}}

{{item.desc}}
- {{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}} - {{item.createdAt | life }} - {{item.rewards}} - {{item.comments.length}} - {{item.torrents.length}} - + {{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}} + {{item.createdAt | life }} + {{item.rewards}} + {{item.comments.length}} + {{item.torrents.length}} + diff --git a/modules/requests/client/views/requests-view.client.view.html b/modules/requests/client/views/requests-view.client.view.html new file mode 100644 index 00000000..2b69f599 --- /dev/null +++ b/modules/requests/client/views/requests-view.client.view.html @@ -0,0 +1,91 @@ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ 'REQUESTS.FIELD_TITLE' | translate}}{{ 'REQUESTS.FIELD_TYPE' | translate}}{{ 'REQUESTS.FIELD_LIFE' | translate}}{{ 'REQUESTS.FIELD_REWARDS' | translate}}{{ 'REQUESTS.FIELD_RESPONSES' | translate}}{{ 'REQUESTS.FIELD_COMMENTS' | translate}}{{ 'REQUESTS.FIELD_USER' | translate}}
+

+
+ + + +
+

+
{{'MENU_TORRENTS_SUB.'+vm.request.type.toUpperCase() | translate}}{{vm.request.createdAt | life }}{{vm.request.rewards}}{{vm.request.comments.length}}{{vm.request.torrents.length}} + +
+
+
+
+ + {{ 'DO_UPLOAD' | translate}} + + + +
+
+ +
+
+
+
+
+
+
diff --git a/modules/torrents/client/config/torrents.client.routes.js b/modules/torrents/client/config/torrents.client.routes.js index e95a9b1f..a32ae932 100644 --- a/modules/torrents/client/config/torrents.client.routes.js +++ b/modules/torrents/client/config/torrents.client.routes.js @@ -22,7 +22,7 @@ $stateProvider .state('torrents.uploads', { - url: '/uploads', + url: '/uploads?req', templateUrl: '/modules/torrents/client/views/uploads-torrents.client.view.html', data: { pageTitle: 'PAGETITLE.UPLOAD'