add admin torrents manager function

This commit is contained in:
OldHawk
2017-05-07 17:48:00 +08:00
parent 7b94e017d8
commit dde3a6d6bc
9 changed files with 483 additions and 9 deletions

View File

@@ -109,7 +109,11 @@
RANKING: 'Ranking',
RULES: 'Rules',
VIP: 'Vip',
FORUM: 'Forum'
FORUM: 'Forum',
ADMIN_USER_LIST: 'User List',
ADMIN_USER_VIEW: 'View User',
ADMIN_USER_EDIT: 'Edit User',
ADMIN_TORRENTS_LIST: 'Torrents LIst'
},
//TorrentsController & views

View File

@@ -109,7 +109,11 @@
RANKING: '排行榜',
RULES: '规则',
VIP: 'Vip',
FORUM: '论坛'
FORUM: '论坛',
ADMIN_USER_LIST: '用户管理',
ADMIN_USER_VIEW: '查看用户',
ADMIN_USER_EDIT: '编辑用户',
ADMIN_TORRENTS_LIST: '种子管理'
},
//TorrentsController & views

View File

@@ -11,7 +11,8 @@
function menuConfig(menuService) {
menuService.addSubMenuItem('topbar', 'admin', {
title: 'MENU_TORRENTS_ADMIN',
state: 'admin.torrents.list',
state: 'admin.torrents',
target: '_blank',
position: 1
});
}

View File

@@ -0,0 +1,21 @@
(function () {
'use strict';
// Setting up route
angular
.module('torrents.admin.routes')
.config(routeConfig);
routeConfig.$inject = ['$stateProvider'];
function routeConfig($stateProvider) {
$stateProvider
.state('admin.torrents', {
url: '/torrents',
templateUrl: '/modules/torrents/client/views/admin/admin-list.client.view.html',
data: {
pageTitle: 'PAGETITLE.ADMIN_TORRENTS_LIST'
}
});
}
}());

View File

@@ -0,0 +1,279 @@
(function () {
'use strict';
angular
.module('torrents')
.controller('TorrentsAdminController', TorrentsAdminController);
TorrentsAdminController.$inject = ['$scope', '$state', '$translate', '$timeout', 'Authentication', 'Notification', 'TorrentsService',
'MeanTorrentConfig', 'DownloadService', '$window'];
function TorrentsAdminController($scope, $state, $translate, $timeout, Authentication, Notification, TorrentsService, MeanTorrentConfig,
DownloadService, $window) {
var vm = this;
vm.user = Authentication.user;
vm.announce = MeanTorrentConfig.meanTorrentConfig.announce;
vm.tmdbConfig = MeanTorrentConfig.meanTorrentConfig.tmdbConfig;
vm.imdbConfig = MeanTorrentConfig.meanTorrentConfig.imdbConfig;
vm.resourcesTags = MeanTorrentConfig.meanTorrentConfig.resourcesTags;
vm.torrentSalesType = MeanTorrentConfig.meanTorrentConfig.torrentSalesType;
vm.searchTags = [];
vm.searchKey = '';
vm.releaseYear = undefined;
vm.topItems = 6;
/**
* If user is not signed in then redirect back home
*/
if (!Authentication.user) {
$state.go('authentication.signin');
}
/**
* commentBuildPager
* pagination init
*/
vm.torrentBuildPager = function () {
vm.torrentPagedItems = [];
vm.torrentItemsPerPage = 8;
vm.torrentCurrentPage = 1;
vm.torrentFigureOutItemsToDisplay();
};
/**
* commentFigureOutItemsToDisplay
* @param callback
*/
vm.torrentFigureOutItemsToDisplay = function (callback) {
vm.getMoviePageInfo(vm.torrentCurrentPage, function (items) {
vm.torrentFilterLength = items.total;
vm.torrentPagedItems = items.rows;
if (callback) callback();
});
};
/**
* commentPageChanged
*/
vm.torrentPageChanged = function () {
var element = angular.element('#top_of_torrent_list');
$('.tb-v-middle').fadeTo(100, 0.01, function () {
vm.torrentFigureOutItemsToDisplay(function () {
$timeout(function () {
$('.tb-v-middle').fadeTo(400, 1, function () {
//window.scrollTo(0, element[0].offsetTop - 60);
$('html,body').animate({scrollTop: element[0].offsetTop - 60}, 200);
});
}, 100);
});
});
};
/**
* onRadioTagClicked
* @param event
* @param n: tag name
*/
vm.onRadioTagClicked = function (event, n) {
var e = angular.element(event.currentTarget);
if (e.hasClass('btn-success')) {
e.removeClass('btn-success').addClass('btn-default');
vm.searchTags.splice(vm.searchTags.indexOf(n), 1);
} else {
e.addClass('btn-success').removeClass('btn-default').siblings().removeClass('btn-success').addClass('btn-default');
vm.searchTags.push(n);
angular.forEach(e.siblings(), function (se) {
if (vm.searchTags.indexOf(se.value) !== -1) {
vm.searchTags.splice(vm.searchTags.indexOf(se.value), 1);
}
});
}
e.blur();
vm.torrentBuildPager();
};
/**
* onCheckboxTagClicked
* @param event
* @param n: tag name
*/
vm.onCheckboxTagClicked = function (event, n) {
var e = angular.element(event.currentTarget);
if (e.hasClass('btn-success')) {
vm.searchTags.push(n);
} else {
vm.searchTags.splice(vm.searchTags.indexOf(n), 1);
}
vm.torrentBuildPager();
};
/**
* onKeysKeyDown
* @param evt
*/
vm.onKeysKeyDown = function (evt) {
if (evt.keyCode === 13) {
vm.torrentBuildPager();
}
};
/**
* getMoviePageInfo
* @param p: page number
*/
vm.getMoviePageInfo = function (p, callback) {
TorrentsService.get({
skip: (p - 1) * vm.torrentItemsPerPage,
limit: vm.torrentItemsPerPage,
keys: vm.searchKey.trim(),
torrent_status: 'reviewed',
torrent_type: 'movie',
torrent_release: vm.releaseYear,
torrent_tags: vm.searchTags
}, function (items) {
if (items.length === 0) {
Notification.error({
message: '<i class="glyphicon glyphicon-remove"></i> ' + $translate.instant('MOVIE_PAGE_INFO_EMPTY')
});
} else {
callback(items);
console.log(items);
}
}, function (err) {
Notification.error({
message: '<i class="glyphicon glyphicon-remove"></i> ' + $translate.instant('MOVIE_PAGE_INFO_ERROR')
});
});
};
/**
* getTagTitle
* @param tag: tag name
* @returns {*}
*/
vm.getTagTitle = function (tag) {
var tmp = tag;
var find = false;
angular.forEach(vm.resourcesTags.movie.radio, function (item) {
angular.forEach(item.value, function (sitem) {
if (sitem.name === tag) {
tmp = item.name;
find = true;
}
});
});
if (!find) {
angular.forEach(vm.resourcesTags.movie.checkbox, function (item) {
angular.forEach(item.value, function (sitem) {
if (sitem.name === tag) {
tmp = item.name;
}
});
});
}
return tmp;
};
/**
* clearAllCondition
*/
vm.clearAllCondition = function () {
vm.searchKey = '';
vm.searchTags = [];
$('.btn-tag').removeClass('btn-success').addClass('btn-default');
vm.torrentBuildPager();
};
/**
* onTagClicked
* @param tag: tag name
*/
vm.onTagClicked = function (tag) {
$timeout(function () {
angular.element('#tag_' + tag).trigger('click');
}, 100);
};
/**
* onReleaseClicked
* @param y
*/
vm.onReleaseClicked = function (y) {
if (vm.releaseYear === y) {
vm.releaseYear = undefined;
} else {
vm.releaseYear = y;
}
vm.torrentBuildPager();
};
/**
* getSaleTypeDesc
*/
vm.getSaleTypeDesc = function (item) {
var desc = '';
angular.forEach(vm.torrentSalesType.value, function (st) {
if (st.name === item.torrent_sale_status) {
desc = st.desc;
}
});
return desc;
};
/**
* onMoreTagsClicked
*/
vm.onMoreTagsClicked = function () {
var e = $('.more-tags');
var i = $('#more-tags-icon');
if (!e.hasClass('panel-collapsed')) {
e.slideUp();
e.addClass('panel-collapsed');
i.removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down');
} else {
e.slideDown();
e.removeClass('panel-collapsed');
i.removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up');
}
};
/**
* downloadTorrent
* @param id
*/
vm.downloadTorrent = function (id) {
var url = '/api/torrents/download/' + id;
DownloadService.downloadFile(url, null, function (status) {
if (status === 200) {
Notification.success({
message: '<i class="glyphicon glyphicon-ok"></i> ' + $translate.instant('TORRENTS_DOWNLOAD_SUCCESSFULLY')
});
}
}, function (err) {
Notification.error({
title: 'ERROR',
message: '<i class="glyphicon glyphicon-remove"></i> ' + $translate.instant('TORRENT_DOWNLOAD_ERROR')
});
});
};
/**
* openTorrentInfo
* @param id
*/
vm.openTorrentInfo = function (id) {
var url = $state.href('torrents.view', {torrentId: id});
$window.open(url, '_blank');
};
}
}());

View File

@@ -23,8 +23,6 @@
vm.releaseYear = undefined;
vm.topItems = 6;
vm.torrentTabs = [];
/**
* If user is not signed in then redirect back home
*/

View File

@@ -0,0 +1,166 @@
<section class="container padding-top-10" ng-controller="TorrentsAdminController as vm" ng-init="vm.torrentBuildPager();">
<div class="panel panel-default">
<div class="panel-heading text-center">
<h3 class="panel-title" translate="TAGS_SEARCH"></h3>
</div>
<div class="panel-body">
<div class="col-md-10 col-md-offset-1">
<dl class="dl-horizontal">
<dt class="h-line">{{ 'CA_KEYWORD' | translate}}:</dt>
<dd class="h-line">
<div class="row" style="">
<div class="col-sm-7">
<input type="text" class="form-control" ng-model="vm.searchKey"
ng-keydown="vm.onKeysKeyDown($event);"
placeholder="{{ 'PH_KEYWORD' | translate}}">
</div>
<div class="col-sm-5">
<span class="label label-tag text-uppercase margin-left-m-20 incline-block-valign"
title="{{ 'TITLE_ALT.MORE_TAGS' | translate}}"
ng-click="vm.onMoreTagsClicked();">
<i class="glyphicon glyphicon-chevron-down" id="more-tags-icon"></i> {{ 'MORE_TAGS' | translate}}
</span>
<span class="label label-tag text-uppercase incline-block-valign"
title="{{ 'TITLE_ALT.RESET_TAGS' | translate}}"
ng-click="vm.clearAllCondition();">
<i class="glyphicon glyphicon-repeat"></i> {{ 'CA_RESET' | translate}}
</span>
</div>
</div>
</dd>
<div class="more-tags panel-collapsed" style="display: none;">
<div ng-repeat="item in vm.resourcesTags.movie.radio">
<dt class="h-line">{{ 'RESOURCESTAGS.'+item.name+'.SELF' | translate}}</dt>
<dd class="h-line">
<div class="btn-group btn-group-xs" role="group">
<button ng-repeat="sitem in item.value" id="tag_{{sitem.name}}"
class="btn btn-xs btn-default btn-tag" value="{{sitem.name}}"
ng-click="vm.onRadioTagClicked($event, sitem.name)">
{{ 'RESOURCESTAGS.' + item.name + '.' + sitem.name | translate}}
</button>
</span>
</div>
</dd>
</div>
<div ng-repeat="item in vm.resourcesTags.movie.checkbox">
<dt class="h-line">{{ 'RESOURCESTAGS.'+item.name+'.SELF' | translate}}</dt>
<dd class="h-line">
<div class="btn-group btn-group-xs" role="group">
<button ng-repeat="sitem in item.value" id="tag_{{sitem.name}}"
class="btn btn-xs btn-default btn-tag" value="{{sitem.name}}"
ng-click="vm.onCheckboxTagClicked($event, sitem.name)"
toggle-class="btn-success" base-class="btn-default" onclick="this.blur();">
{{ 'RESOURCESTAGS.' + item.name + '.' + sitem.name | translate}}
</button>
</div>
</dd>
</div>
</div>
</dl>
</div>
</div>
</div>
<div class="torrent-list" id="top_of_torrent_list">
<div class="pagination-div-top">
<uib-pagination boundary-links="true" max-size="8" items-per-page="vm.torrentItemsPerPage" total-items="vm.torrentFilterLength"
ng-model="vm.torrentCurrentPage" ng-change="vm.torrentPageChanged()"
first-text="{{ 'PAGE_TEXT_FIRST' | translate}}" previous-text="{{ 'PAGE_TEXT_PREVIOUS' | translate}}"
next-text="{{ 'PAGE_TEXT_NEXT' | translate}}" last-text="{{ 'PAGE_TEXT_LAST' | translate}}">
</uib-pagination>
</div>
<div class="table-responsive">
<table class="table table-hover tb-v-middle">
<thead>
<tr>
<th>{{ 'TABLE_FIELDS.INFO' | translate}}</th>
<th>{{ 'TABLE_FIELDS.VOTES' | translate}}</th>
<th>{{ 'TABLE_FIELDS.LIFETIME' | translate}}</th>
<th>{{ 'TABLE_FIELDS.SIZE' | translate}}</th>
<th>{{ 'TABLE_FIELDS.SEEDS_LEECHERS_FINISHED' | translate}}</th>
<th>{{ 'TABLE_FIELDS.PUBLISHER' | translate}}</th>
</tr>
</thead>
<tbody>
<tr class="torrent-list-info" ng-repeat="item in vm.torrentPagedItems" ng-click="vm.openTorrentInfo(item._id);">
<td class="col-md-7 td-text-overflow">
<div class="media">
<div class="media-left">
<img class="media-object" ng-src="{{vm.tmdbConfig.poster_list_base_url}}{{item.torrent_img}}" alt="...">
</div>
<div class="media-body">
<h5 class="media-heading">{{item.torrent_original_title}}
<span ng-show="item.torrent_original_title!=item.torrent_title"> / {{item.torrent_title}}</span>
<span class="label label-download text-uppercase"
title="{{ 'TITLE_ALT.DOWNLOAD_TORRENT' | translate}}"
ng-click="vm.downloadTorrent(item._id); $event.stopPropagation();">
<i class="glyphicon glyphicon-arrow-right"></i> {{ 'CA_DOWNLOAD' | translate}}
</span>
</h5>
<div class="list-all-genres">
<span class="genres-item" ng-repeat="t in item.torrent_genres">{{t}}</span>
</div>
<div class="text-long">{{item.torrent_filename | filename}}</div>
<div class="list-all-tags">
<!--<span class="label label-success text-uppercase">{{ item.torrent_type}}</span>-->
<span class="label label-release label-warning" ng-click="vm.onReleaseClicked(item.torrent_release); $event.stopPropagation();">
{{ item.torrent_release}}
</span>
<span class="label label-sale" ng-if="item.isSaling"
title="{{vm.getSaleTypeDesc(item);}} | {{ 'SALE_EXPIRES_TIME' | translate}}: {{item.torrent_sale_expires | date: 'MM-dd HH:mm'}}"
ng-class="{'label-default': !item.isSaling, 'label-success': item.isSaling}">
{{item.torrent_sale_status}} {{item.torrent_sale_expires | unlife}}
</span>
<span ng-repeat="t in item.torrent_tags">
<span class="label label-tag" ng-class="{'used': vm.searchTags.indexOf(t) !== -1}"
ng-click="vm.onTagClicked(t); $event.stopPropagation();">
{{ 'RESOURCESTAGS.' + vm.getTagTitle(t) + '.' + t | translate}}
</span>
</span>
</div>
</div>
</div>
</td>
<td class="col-md-1 td-v-middle text-center">
<span title="{{ 'TITLE_ALT.IMDB_VOTES' | translate}}"
class="pull-right torrent-votes"><kbd>IMDB</kbd> {{item.torrent_imdb_votes | number : 1}}</span>
</td>
<td class="col-md-1 td-v-middle">{{item.createdat | life}}</td>
<td class="col-md-1 td-v-middle">{{item.torrent_size | bytes:2}}</td>
<td class="col-md-1 td-v-middle list-user-info">
<p class="no-margin-p" title="{{ 'TITLE_ALT.SEEDS' | translate}}">
<span class="glyphicon glyphicon-arrow-up torrent-up"></span>
{{item.torrent_seeds}}
</p>
<p class="no-margin-p" title="{{ 'TITLE_ALT.LEECHERS' | translate}}">
<span class="glyphicon glyphicon-arrow-down torrent-down"></span>
{{item.torrent_leechers}}
</p>
<p class="no-margin-p" title="{{ 'TITLE_ALT.FINISHED' | translate}}">
<span class="glyphicon glyphicon-ok torrent-finished"></span>
{{item.torrent_finished}}
</p>
</td>
<td class="col-md-1 td-v-middle">{{item.user.displayName}}</td>
</tr>
</tbody>
</table>
</div>
<div class="pagination-div-bottom">
<uib-pagination boundary-links="true" max-size="8" items-per-page="vm.torrentItemsPerPage" total-items="vm.torrentFilterLength"
ng-model="vm.torrentCurrentPage" ng-change="vm.torrentPageChanged()"
first-text="{{ 'PAGE_TEXT_FIRST' | translate}}" previous-text="{{ 'PAGE_TEXT_PREVIOUS' | translate}}"
next-text="{{ 'PAGE_TEXT_NEXT' | translate}}" last-text="{{ 'PAGE_TEXT_LAST' | translate}}">
</uib-pagination>
</div>
</div>
</section>

View File

@@ -11,7 +11,8 @@
function menuConfig(menuService) {
menuService.addSubMenuItem('topbar', 'admin', {
title: 'MENU_USERS_ADMIN',
state: 'admin.users'
state: 'admin.users',
target: '_blank'
});
}
}());

View File

@@ -16,7 +16,7 @@
controller: 'UserListController',
controllerAs: 'vm',
data: {
pageTitle: 'Users List'
pageTitle: 'PAGETITLE.ADMIN_USER_LIST'
}
})
.state('admin.user', {
@@ -28,7 +28,7 @@
userResolve: getUser
},
data: {
pageTitle: 'Edit {{ userResolve.displayName }}'
pageTitle: 'PAGETITLE.ADMIN_USER_VIEW'
}
})
.state('admin.user-edit', {
@@ -40,7 +40,7 @@
userResolve: getUser
},
data: {
pageTitle: 'Edit User {{ userResolve.displayName }}'
pageTitle: 'PAGETITLE.ADMIN_USER_EDIT'
}
});