feat(requests): add request my responses list view, route, controller

This commit is contained in:
OldHawk
2018-01-11 12:53:02 +08:00
parent ad264f5412
commit c5bb4f7969
13 changed files with 293 additions and 29 deletions

View File

@@ -376,7 +376,10 @@ module.exports = {
forumReplyContentLength: 2048,
makerGroupDescLength: 2048,
collectionsOverviewLength: 2048
collectionsOverviewLength: 2048,
requestDescLength: 1024,
requestCommentLength: 512
},
/**

View File

@@ -185,6 +185,7 @@
FORUM: 'Forum',
REQUESTS: 'Requests',
REQUESTS_MY: 'My Requests',
REQUESTS_RES: 'My Responses',
REQUESTS_ADD: 'Add Requests',
ADMIN_USER_LIST: 'User List',
ADMIN_USER_VIEW: 'View User',
@@ -705,6 +706,7 @@
REQUESTS: {
NAV_LIST: 'Requests List',
NAV_MY: 'My Requests',
NAV_RES: 'My Responses',
NAV_ADD: 'Add Request',
FORM_TITLE: 'Resource Title',
FORM_TITLE_REQUIRED: 'Resource title is required',
@@ -714,6 +716,7 @@
FORM_REWARDS_MAX_MIN: 'Rewards score numbers must more than {{min}} and less than {{max}}',
BTN_SUBMIT_REQUEST: 'Submit Request',
NO_MY_REQUESTS: 'You arent post any request.',
NO_RES_REQUESTS: 'You arent response any request.',
NO_REQUESTS: 'Has no anybody post request.',
STATUS_GETTING: 'Getting requests, please waiting ...',
STATUS_GETTING_ERROR: 'Getting requests ERROR!',
@@ -721,8 +724,10 @@
POST_REQUEST_FAILED: 'Create request failed',
FIELD_TITLE: 'Title',
FIELD_TYPE: 'Type',
FIELD_CREATEDAT: 'Created At',
FIELD_LIFE: 'Life',
FIELD_REWARDS: 'Rewards',
FIELD_COMMENTS: 'Comments',
FIELD_RESPONSES: 'responses',
FIELD_USER: 'User',
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}})',

View File

@@ -185,6 +185,7 @@
FORUM: '论坛',
REQUESTS: '求种',
REQUESTS_MY: '我的求种',
REQUESTS_RES: '我的响应',
REQUESTS_ADD: '我要求种',
ADMIN_USER_LIST: '用户管理',
ADMIN_USER_VIEW: '查看用户',
@@ -703,9 +704,10 @@
//requests
REQUESTS: {
NAV_LIST: '求种请求列表',
NAV_MY: '我的求种请求',
NAV_ADD: '发起求种请求',
NAV_LIST: '求种列表',
NAV_MY: '我的求种',
NAV_RES: '我的响应',
NAV_ADD: '发起请求',
FORM_TITLE: '资源标题',
FORM_TITLE_REQUIRED: '资源标题不能为空',
FORM_DESC: '对资源的要求',
@@ -714,6 +716,7 @@
FORM_REWARDS_MAX_MIN: '悬赏积分必须大于 {{min}} 且小于 {{max}}',
BTN_SUBMIT_REQUEST: '提交请求',
NO_MY_REQUESTS: '您没有提交过任何求种请求.',
NO_RES_REQUESTS: '您没有响应过任何求种请求.',
NO_REQUESTS: '还有没任何用户发起求种请求.',
STATUS_GETTING: '正在获取求种请求, 请稍候 ...',
STATUS_GETTING_ERROR: '获取求种请求失败!',
@@ -721,8 +724,10 @@
POST_REQUEST_FAILED: '创建求种请求失败!',
FIELD_TITLE: '求种标题',
FIELD_TYPE: '求种类型',
FIELD_CREATEDAT: '创建时间',
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}}).',

View File

@@ -31,6 +31,13 @@
pageTitle: 'PAGETITLE.REQUESTS_MY'
}
})
.state('requests.res', {
url: '/res',
templateUrl: '/modules/requests/client/views/requests-res.client.view.html',
data: {
pageTitle: 'PAGETITLE.REQUESTS_RES'
}
})
.state('requests.add', {
url: '/add',
templateUrl: '/modules/requests/client/views/requests-add.client.view.html',

View File

@@ -15,6 +15,7 @@
vm.itemsPerPageConfig = MeanTorrentConfig.meanTorrentConfig.itemsPerPage;
vm.requestsConfig = MeanTorrentConfig.meanTorrentConfig.requests;
vm.torrentTypeConfig = MeanTorrentConfig.meanTorrentConfig.torrentType;
vm.inputLengthConfig = MeanTorrentConfig.meanTorrentConfig.inputLength;
vm.request = {
type: 'movie',

View File

@@ -0,0 +1,88 @@
(function () {
'use strict';
angular
.module('requests')
.controller('RequestsResController', RequestsResController);
RequestsResController.$inject = ['$scope', '$rootScope', '$state', '$timeout', '$translate', 'Authentication', 'RequestsService', 'ScoreLevelService', 'MeanTorrentConfig', 'DebugConsoleService',
'NotifycationService', 'uibButtonConfig', 'marked'];
function RequestsResController($scope, $rootScope, $state, $timeout, $translate, Authentication, RequestsService, ScoreLevelService, MeanTorrentConfig, mtDebug,
NotifycationService, uibButtonConfig, marked) {
var vm = this;
vm.user = Authentication.user;
vm.itemsPerPageConfig = MeanTorrentConfig.meanTorrentConfig.itemsPerPage;
vm.requestsConfig = MeanTorrentConfig.meanTorrentConfig.requests;
vm.announceConfig = MeanTorrentConfig.meanTorrentConfig.announce;
/**
* getRequestsDesc
* @returns {*}
*/
vm.getRequestsDesc = function () {
var ts = $translate.instant('REQUESTS.DESC_RES', {
days: vm.requestsConfig.requestExpires / (60 * 60 * 1000 * 24),
admin: vm.announceConfig.admin
});
return marked(ts, {sanitize: true});
};
/**
* buildPager
*/
vm.buildPager = function () {
vm.pagedItems = [];
vm.itemsPerPage = vm.itemsPerPageConfig.requestListPerPage;
vm.currentPage = 1;
vm.figureOutItemsToDisplay();
};
/**
* figureOutItemsToDisplay
* @param callback
*/
vm.figureOutItemsToDisplay = function (callback) {
vm.getResRequests(vm.currentPage, function (items) {
vm.filterLength = items.total;
vm.pagedItems = items.rows;
if (callback) callback();
});
};
/**
* getResRequests
*/
vm.getResRequests = function (p, callback) {
vm.statusMsg = 'REQUESTS.STATUS_GETTING';
RequestsService.get({
skip: (p - 1) * vm.itemsPerPage,
limit: vm.itemsPerPage,
res_id: vm.user._id
}, function (data) {
vm.statusMsg = undefined;
mtDebug.info(data);
callback(data);
}, function (res) {
vm.statusMsg = 'REQUESTS.STATUS_GETTING_ERROR';
});
};
/**
* pageChanged
*/
vm.pageChanged = function () {
var element = angular.element('#top_of_follow_list');
vm.figureOutItemsToDisplay(function () {
$timeout(function () {
$('html,body').animate({scrollTop: element[0].offsetTop - 60}, 200);
}, 10);
});
};
}
}());

View File

@@ -4,12 +4,26 @@
.btn {
text-shadow: none !important;
}
@media (max-width: @screen-sm-max) {
.btn {
min-width: 160px !important;
}
}
@media (max-width: @screen-xs-max) {
.btn {
min-width: auto !important;
}
}
@media (max-width: @screen-xs) {
.btn {
margin: 0 5px !important;
border-radius: 4px !important;
min-width: 180px !important;
}
.visible-xxs-block {
margin-bottom: 10px;
}
}
}
.requests-desc {
@@ -34,7 +48,7 @@
textarea {
resize: vertical;
min-height: 120px;
max-height: 240px;
max-height: 300px;
}
}

View File

@@ -3,18 +3,23 @@
<div class="container">
<div class="padding-top-30 padding-bottom-30 text-center">
<div class="btn-group requests-group">
<a class="btn btn-default btn-width-200"
<a class="btn btn-default btn-width-180"
ui-sref="requests.list">
{{'REQUESTS.NAV_LIST' | translate}}
</a>
<a class="btn btn-success btn-width-200"
<a class="btn btn-success btn-width-180"
ui-sref="requests.add">
{{'REQUESTS.NAV_ADD' | translate}}
</a>
<a class="btn btn-default btn-width-200"
<div class="clearfix visible-xxs-block "></div>
<a class="btn btn-default btn-width-180"
ui-sref="requests.my">
{{'REQUESTS.NAV_MY' | translate}}
</a>
<a class="btn btn-default btn-width-180"
ui-sref="requests.res">
{{'REQUESTS.NAV_RES' | translate}}
</a>
</div>
</div>
@@ -51,10 +56,11 @@
</div>
</div>
<div class="form-group" show-errors>
<label for="desc" class="col-sm-3 control-label">{{ 'REQUESTS.FORM_DESC' | translate}}:</label>
<label for="requestDesc" class="col-sm-3 control-label">{{ 'REQUESTS.FORM_DESC' | translate}}:</label>
<div class="col-sm-9">
<textarea id="desc" name="desc" class="form-control"
ng-model="vm.request.desc" required/>
<textarea id="requestDesc" name="requestDesc" ng-model="vm.request.desc"
mt-markdown-editor="requestDesc" maxlength="{{vm.inputLengthConfig.requestDescLength}}"
required></textarea>
<div ng-messages="vm.requestForm.desc.$error" role="alert">
<p class="help-block error-text" ng-message="required">{{ 'REQUESTS.FORM_DESC_REQUIRED' | translate}}</p>
</div>

View File

@@ -3,18 +3,23 @@
<div class="container">
<div class="padding-top-30 padding-bottom-30 text-center">
<div class="btn-group requests-group">
<a class="btn btn-success btn-width-200"
<a class="btn btn-success btn-width-180"
ui-sref="requests.list">
{{'REQUESTS.NAV_LIST' | translate}}
</a>
<a class="btn btn-default btn-width-200"
<a class="btn btn-default btn-width-180"
ui-sref="requests.add">
{{'REQUESTS.NAV_ADD' | translate}}
</a>
<a class="btn btn-default btn-width-200"
<div class="clearfix visible-xxs-block "></div>
<a class="btn btn-default btn-width-180"
ui-sref="requests.my">
{{'REQUESTS.NAV_MY' | translate}}
</a>
<a class="btn btn-default btn-width-180"
ui-sref="requests.res">
{{'REQUESTS.NAV_RES' | translate}}
</a>
</div>
</div>
@@ -28,7 +33,7 @@
<div class="container">
<div class="margin-bottom-10 margin-top-10">
<div class="jumbotron text-center" ng-if="vm.statusMsg || vm.pagedItems.length<=0">
<div class="jumbotron margin-top-20 text-center" ng-if="vm.statusMsg || vm.pagedItems.length<=0">
<div ng-if="vm.statusMsg">
<h3 class="text-muted">{{vm.statusMsg | translate}}</h3>
</div>
@@ -55,22 +60,26 @@
<tr>
<th>{{ 'REQUESTS.FIELD_TITLE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_TYPE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_CREATEDAT' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_LIFE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_REWARDS' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_RESPONSES' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_COMMENTS' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_USER' | translate}}</th>
</tr>
</thead>
<tbody>
<tr class="request-item" ng-repeat="item in vm.pagedItems">
<td class="col-md-7 td-text-overflow">
<td class="col-md-6 td-text-overflow">
<h4>
<a ui-sref="requests.view({requestId: item._id})">{{item.title}}</a>
</h4>
<div class="item-desc text-long">{{item.desc}}</div>
</td>
<td class="col-md-1 td-v-middle text-center width-80">{{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}}</td>
<td class="col-md-2 td-v-middle text-center width-160">{{item.createdAt | date: 'yyyy-MM-dd HH:mm:ss'}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.createdAt | life }}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.rewards}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.torrents.length}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.comments.length}}</td>
<td class="col-md-1 td-v-middle text-center width-80">
<span user-info="item.user" info-name></span>
</td>

View File

@@ -3,18 +3,23 @@
<div class="container">
<div class="padding-top-30 padding-bottom-30 text-center">
<div class="btn-group requests-group">
<a class="btn btn-default btn-width-200"
<a class="btn btn-default btn-width-180"
ui-sref="requests.list">
{{'REQUESTS.NAV_LIST' | translate}}
</a>
<a class="btn btn-default btn-width-200"
<a class="btn btn-default btn-width-180"
ui-sref="requests.add">
{{'REQUESTS.NAV_ADD' | translate}}
</a>
<a class="btn btn-success btn-width-200"
<div class="clearfix visible-xxs-block "></div>
<a class="btn btn-success btn-width-180"
ui-sref="requests.my">
{{'REQUESTS.NAV_MY' | translate}}
</a>
<a class="btn btn-default btn-width-180"
ui-sref="requests.res">
{{'REQUESTS.NAV_RES' | translate}}
</a>
</div>
</div>
@@ -28,7 +33,7 @@
<div class="container">
<div class="margin-bottom-10 margin-top-10">
<div class="jumbotron text-center" ng-if="vm.statusMsg || vm.pagedItems.length<=0">
<div class="jumbotron margin-top-20 text-center" ng-if="vm.statusMsg || vm.pagedItems.length<=0">
<div ng-if="vm.statusMsg">
<h3 class="text-muted">{{vm.statusMsg | translate}}</h3>
</div>
@@ -55,22 +60,26 @@
<tr>
<th>{{ 'REQUESTS.FIELD_TITLE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_TYPE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_CREATEDAT' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_LIFE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_REWARDS' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_RESPONSES' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_COMMENTS' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_USER' | translate}}</th>
</tr>
</thead>
<tbody>
<tr class="request-item" ng-repeat="item in vm.pagedItems">
<td class="col-md-7 td-text-overflow">
<td class="col-md-6 td-text-overflow">
<h4>
<a ui-sref="requests.view({requestId: item._id})">{{item.title}}</a>
</h4>
<div class="item-desc text-long">{{item.desc}}</div>
</td>
<td class="col-md-1 td-v-middle text-center width-80">{{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}}</td>
<td class="col-md-2 td-v-middle text-center width-160">{{item.createdAt | date: 'yyyy-MM-dd HH:mm:ss'}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.createdAt | life }}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.rewards}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.comments.length}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.torrents.length}}</td>
<td class="col-md-1 td-v-middle text-center width-80">
<span user-info="item.user" info-name></span>
</td>

View File

@@ -0,0 +1,104 @@
<div ng-controller="RequestsResController as vm" ng-init="vm.buildPager();">
<div class="pagetop">
<div class="container">
<div class="padding-top-30 padding-bottom-30 text-center">
<div class="btn-group requests-group">
<a class="btn btn-default btn-width-180"
ui-sref="requests.list">
{{'REQUESTS.NAV_LIST' | translate}}
</a>
<a class="btn btn-default btn-width-180"
ui-sref="requests.add">
{{'REQUESTS.NAV_ADD' | translate}}
</a>
<div class="clearfix visible-xxs-block "></div>
<a class="btn btn-default btn-width-180"
ui-sref="requests.my">
{{'REQUESTS.NAV_MY' | translate}}
</a>
<a class="btn btn-success btn-width-180"
ui-sref="requests.res">
{{'REQUESTS.NAV_RES' | translate}}
</a>
</div>
</div>
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="requests-desc" ng-bind-html="vm.getRequestsDesc();"></div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="margin-bottom-10 margin-top-10">
<div class="jumbotron margin-top-20 text-center" ng-if="vm.statusMsg || vm.pagedItems.length<=0">
<div ng-if="vm.statusMsg">
<h3 class="text-muted">{{vm.statusMsg | translate}}</h3>
</div>
<div ng-if="!vm.statusMsg && vm.pagedItems.length<=0">
<i class="fa fa-users fa-2x text-muted" aria-hidden="true"></i>
<h3 class="text-muted">{{'REQUESTS.NO_RES_REQUESTS' | translate}}</h3>
</div>
</div>
<div ng-if="vm.pagedItems.length>0">
<div id="top_of_follow_list">
<div class="pagination-border-bottom">
<ul uib-pagination boundary-links="true" max-size="8" items-per-page="vm.itemsPerPage" total-items="vm.filterLength"
ng-model="vm.currentPage"
ng-change="vm.pageChanged()"
first-text="{{ 'PAGE_TEXT_FIRST' | translate}}" previous-text="{{ 'PAGE_TEXT_PREVIOUS' | translate}}"
next-text="{{ 'PAGE_TEXT_NEXT' | translate}}" last-text="{{ 'PAGE_TEXT_LAST' | translate}}">
</ul>
</div>
<div class="request-list">
<div class="table-responsive">
<table class="table table-hover tb-v-middle">
<thead>
<tr>
<th>{{ 'REQUESTS.FIELD_TITLE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_TYPE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_LIFE' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_REWARDS' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_RESPONSES' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_COMMENTS' | translate}}</th>
<th class="text-center">{{ 'REQUESTS.FIELD_USER' | translate}}</th>
</tr>
</thead>
<tbody>
<tr class="request-item" ng-repeat="item in vm.pagedItems">
<td class="col-md-6 td-text-overflow">
<h4>
<a ui-sref="requests.view({requestId: item._id})">{{item.title}}</a>
</h4>
<div class="item-desc text-long">{{item.desc}}</div>
</td>
<td class="col-md-1 td-v-middle text-center width-80">{{'MENU_TORRENTS_SUB.'+item.type.toUpperCase() | translate}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.createdAt | life }}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.rewards}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.comments.length}}</td>
<td class="col-md-1 td-v-middle text-center width-80">{{item.torrents.length}}</td>
<td class="col-md-1 td-v-middle text-center width-80">
<span user-info="item.user" info-name></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="pagination-border-top">
<ul uib-pagination boundary-links="true" max-size="8" items-per-page="vm.itemsPerPage" total-items="vm.filterLength"
ng-model="vm.currentPage"
ng-change="vm.pageChanged()"
first-text="{{ 'PAGE_TEXT_FIRST' | translate}}" previous-text="{{ 'PAGE_TEXT_PREVIOUS' | translate}}"
next-text="{{ 'PAGE_TEXT_NEXT' | translate}}" last-text="{{ 'PAGE_TEXT_LAST' | translate}}">
</ul>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -120,6 +120,7 @@ exports.list = function (req, res) {
var skip = 0;
var limit = 0;
var user_id = undefined;
var res_id = undefined;
if (req.query.skip !== undefined) {
skip = parseInt(req.query.skip, 10);
@@ -130,11 +131,17 @@ exports.list = function (req, res) {
if (req.query.user_id !== undefined) {
user_id = req.query.user_id;
}
if (req.query.res_id !== undefined) {
res_id = req.query.res_id;
}
var condition = {};
if (user_id !== undefined) {
condition.user = user_id;
}
if (res_id !== undefined) {
condition.responses = {$in: [res_id]};
}
var countQuery = function (callback) {
Request.count(condition, function (err, count) {
@@ -150,6 +157,8 @@ exports.list = function (req, res) {
Request.find(condition)
.sort('-createdAt')
.populate('user', 'username displayName profileImageURL isVip')
.skip(skip)
.limit(limit)
.exec(function (err, requests) {
if (err) {
return res.status(422).send({

View File

@@ -39,12 +39,16 @@ var RequestSchema = new Schema({
type: Schema.Types.ObjectId,
ref: 'Torrent'
}],
responses: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
accept: {
type: Schema.Types.ObjectId,
ref: 'Torrent'
},
comment: [CommonSchema.CommentSchema],
comments: [CommonSchema.CommentSchema],
createdAt: {
type: Date,