diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 8ded24b4..0714e64b 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -165,25 +165,25 @@ class AdminController extends Controller return view('admin.users'); } - public function getUserData() + public function getUserData(Request $request) { - $users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at']); + $users = collect(); - $permissionTextMap = [ - User::BANNED => trans('admin.users.status.banned'), - User::NORMAL => trans('admin.users.status.normal'), - User::ADMIN => trans('admin.users.status.admin'), - User::SUPER_ADMIN => trans('admin.users.status.super-admin') - ]; + if ($request->has('uid')) { + $users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at']) + ->where('uid', intval($request->input('uid'))); + } else { + $users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at']); + } return Datatables::of($users)->editColumn('email', function ($user) { return $user->email ?: 'EMPTY'; - })->editColumn('permission', function ($user) use ($permissionTextMap) { - return array_get($permissionTextMap, $user->permission); }) ->setRowId('uid') - ->editColumn('score', 'vendor.admin-operations.users.score') - ->addColumn('operations', 'vendor.admin-operations.users.operations') + ->addColumn('operations', app('user.current')->getPermission()) + ->addColumn('players_count', function ($user) { + return Player::where('uid', $user->uid)->count(); + }) ->make(true); } @@ -198,15 +198,17 @@ class AdminController extends Controller return view('admin.players'); } - public function getPlayerData() + public function getPlayerData(Request $request) { - $players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified']); + $players = collect(); + if ($request->has('uid')) { + $players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified']) + ->where('uid', intval($request->input('uid'))); + } else { + $players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified']); + } - return Datatables::of($players)->editColumn('preference', 'vendor.admin-operations.players.preference') - ->setRowId('pid') - ->addColumn('previews', 'vendor.admin-operations.players.previews') - ->addColumn('operations', 'vendor.admin-operations.players.operations') - ->make(true); + return Datatables::of($players)->setRowId('pid')->make(true); } /** @@ -228,6 +230,10 @@ class AdminController extends Controller 'email' => 'required|email' ]); + if ($users->get($request->input('email'), 'email')) { + return json(trans('admin.users.operations.email.existed', ['email' => $request->input('email')]), 1); + } + $user->setEmail($request->input('email')); return json(trans('admin.users.operations.email.success'), 0); @@ -354,6 +360,28 @@ class AdminController extends Controller $player->delete(); return json(trans('admin.players.delete.success'), 0); + } elseif ($action == "name") { + $player->rename($request->input('name')); + + return json(trans('admin.players.name.success', ['player' => $player->player_name]), 0, ['name' => $player->player_name]); + } + } + + /** + * Get one user information + * + * @param string $uid + * @return JsonResponse + */ + public function getOneUser($uid, UserRepository $users) + { + $user = $users->get(intval($uid)); + if ($user) { + return json('success', 0, ['user' => $user->makeHidden([ + 'password', 'ip', 'last_sign_at', 'register_at' + ])->toArray()]); + } else { + return json('No such user.', 1); } } diff --git a/app/Http/Controllers/ClosetController.php b/app/Http/Controllers/ClosetController.php index 5f07b80b..7e35742c 100644 --- a/app/Http/Controllers/ClosetController.php +++ b/app/Http/Controllers/ClosetController.php @@ -25,43 +25,40 @@ class ClosetController extends Controller $this->closet = new Closet(session('uid')); } - public function index(Request $request) + public function index() + { + return view('user.closet')->with('user', app('user.current')); + } + + public function getClosetData(Request $request) { $category = $request->input('category', 'skin'); - $page = $request->input('page', 1); - $page = $page <= 0 ? 1 : $page; + $page = abs($request->input('page', 1)); $q = $request->input('q', null); $items = []; if ($q) { - foreach (['skin', 'cape'] as $category) { - // do search - foreach ($this->closet->getItems($category) as $item) { - if (strstr($item->name, $q)) { - $items[$category][] = $item; - } + // do search + foreach ($this->closet->getItems($category) as $item) { + if (stristr($item->name, $q)) { + $items[] = $item; } } } else { - $items['skin'] = $this->closet->getItems('skin'); - $items['cape'] = $this->closet->getItems('cape'); + $items = $this->closet->getItems($category); } // pagination - $total_pages = []; + $total_pages = ceil(count($items) / 6); - foreach ($items as $key => $value) { - $total_pages[] = ceil(count($items[$key]) / 6); - $items[$key] = array_slice($value, ($page-1)*6, 6); - } + $items = array_slice($items, ($page - 1) * 6, 6); - return view('user.closet')->with('items', $items) - ->with('page', $page) - ->with('q', $q) - ->with('category', $category) - ->with('total_pages', $total_pages ? max($total_pages) : 0) - ->with('user', app('user.current')); + return response()->json([ + 'category' => $category, + 'items' => $items, + 'total_pages' => $total_pages + ]); } public function info() diff --git a/app/Http/Controllers/PlayerController.php b/app/Http/Controllers/PlayerController.php index 6f639d3a..5b91d11a 100644 --- a/app/Http/Controllers/PlayerController.php +++ b/app/Http/Controllers/PlayerController.php @@ -138,9 +138,13 @@ class PlayerController extends Controller return json(trans('user.player.set.success', ['name' => $this->player->player_name]), 0); } - public function clearTexture() + public function clearTexture(Request $request) { - $this->player->clearTexture(); + $types = array_filter(['steve', 'alex', 'cape'], function ($type) use ($request) { + return $request->input($type); + }); + + $this->player->clearTexture($types); return json(trans('user.player.clear.success', ['name' => $this->player->player_name]), 0); } diff --git a/app/Http/Controllers/PluginController.php b/app/Http/Controllers/PluginController.php index ce96c470..21545ea0 100644 --- a/app/Http/Controllers/PluginController.php +++ b/app/Http/Controllers/PluginController.php @@ -75,13 +75,13 @@ class PluginController extends Controller return trans($plugin->description); }) ->editColumn('author', function ($plugin) { - return "".trans($plugin->author).""; + return ['author' => trans($plugin->author), 'url' => $plugin->url]; }) ->addColumn('status', function ($plugin) { return trans('admin.plugins.status.'.($plugin->isEnabled() ? 'enabled' : 'disabled')); }) ->addColumn('operations', function ($plugin) { - return view('vendor.admin-operations.plugins.operations', compact('plugin')); + return ['enabled' => $plugin->isEnabled(), 'hasConfigView' => $plugin->hasConfigView()]; }) ->make(true); } diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index ea1bc175..e9e5afcf 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -32,7 +32,7 @@ class SetupController extends Controller { $this->validate($request, [ 'email' => 'required|email', - 'password' => 'required|min:6|max:16|confirmed', + 'password' => 'required|min:8|max:16|confirmed', 'site_name' => 'required' ]); diff --git a/app/Http/Controllers/SkinlibController.php b/app/Http/Controllers/SkinlibController.php index 7e7a4bba..d73ef76e 100644 --- a/app/Http/Controllers/SkinlibController.php +++ b/app/Http/Controllers/SkinlibController.php @@ -32,41 +32,41 @@ class SkinlibController extends Controller { $filter = $request->input('filter', 'skin'); $sort = $request->input('sort', 'time'); - $uid = $request->input('uid', session('uid')); - $page = $request->input('page', 1); - $page = $page <= 0 ? 1 : $page; + $uid = intval($request->input('uid', 0)); + $page = $request->input('page', 1) <= 0 ? 1 : $request->input('page', 1); $sort_by = ($sort == "time") ? "upload_at" : $sort; if ($filter == "skin") { - $textures = Texture::where(function($query) { - $query->where('type', '=', 'steve') - ->orWhere('type', '=', 'alex'); - })->orderBy($sort_by, 'desc'); - - } elseif ($filter == "user") { - $textures = Texture::where('uploader', $uid)->orderBy($sort_by, 'desc'); - + $textures = Texture::where('type', 'steve')->orWhere('type', 'alex'); } else { - $textures = Texture::where('type', $filter)->orderBy($sort_by, 'desc'); + $textures = Texture::where('type', $filter); + } + + $textures = $textures->orderBy($sort_by, 'desc')->get(); + + if ($uid != 0) { + $textures = $textures->where('uploader', $uid); } if (!is_null($this->user)) { // show private textures when show uploaded textures of current user - if (!$this->user->isAdmin()) - $textures = $textures->where('public', '1') - ->orWhere('uploader', $this->user->uid); + if ($uid != $this->user->uid && !$this->user->isAdmin()) { + $textures = $textures->where('public', 1) + ->merge($textures->where('uploader', $this->user->uid)); + } } else { - $textures = $textures->where('public', '1'); + $textures = $textures->where('public', 1); } $total_pages = ceil($textures->count() / 20); - $textures = $textures->skip(($page - 1) * 20)->take(20)->get(); + $textures = $textures->slice(($page - 1) * 20); return view('skinlib.index')->with('user', $this->user) ->with('sort', $sort) ->with('filter', $filter) + ->with('uploader', $uid) ->with('textures', $textures) ->with('page', $page) ->with('total_pages', $total_pages); @@ -80,22 +80,36 @@ class SkinlibController extends Controller $sort_by = ($sort == "time") ? "upload_at" : $sort; + if ($q == '') { + return redirect('skinlib'); + } + if ($filter == "skin") { $textures = Texture::like('name', $q)->where(function($query) use ($q) { - $query->where('public', '=', '1') - ->where('type', '=', 'steve') + $query->where('type', '=', 'steve') ->orWhere('type', '=', 'alex'); })->orderBy($sort_by, 'desc')->get(); } else { $textures = Texture::like('name', $q) ->where('type', $filter) - ->where('public', '1') + ->where('public', 1) ->orderBy($sort_by, 'desc')->get(); } + if (!is_null($this->user)) { + // show private textures when show uploaded textures of current user + if (!$this->user->isAdmin()) { + $textures = $textures->where('public', 1) + ->merge($textures->where('uploader', $this->user->uid)); + } + } else { + $textures = $textures->where('public', 1); + } + return view('skinlib.search')->with('user', $this->user) ->with('sort', $sort) ->with('filter', $filter) + ->with('uploader', 0) ->with('q', $q) ->with('textures', $textures); } @@ -153,6 +167,7 @@ class SkinlibController extends Controller $t->upload_at = Utils::getTimeFormatted(); $cost = $t->size * (($t->public == "1") ? Option::get('score_per_storage') : Option::get('private_score_per_storage')); + $cost += option('score_per_closet_item'); if ($this->user->getScore() < $cost) return json(trans('skinlib.upload.lack-score'), 7); @@ -182,7 +197,7 @@ class SkinlibController extends Controller } } - public function delete(Request $request) + public function delete(Request $request, UserRepository $users) { $result = Texture::find($request->tid); @@ -197,17 +212,24 @@ class SkinlibController extends Controller Storage::delete($result['hash']); if (option('return_score')) { - if ($result->public == 1) - $this->user->setScore($result->size * Option::get('score_per_storage'), 'plus'); + if ($result->public == 1) { + $users->get($result->uploader)->setScore($result->size * Option::get('score_per_storage'), 'plus'); + foreach (Closet::all() as $closet) { + if ($closet->has($result->tid)) { + $closet->remove($result->tid); + $users->get($closet->uid)->setScore(option('score_per_closet_item'), 'plus'); + } + } + } else - $this->user->setScore($result->size * Option::get('private_score_per_storage'), 'plus'); + $users->get($result->uploader)->setScore($result->size * Option::get('private_score_per_storage'), 'plus'); } if ($result->delete()) return json(trans('skinlib.delete.success'), 0); } - public function privacy(Request $request) + public function privacy(Request $request, UserRepository $users) { $t = Texture::find($request->input('tid')); $type = $t->type; @@ -227,12 +249,12 @@ class SkinlibController extends Controller if ($closet->uid != $uid && $closet->has($t->tid)) { $closet->remove($t->tid); if (option('return_score')) { - User::find($closet->uid)->setScore(option('score_per_closet_item'), 'plus'); + $users->get($closet->uid)->setScore(option('score_per_closet_item'), 'plus'); } } } - app('user.current')->setScore( + $users->get($t->uploader)->setScore( $t->size * (option('private_score_per_storage') - option('score_per_storage')) * ($t->public == 1 ? -1 : 1), 'plus' ); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 569f7de1..d37731a1 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -90,9 +90,9 @@ class UserController extends Controller * Handle changing user profile. * * @param Request $request - * @return void + * @return mixed */ - public function handleProfile(Request $request) + public function handleProfile(Request $request, UserRepository $users) { $action = $request->input('action', ''); @@ -129,6 +129,10 @@ class UserController extends Controller 'password' => 'required|min:8|max:16' ]); + if ($users->get($request->input('new_email'), 'email')) { + return json(trans('user.profile.email.existed'), 1); + } + if (!$this->user->verifyPassword($request->input('password'))) return json(trans('user.profile.email.wrong-password'), 1); diff --git a/app/Http/Routes/web.php b/app/Http/Routes/web.php index b512ae65..bdaf3d56 100644 --- a/app/Http/Routes/web.php +++ b/app/Http/Routes/web.php @@ -65,6 +65,7 @@ Route::group(['middleware' => 'auth', 'prefix' => 'user'], function () // Closet Route::get ('/closet', 'ClosetController@index'); + Route::get ('/closet-data', 'ClosetController@getClosetData'); Route::post('/closet/add', 'ClosetController@add'); Route::post('/closet/remove', 'ClosetController@remove'); Route::post('/closet/rename', 'ClosetController@rename'); @@ -107,6 +108,7 @@ Route::group(['middleware' => 'admin', 'prefix' => 'admin'], function () Route::get('/players', 'AdminController@players'); Route::get('/player-data', 'AdminController@getPlayerData'); + Route::get('/user/{uid}', 'AdminController@getOneUser'); // ajax handlers Route::post('/users', 'AdminController@userAjaxHandler'); diff --git a/app/Models/Player.php b/app/Models/Player.php index 4aab2113..acbe5107 100644 --- a/app/Models/Player.php +++ b/app/Models/Player.php @@ -97,17 +97,22 @@ class Player extends Model /** * Clear the textures of player. * - * @return mixed + * @param array|string $types + * @return $this */ - public function clearTexture() + public function clearTexture($types) { - $this->setPreference('default'); + $types = (array) $types; - return $this->setTexture([ - 'tid_steve' => 0, - 'tid_alex' => 0, - 'tid_cape' => 0 - ]); + $map = []; + + foreach ($types as $type) { + $map["tid_$type"] = 0; + } + + $this->setTexture($map); + + return $this; } /** diff --git a/bower.json b/bower.json index 867479f8..88e00a64 100644 --- a/bower.json +++ b/bower.json @@ -24,6 +24,10 @@ "font-awesome": "Font-Awesome#^4.6.3", "bootstrap-fileinput": "^4.3.3", "bootstrap": "^3.3.6", - "sweetalert2": "^4.1.6" + "sweetalert2": "^4.1.6", + "jqPaginator": "^1.2.0" + }, + "resolutions": { + "jquery": "1.9.1 - 3" } } diff --git a/gulpfile.js b/gulpfile.js index d1a8c8af..d9e0d0ea 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,8 +1,8 @@ /* * @Author: printempw * @Date: 2016-07-21 13:38:26 -* @Last Modified by: printempw -* @Last Modified time: 2017-01-22 20:45:06 + * @Last Modified by: g-plane + * @Last Modified time: 2017-04-26 15:39:46 */ 'use strict'; @@ -35,6 +35,7 @@ var vendorScripts = [ 'toastr/toastr.min.js', 'es6-promise/es6-promise.auto.min.js', 'sweetalert2/dist/sweetalert2.min.js', + 'jqPaginator/dist/jqPaginator.min.js', 'resources/assets/dist/scripts/general.js', ]; diff --git a/resources/assets/src/scripts/admin.js b/resources/assets/src/scripts/admin.js index 3a9ce350..ca776546 100644 --- a/resources/assets/src/scripts/admin.js +++ b/resources/assets/src/scripts/admin.js @@ -1,16 +1,39 @@ /* * @Author: printempw * @Date: 2016-07-22 14:02:44 - * @Last Modified by: printempw - * @Last Modified time: 2017-01-21 10:58:50 + * @Last Modified by: g-plane + * @Last Modified time: 2017-04-28 19:54:02 */ 'use strict'; +let pluginsTable; + $(document).ready(function() { $('input').iCheck({ checkboxClass: 'icheckbox_square-blue' }); + swal.setDefaults({ + confirmButtonText: trans('general.confirm'), + cancelButtonText: trans('general.cancel') + }); + + $.extend(true, $.fn.dataTable.defaults, { + language: trans('vendor.datatables'), + scrollX: true, + pageLength: 25, + autoWidth: false, + processing: true, + serverSide: true + }); + + if (window.location.href.indexOf(url('admin/users')) >= 0) { + initUsersTable(); + } else if (window.location.href.indexOf(url('admin/players')) >= 0) { + initPlayersTable(); + } else if (window.location.href.indexOf(url('admin/plugins/manage')) >= 0) { + pluginsTable = initPluginsTable(); + } }); $('#layout-skins-list [data-skin]').click(function(e) { @@ -37,67 +60,75 @@ $('#color-submit').click(function() { }); function changeUserEmail(uid) { - var email = prompt(trans('admin.newUserEmail')); - - if (!email) return; - - $.ajax({ - type: "POST", - url: "./users?action=email", - dataType: "json", - data: { 'uid': uid, 'email': email }, - success: function(json) { - if (json.errno == 0) { - $($('tr#'+uid+' > td')[1]).html(email); - toastr.success(json.msg); - } else { - toastr.warning(json.msg); - } - }, - error: showAjaxError + let dom = $(`tr#user-${uid} > td:nth-child(2)`); + swal({ + text: trans('admin.newUserEmail'), + showCancelButton: true, + input: 'text', + inputValue: dom.text() + }).then(email => { + $.ajax({ + type: "POST", + url: "./users?action=email", + dataType: "json", + data: { 'uid': uid, 'email': email }, + success: json => { + if (json.errno == 0) { + dom.text(email); + toastr.success(json.msg); + } else { + toastr.warning(json.msg); + } + }, + error: showAjaxError + }); }); } function changeUserNickName(uid) { - var nickname = prompt(trans('admin.newUserNickname')); - - if (!nickname) return; - - $.ajax({ - type: "POST", - url: "./users?action=nickname", - dataType: "json", - data: { 'uid': uid, 'nickname': nickname }, - success: function(json) { - if (json.errno == 0) { - $($('tr#'+uid+' > td')[2]).html(nickname); - toastr.success(json.msg); - } else { - toastr.warning(json.msg); - } - }, - error: showAjaxError + let dom = $(`tr#user-${uid} > td:nth-child(3)`); + swal({ + text: trans('admin.newUserNickname'), + showCancelButton: true, + input: 'text', + inputValue: dom.text() + }).then(nickname => { + $.ajax({ + type: "POST", + url: "./users?action=nickname", + dataType: "json", + data: { 'uid': uid, 'nickname': nickname }, + success: json => { + if (json.errno == 0) { + dom.text(nickname); + toastr.success(json.msg); + } else { + toastr.warning(json.msg); + } + }, + error: showAjaxError + }); }); } function changeUserPwd(uid) { - var password = prompt(trans('admin.newUserPassword')); - - if (!password) return; - - $.ajax({ - type: "POST", - url: "./users?action=password", - dataType: "json", - data: { 'uid': uid, 'password': password }, - success: function(json) { - if (json.errno == 0) - toastr.success(json.msg); - else - toastr.warning(json.msg); - }, - error: showAjaxError - }); + swal({ + text: trans('admin.newUserPassword'), + showCancelButton: true, + input: 'password', + }).then(password => { + return Promise.resolve($.ajax({ + type: "POST", + url: "./users?action=password", + dataType: "json", + data: { 'uid': uid, 'password': password } + })); + }).then(json => { + if (json.errno == 0) + toastr.success(json.msg); + else + toastr.warning(json.msg); + }).catch(error => showAjaxError); } function changeUserScore(uid, score) { @@ -126,12 +157,16 @@ function changeBanStatus(uid) { data: { 'uid': uid }, success: function(json) { if (json.errno == 0) { - var object = $('#'+uid).find('a#ban'); - var dom = '' + - (object.text() == trans('admin.ban') ? trans('admin.unban') : trans('admin.ban')) + ''; - object.html(dom); + let dom = $(`#ban-${uid}`); + if (dom.attr('data') == 'banned') { + dom.text(trans('admin.ban')); + dom.attr('data', 'normal'); + } else { + dom.text(trans('admin.unban')); + dom.attr('data', 'banned'); + } - $('#'+uid).find('#permission').text(json.permission == '-1' ? trans('admin.banned') : trans('admin.normal')); + $(`#user-${uid} > td:nth-child(5)`).text(json.permission == -1 ? trans('admin.banned') : trans('admin.normal')); toastr.success(json.msg); } else { toastr.warning(json.msg); @@ -149,12 +184,16 @@ function changeAdminStatus(uid) { data: { 'uid': uid }, success: function(json) { if (json.errno == 0) { - var object = $('#'+uid).find('a#admin'); - var dom = '' + - (object.text() == trans('admin.setAdmin') ? trans('admin.unsetAdmin') : trans('admin.setAdmin')) + ''; - object.html(dom); + let dom = $(`#admin-${uid}`); + if (dom.attr('data') == 'admin') { + dom.text(trans('admin.setAdmin')); + dom.attr('data', 'normal'); + } else { + dom.text(trans('admin.unsetAdmin')); + dom.attr('data', 'admin'); + } - $('#'+uid).find('#permission').text(json.permission == '1' ? trans('admin.admin') : trans('admin.normal')); + $(`#user-${uid} > td:nth-child(5)`).text(json.permission == 1 ? trans('admin.admin') : trans('admin.normal')); toastr.success(json.msg); } else { toastr.warning(json.msg); @@ -165,23 +204,25 @@ function changeAdminStatus(uid) { } function deleteUserAccount(uid) { - if (!window.confirm(trans('admin.deleteUserNotice'))) return; - - $.ajax({ - type: "POST", - url: "./users?action=delete", - dataType: "json", - data: { 'uid': uid }, - success: function(json) { - if (json.errno == 0) { - $('tr#'+uid).remove(); - toastr.success(json.msg); - } else { - toastr.warning(json.msg); - } - }, - error: showAjaxError - }); + swal({ + text: trans('admin.deleteUserNotice'), + type: 'warning', + showCancelButton: true + }).then(() => { + return Promise.resolve($.ajax({ + type: "POST", + url: "./users?action=delete", + dataType: "json", + data: { 'uid': uid } + })) + }).then(json => { + if (json.errno == 0) { + $('tr#user-' + uid).remove(); + toastr.success(json.msg); + } else { + toastr.warning(json.msg); + } + }).catch(error => showAjaxError); } $('body').on('keypress', '.score', function(event){ @@ -191,7 +232,7 @@ $('body').on('keypress', '.score', function(event){ } }); -$('body').on('change', '#preference', function() { +function changePreference() { $.ajax({ type: "POST", url: "./players?action=preference", @@ -206,9 +247,9 @@ $('body').on('change', '#preference', function() { }, error: showAjaxError }); -}); +} -function changeTexture(pid) { +function changeTexture(pid, playerName) { let dom = `
@@ -223,8 +264,6 @@ function changeTexture(pid) {
`; - let playerName = $('#'+pid).find('#player-name').text(); - showModal(dom, trans('admin.changePlayerTexture', {'player': playerName}), 'default', { callback: `ajaxChangeTexture(${pid})` }); @@ -259,46 +298,106 @@ function ajaxChangeTexture(pid) { }); } +function changePlayerName(pid, oldName) { + let dom = $(`tr#${pid} > td:nth-child(3)`); + swal({ + text: trans('admin.changePlayerNameNotice'), + input: 'text', + inputValue: oldName, + inputValidator: name => { + return new Promise((resolve, reject) => { + if (name) { + resolve(); + } else { + reject(trans('admin.emptyPlayerName')); + } + }) + } + }).then(name => { + return Promise.resolve($.ajax({ + type: 'POST', + url: './players?action=name', + dataType: 'json', + data: { pid: pid, name: name } + })); + }).then(json => { + if (json.errno == 0) { + dom.text(json.name); + toastr.success(json.msg); + } else { + toastr.warning(json.msg); + } + }).catch(error => showAjaxError); +} + function changeOwner(pid) { - var uid = prompt(trans('admin.changePlayerOwner')); - - if (!uid) return; - - $.ajax({ - type: "POST", - url: "./players?action=owner", - dataType: "json", - data: { 'pid': pid, 'uid': uid }, - success: function(json) { - if (json.errno == 0) { - $($('#'+pid).children()[1]).text(uid); - toastr.success(json.msg); - } else { - toastr.warning(json.msg); - } - }, - error: showAjaxError + let dom = $(`#${pid} > td:nth-child(2)`); + swal({ + html: `${trans('admin.changePlayerOwner')}
 `, + input: 'number', + inputValue: dom.text(), + showCancelButton: true + }).then(uid => { + $.ajax({ + type: "POST", + url: "./players?action=owner", + dataType: "json", + data: { 'pid': pid, 'uid': uid }, + success: function (json) { + if (json.errno == 0) { + dom.text(uid); + toastr.success(json.msg); + } else { + toastr.warning(json.msg); + } + }, + error: showAjaxError + }); }); + + $('.swal2-input').on('input', debounce(() => { + const uid = $('.swal2-input').val(); + if (uid > 0) { + Promise.resolve($.ajax({ + type: 'GET', + url: `./user/${uid}`, + dataType: 'json' + })).then(result => { + $('#swal2-content').html( + `${trans('admin.changePlayerOwner')}
+ ${trans('admin.targetUser', { nickname: result.user.nickname })}` + ); + }).catch(() => { + $('#swal2-content').html(`${trans('admin.changePlayerOwner')}
${trans('admin.noSuchUser')}`); + }); + } + }, 350)); } function deletePlayer(pid) { - if (!window.confirm(trans('admin.deletePlayerNotice'))) return; + swal({ + text: trans('admin.deletePlayerNotice'), + type: 'warning', + showCancelButton: true + }).then(() => { + return Promise.resolve($.ajax({ + type: "POST", + url: "./players?action=delete", + dataType: "json", + data: { 'pid': pid }, + success: function (json) { - $.ajax({ - type: "POST", - url: "./players?action=delete", - dataType: "json", - data: { 'pid': pid }, - success: function(json) { - if (json.errno == 0) { - $('tr#'+pid).remove(); - toastr.success(json.msg); - } else { - toastr.warning(json.msg); - } - }, - error: showAjaxError - }); + }, + error: showAjaxError + })) + }).then(json => { + if (json.errno == 0) { + $('tr#' + pid).remove(); + toastr.success(json.msg); + } else { + toastr.warning(json.msg); + } + }).catch(error => showAjaxError); } function enablePlugin(name) { @@ -310,7 +409,7 @@ function enablePlugin(name) { if (json.errno == 0) { toastr.success(json.msg); - table.ajax.reload(null, false); + pluginsTable.ajax.reload(null, false); } else { toastr.warning(json.msg); } @@ -328,7 +427,7 @@ function disablePlugin(name) { if (json.errno == 0) { toastr.warning(json.msg); - table.ajax.reload(null, false); + pluginsTable.ajax.reload(null, false); } else { toastr.warning(json.msg); } @@ -351,7 +450,7 @@ function deletePlugin(name) { if (json.errno == 0) { toastr.success(json.msg); - $('tr[id=plugin-'+name+']').remove(); + pluginsTable.ajax.reload(null, false); } else { toastr.warning(json.msg); } @@ -453,3 +552,273 @@ function downloadUpdates() { .fail(showAjaxError); } + +function initUsersTable() { + let dataUrl = url('admin/user-data'); + if (getQueryString('uid')) { + dataUrl += '?uid=' + getQueryString('uid'); + } + $('#user-table').DataTable({ + ajax: dataUrl, + scrollY: ($('.content-wrapper').height() - $('.content-header').outerHeight()) * 0.7, + rowCallback: (row, data) => { + $(row).attr('id', `user-${data.uid}`); + }, + columnDefs: [ + { + targets: 0, + data: 'uid', + width: '1%' + }, + { + targets: 1, + data: 'email' + }, + { + targets: 2, + data: 'nickname' + }, + { + targets: 3, + data: 'score', + render: data => { + return ``; + } + }, + { + targets: 4, + data: 'players_count', + render: (data, type, row) => { + return `${data}`; + } + }, + { + targets: 5, + data: 'permission', + render: data => { + switch (data) { + case -1: + return trans('admin.banned'); + case 0: + return trans('admin.normal'); + case 1: + return trans('admin.admin'); + case 2: + return trans('admin.superAdmin'); + } + } + }, + { + targets: 6, + data: 'register_at' + }, + { + targets: 7, + data: 'operations', + searchable: false, + orderable: false, + render: (data, type, row) => { + let operationsHtml, adminOption = '', bannedOption = '', deleteUserButton; + if (row.permission !== 2) { + if (data === 2) { + if (row.permission === 1) { + adminOption = `
  • +
  • ${trans('admin.unsetAdmin')}
  • `; + } else { + adminOption = `
  • +
  • ${trans('admin.setAdmin')}
  • `; + } + } + if (row.permission === -1) { + bannedOption = `
  • +
  • ${trans('admin.unban')}
  • `; + } else { + bannedOption = `
  • +
  • ${trans('admin.ban')}
  • `; + } + } + + if (data === 2) { + if (row.permission === 2) { + deleteUserButton = ` + ${trans('admin.deleteUser')}`; + } else { + deleteUserButton = ` + ${trans('admin.deleteUser')}`; + } + } else { + if (row.permission === 1 || row.permission === 2) { + deleteUserButton = ` + ${trans('admin.deleteUser')}`; + } else { + deleteUserButton = ` + ${trans('admin.deleteUser')}`; + } + } + + return ` +
    + + +
    + ${deleteUserButton}`; + } + } + ] + }); +} + +function initPlayersTable() { + let dataUrl = url('admin/player-data'); + if (getQueryString('uid')) { + dataUrl += '?uid=' + getQueryString('uid'); + } + $('#player-table').DataTable({ + ajax: dataUrl, + scrollY: ($('.content-wrapper').height() - $('.content-header').outerHeight()) * 0.7, + columnDefs: [ + { + targets: 0, + data: 'pid', + width: '1%' + }, + { + targets: 1, + data: 'uid', + render: (data, type, row) => { + return `${data}`; + } + }, + { + targets: 2, + data: 'player_name' + }, + { + targets: 3, + data: 'preference', + render: data => { + return ` + `; + } + }, + { + targets: 4, + searchable: false, + orderable: false, + render: (data, type, row) => { + let html = { steve: '', alex: '', cape: '' }; + ['steve', 'alex', 'cape'].forEach(textureType => { + if (row['tid_' + textureType] === 0) { + html[textureType] = ``; + } else { + html[textureType] = ` + + + `; + } + }); + return html.steve + html.alex + html.cape; + } + }, + { + targets: 5, + data: 'last_modified' + }, + { + targets: 6, + searchable: false, + orderable: false, + render: (data, type, row) => { + return ` +
    + + +
    + ${trans('admin.deletePlayer')}`; + } + } + ] + }); +} + +function initPluginsTable() { + return $('#plugin-table').DataTable({ + ajax: url('admin/plugins/data'), + columnDefs: [ + { + targets: 0, + data: 'title' + }, + { + targets: 1, + data: 'description', + width: '35%' + }, + { + targets: 2, + data: 'author', + render: data => { + if (data.url === '' || data.url === null) { + return data.author; + } else { + return `${data.author}`; + } + } + }, + { + targets: 3, + data: 'version' + }, + { + targets: 4, + data: 'status' + }, + { + targets: 5, + data: 'operations', + searchable: false, + orderable: false, + render: (data, type, row) => { + let switchEnableButton, configViewButton, deletePluginButton; + if (data.enabled) { + switchEnableButton = ` + ${trans('admin.disablePlugin')}`; + } else { + switchEnableButton = ` + ${trans('admin.enablePlugin')}`; + } + if (data.enabled && data.hasConfigView) { + configViewButton = ` + ${trans('admin.configurePlugin')}`; + } else { + configViewButton = ` + ${trans('admin.configurePlugin')}`; + } + deletePluginButton = ` + ${trans('admin.deletePlugin')}`; + return switchEnableButton + configViewButton + deletePluginButton; + } + } + ] + }); +} diff --git a/resources/assets/src/scripts/general.js b/resources/assets/src/scripts/general.js index 6294cce3..7c3db483 100644 --- a/resources/assets/src/scripts/general.js +++ b/resources/assets/src/scripts/general.js @@ -1,8 +1,8 @@ /* * @Author: printempw * @Date: 2016-09-15 10:39:41 -* @Last Modified by: printempw -* @Last Modified time: 2017-01-22 18:51:51 + * @Last Modified by: g-plane + * @Last Modified time: 2017-04-27 15:33:24 */ 'use strict'; @@ -88,7 +88,7 @@ function trans(key, parameters = {}) { return temp; } -function showModal(msg, title = 'Messgae', type = 'default', options = {}) { +function showModal(msg, title = 'Message', type = 'default', options = {}) { let btnType = (type != "default") ? "btn-outline" : "btn-primary"; let onClick = (options.callback === undefined) ? 'data-dismiss="modal"' : `onclick="${options.callback}"`; @@ -157,6 +157,28 @@ function getQueryString(key) { } } +/** + * Return a debounced function + * + * @param {Function} func + * @param {number} delay + * @param {Array} args + * @param {Object} context + */ +function debounce(func, delay, args = [], context = undefined) { + if (isNaN(delay) || typeof func !== 'function') { + throw new Error('Arguments type of function "debounce" is incorrent!'); + } + + let timer = null; + return function () { + clearTimeout(timer); + timer = setTimeout(() => { + func.apply(context, args); + }, delay); + } +} + // polyfill of String.prototype.endsWith if (!String.prototype.endsWith) { String.prototype.endsWith = function (searchString, position) { @@ -200,18 +222,11 @@ function confirmLogout() { } function logout() { - return new Promise((resolve, reject) => { - $.ajax({ - type: "POST", - url: url('auth/logout'), - dataType: "json", - success: (json) => resolve(json), - error: (json) => { - showAjaxError(json); - reject(json); - } - }); - }); + return Promise.resolve($.ajax({ + type: "POST", + url: url('auth/logout'), + dataType: "json" + })); } $('#logout-button').click(() => confirmLogout()); @@ -237,7 +252,7 @@ var TexturePreview = function (type, tid, preference) { this.change3dPreview = function () { - if (this.playerPreference == this.preference) { + if (this.playerPreference == this.preference || this.type == 'cape') { $.ajax({ type: "GET", url: url(`skinlib/info/${this.tid}`), diff --git a/resources/assets/src/scripts/skinlib.js b/resources/assets/src/scripts/skinlib.js index 631df5f2..d5d7b6c7 100644 --- a/resources/assets/src/scripts/skinlib.js +++ b/resources/assets/src/scripts/skinlib.js @@ -1,8 +1,8 @@ /* * @Author: printempw * @Date: 2016-07-19 10:46:38 - * @Last Modified by: printempw - * @Last Modified time: 2017-01-22 15:57:57 + * @Last Modified by: g-plane + * @Last Modified time: 2017-04-25 21:56:19 */ 'use strict'; @@ -158,8 +158,9 @@ function handleFiles(files, type) { (type == "skin") ? MSP.changeSkin(img.src) : MSP.changeCape(img.src); let domTextureName = $('#name'); if (domTextureName.val() === '' || domTextureName.val() === domTextureName.attr('data-last-file-name')) { - domTextureName.attr('data-last-file-name', file.name); - domTextureName.val(file.name); + const fileName = file.name.replace(/\.[Pp][Nn][Gg]$/, ''); + domTextureName.attr('data-last-file-name', fileName); + domTextureName.val(fileName); } }; img.onerror = () => toastr.warning(trans('skinlib.fileExtError')); @@ -243,10 +244,11 @@ function upload() { return false; } -function changeTextureName(tid) { +function changeTextureName(tid, oldName) { swal({ text: trans('skinlib.setNewTextureName'), input: 'text', + inputValue: oldName, showCancelButton: true, inputValidator: (value) => { return new Promise((resolve, reject) => { diff --git a/resources/assets/src/scripts/user.js b/resources/assets/src/scripts/user.js index b3138b1d..b0051226 100644 --- a/resources/assets/src/scripts/user.js +++ b/resources/assets/src/scripts/user.js @@ -1,8 +1,8 @@ /* * @Author: printempw * @Date: 2016-07-16 10:02:24 - * @Last Modified by: printempw - * @Last Modified time: 2017-01-20 21:19:07 + * @Last Modified by: g-plane + * @Last Modified time: 2017-04-27 16:37:05 */ 'use strict'; @@ -18,13 +18,13 @@ $('body').on('click', '#preview-switch', () => { TexturePreview.previewType == '3D' ? TexturePreview.show2dPreview() : TexturePreview.show3dPreview(); }); -var selected = []; +let selectedTextures = []; $('body').on('click', '.item-body', function () { $('.item-selected').parent().removeClass('item-selected'); $(this).parent().addClass('item-selected'); - let tid = $(this).parent().attr('tid'); + const tid = parseInt($(this).parent().attr('tid')); $.ajax({ type: "POST", @@ -33,24 +33,94 @@ $('body').on('click', '.item-body', function () { success: (json) => { if (json.type == "cape") { MSP.changeCape('../textures/' + json.hash); - selected['cape'] = tid; + selectedTextures['cape'] = tid; } else { MSP.changeSkin('../textures/' + json.hash); - selected['skin'] = tid; + selectedTextures['skin'] = tid; } - selected.length = 0; - - ['skin', 'cape'].forEach((key) => { - if (selected[key] !== undefined) selected.length++; - - $('#textures-indicator').html(selected.length); - }); + if (selectedTextures['skin'] !== undefined && selectedTextures['cape'] !== undefined) + $('#textures-indicator').text(`${trans('general.skin')} & ${trans('general.cape')}`); + else if (selectedTextures['skin'] != undefined) + $('#textures-indicator').text(trans('general.skin')); + else if (selectedTextures['cape'] != undefined) + $('#textures-indicator').text(trans('general.cape')); }, error: showAjaxError }); }); +$('body').on('click', '.category-switch', () => { + const category = $('a[href="#skin-category"]').parent().hasClass('active') ? 'cape' : 'skin'; + const page = parseInt($('#closet-paginator').attr(`last-${category}-page`)); + const search = $('input[name=q]').val(); + reloadCloset(category, page, search); +}); + +function renderClosetItemComponent(item) { + return ` +
    +
    + +
    + +
    `; +} + +function renderCloset(items, category) { + const search = $('input[name=q]').val(); + let container = $(`#${category}-category`); + container.html(''); + if (items.length === 0) { + $('#closet-paginator').hide(); + if (search === '') { + container.html(`
    + ${trans('user.emptyClosetMsg', { url: url('skinlib?filter=' + category) })}
    `); + } else { + container.html(`
    ${trans('general.noResult')}
    `); + } + } else { + $('#closet-paginator').show(); + for (const item of items) { + container.append(renderClosetItemComponent(item)); + } + } +} + +function reloadCloset(category, page, search) { + Promise.resolve($.ajax({ + type: 'GET', + url: url('user/closet-data'), + dataType: 'json', + data: { + category: category, + page: page, + q: search + } + })).then(result => { + renderCloset(result.items, result.category); + let paginator = $('#closet-paginator'); + paginator.attr(`last-${result.category}-page`, page); + paginator.jqPaginator('option', { + currentPage: page, + totalPages: result.total_pages + }); + }).catch(error => showAjaxError); +} + function showPlayerTexturePreview(pid) { $.ajax({ type: "POST", @@ -81,10 +151,11 @@ function showPlayerTexturePreview(pid) { }); } -function renameClosetItem(tid) { +function renameClosetItem(tid, oldName) { swal({ title: trans('user.renameClosetItem'), input: 'text', + inputValue: oldName, showCancelButton: true, inputValidator: function(value) { return new Promise(function(resolve, reject) { @@ -133,6 +204,14 @@ function removeFromCloset(tid) { }); $('div[tid='+tid+']').remove(); + + ['skin', 'cape'].forEach(type => { + let container = $(`#${type}-category`); + if ($.trim(container.html()) == '') { + container.html(`
    + ${trans('user.emptyClosetMsg', { url: url('skinlib?filter=' + type) })}
    `); + } + }) } else { toastr.warning(json.msg); } @@ -178,6 +257,43 @@ $(document).ready(function() { confirmButtonText: trans('general.confirm'), cancelButtonText: trans('general.cancel') }); + + if (window.location.pathname.includes('/user/closet')) { + Promise.resolve($.ajax({ + type: 'GET', + url: /(^https?.*)\/user\/closet/.exec(window.location.href)[1] + '/user/closet-data', + dataType: 'json' + })).then(result => { + renderCloset(result.items, result.category); + $('#closet-paginator').jqPaginator({ + totalPages: result.total_pages, + visiblePages: 5, + currentPage: 1, + first: '
  • «
  • ', + prev: '
  • ', + next: '
  • ', + last: '
  • »
  • ', + page: '
  • {{page}}
  • ', + wrapper: '', + onPageChange: page => { + reloadCloset( + $('#skin-category').hasClass('active') ? 'skin' : 'cape', + page, + $('input[name=q]').val() + ); + } + }); + }).catch(error => showAjaxError); + + $('input[name=q]').on('input', debounce(() => { + const category = $('#skin-category').hasClass('active') ? 'skin' : 'cape'; + reloadCloset( + category, + 1, + $('input[name=q]').val() + ); + }, 350)); + } }); function setTexture() { @@ -189,7 +305,7 @@ function setTexture() { if (!pid) { toastr.info(trans('user.emptySelectedPlayer')); - } else if (selected.length == 0) { + } else if (selectedTextures['skin'] == undefined && selectedTextures['cape'] == undefined) { toastr.info(trans('user.emptySelectedTexture')); } else { $.ajax({ @@ -198,8 +314,8 @@ function setTexture() { dataType: "json", data: { 'pid': pid, - 'tid[skin]': selected['skin'], - 'tid[cape]': selected['cape'] + 'tid[skin]': selectedTextures['skin'], + 'tid[cape]': selectedTextures['cape'] }, success: function(json) { if (json.errno == 0) { @@ -238,7 +354,7 @@ $('body').on('change', '#preference', function() { function changePlayerName(pid, current_player_name) { swal({ title: trans('user.changePlayerName'), - text: trans('user.playerNameRule'), + text: $('#player_name').attr('placeholder'), inputValue: current_player_name, input: 'text', showCancelButton: true, @@ -277,32 +393,49 @@ function changePlayerName(pid, current_player_name) { } function clearTexture(pid) { - swal({ - text: trans('user.clearTexture'), - type: 'warning', - showCancelButton: true - }).then(function() { - $.ajax({ - type: "POST", - url: "./player/texture/clear", - dataType: "json", - data: { 'pid' : pid }, - success: function(json) { - if (json.errno == 0) { - swal({ - type: 'success', - html: json.msg - }); - } else { - swal({ - type: 'error', - html: json.msg - }); - } - }, - error: showAjaxError - }); + let dom = ` +
    + Default (Steve) +
    +
    + Slim (Alex) +
    +
    + ${trans('general.cape')} +
    + + `; + showModal(dom, trans('user.chooseClearTexture'), 'default', { callback: `ajaxClearTexture(${pid})` }); + return; +} + +function ajaxClearTexture(pid) { + $('.modal').each(function () { + if ($(this).css('display') == "none") + $(this).remove(); }); + + let data = { pid: pid }; + ['steve', 'alex', 'cape'].forEach(type => { + data[type] = $(`#clear-${type}`).prop('checked') ? 1 : 0; + }); + + if (data['steve'] == 0 && data['alex'] == 0 && data['cape'] == 0) { + toastr.warning(trans('user.noClearChoice')); + return; + } + + Promise.resolve($.ajax({ + type: 'POST', + url: './player/texture/clear', + dataType: 'json', + data: data + })).then(json => { + swal({ type: json.errno == 0 ? 'success' : 'error', html: json.msg }); + $('.modal').modal('hide'); + }).catch(error => showAjaxError); } function deletePlayer(pid) { @@ -405,49 +538,46 @@ function changeNickName() { } function changePassword() { + let domOldPwd = $('#password'); + let domNewPwd = $('#new-passwd'); + let domConfirmPwd = $('#confirm-pwd'); - var password = $('#password').val(); - var new_passwd = $('#new-passwd').val(); + let password = domOldPwd.val(); + let new_passwd = domNewPwd.val(); if (password == "") { toastr.info(trans('user.emptyPassword')); - $('#passwd').focus(); + domOldPwd.focus(); } else if (new_passwd == "") { toastr.info(trans('user.emptyNewPassword')); - $('#new-passwd').focus(); - } else if ($('#confirm-pwd').val() == "") { + domNewPwd.focus(); + } else if (domConfirmPwd.val() == "") { toastr.info(trans('auth.emptyConfirmPwd')); - $('#confirm-pwd').focus(); - } else if (new_passwd != $('#confirm-pwd').val()) { + domConfirmPwd.focus(); + } else if (new_passwd != domConfirmPwd.val()) { toastr.warning(trans('auth.invalidConfirmPwd')); - $('#confirm-pwd').focus(); + domConfirmPwd.focus(); } else { - $.ajax({ + Promise.resolve($.ajax({ type: "POST", url: "./profile?action=password", dataType: "json", - data: { 'current_password': password, 'new_password': new_passwd}, - success: function(json) { - if (json.errno == 0) { - swal({ - type: 'success', - html: json.msg - }).then(function() { - logout(true, function() { - window.location = "../auth/login"; - }); - }); - } else { - swal({ - type: 'warning', - html: json.msg - }); - } - }, - error: showAjaxError - }); + data: { 'current_password': password, 'new_password': new_passwd } + })).then(result => { + if (result.errno == 0) { + return swal({ type: 'success', text: result.msg }) + .then(() => { + return logout(); + }).then(result => { + if (result.errno == 0) { + window.location = url('auth/login'); + } + }).catch(error => showAjaxError); + } else { + return swal({ type: 'warning', text: result.msg }); + } + }).catch(error => showAjaxError); } - return false; } $('#new-email').focusin(function() { @@ -481,32 +611,27 @@ function changeEmail() { text: trans('user.changeEmail', { new_email: new_email }), type: 'question', showCancelButton: true - }).then(function() { - $.ajax({ - type: "POST", - url: "./profile?action=email", - dataType: "json", - data: { 'new_email' : new_email, 'password' : $('#current-password').val() }, - success: function(json) { - if (json.errno == 0) { - swal({ - type: 'success', - html: json.msg - }).then(function() { - logout(true, function() { - window.location = "../auth/login"; - }); - }); - } else { - swal({ - type: 'warning', - html: json.msg - }); - } - }, - error: showAjaxError - }); - }); + }).then(() => { + return Promise.resolve($.ajax({ + type: 'POST', + url: './profile?action=email', + dataType: 'json', + data: { 'new_email': new_email, 'password': $('#current-password').val() } + })); + }).then(result => { + if (result.errno == 0) { + return swal({ type: 'success', text: result.msg }) + .then(() => { + return logout(); + }).then(result => { + if (result.errno == 0) { + window.location = url('auth/login'); + } + }).catch(error => showAjaxError); + } else { + return swal({ type: 'warning', text: result.msg }); + } + }).catch(error => showAjaxError); } function deleteAccount() { diff --git a/resources/lang/en/admin.yml b/resources/lang/en/admin.yml index 36b101f2..4c6256cc 100644 --- a/resources/lang/en/admin.yml +++ b/resources/lang/en/admin.yml @@ -6,19 +6,20 @@ index: overview: Overview users: + players-count: + title: Players Count status: title: Status normal: Normal banned: Banned admin: Admin super-admin: Super Admin - score: - tip: Press enter to submit new score operations: title: Operations non-existent: No such user. email: change: Edit Email + existed: :email is existed. success: Email changed successfully. nickname: change: Edit Nickname @@ -61,6 +62,8 @@ players: change: Change Textures non-existent: No such texture tid.:tid success: The textures of :player has been updated. + name: + success: Player name has been updated to :player owner: change: Change Owner success: The player :player was transferred to user :user. @@ -100,12 +103,6 @@ plugins: operations: title: Operations - disable: Disable - enable: Enable - configure: Configure - no-config-notice: The plugin has been disabled or no configuration is provided. - delete: Delete - enabled: :plugin has been enabled. disabled: :plugin has been disabled. deleted: The plugin was deleted successfully. diff --git a/resources/lang/en/locale.js b/resources/lang/en/locale.js index 1a337a90..70f0533f 100644 --- a/resources/lang/en/locale.js +++ b/resources/lang/en/locale.js @@ -62,12 +62,17 @@ setAsPublic: 'Set as Public', setPublicNotice: 'Sure to set this as public texture?', - deleteNotice: 'Are you sure to delete this texture? Scores will be returned.' + deleteNotice: 'Are you sure to delete this texture?' }, user: { signInRemainingTime: 'Available after :time hours', // Closet + emptyClosetMsg: '

    Nothing in your closet...

    Why not explore the Skin Library for a while?

    ', + renameItem: 'Rename item', + removeItem: 'Remove from closet', + setAsAvatar: 'Set as avatar', + viewInSkinlib: 'View in skin library', switch2dPreview: 'Switch to 2D Preview', switch3dPreview: 'Switch to 3D Preview', removeFromClosetNotice: 'Sure to remove this texture from your closet?', @@ -77,11 +82,12 @@ // Player changePlayerName: 'Please enter the player name:', - playerNameRule: 'The player name should only contain letters, numbers, and dashes.', emptyPlayerName: 'Empty player name.', clearTexture: 'Sure to clear the skins & cape of this player?', deletePlayer: 'Sure to delete this player?', deletePlayerNotice: 'It\'s permanent. No backups.', + chooseClearTexture: 'Choose texture types you want to clear', + noClearChoice: 'You haven\'t choose any types', // Profile setAvatar: 'Sure to set this as your avatar?', @@ -95,38 +101,59 @@ emptyDeletePassword: 'Please enter the current password:' }, admin: { - // Change User Profile - newUserEmail: 'Please enter the new email:', - newUserNickname: 'Please enter the new nickname:', - newUserPassword: 'Please enter the new password:', - deleteUserNotice: 'Are you sure to delete this user? It\' permanent.', - changePlayerOwner: 'Please enter the id of user which this player should be transferred to:', - deletePlayerNotice: 'Are you sure to delete this player? It\' permanent.', + operationsTitle: 'Operations', - // Status - banned: 'Banned', - normal: 'Normal', - admin: 'Admin', - - // Operations + // Users ban: 'Ban', unban: 'Unban', setAdmin: 'Set as admin', unsetAdmin: 'Remove admin', + deleteUser: 'Delete User', + cannotDeleteAdmin: 'You can\'t delete admins.', + cannotDeleteSuperAdmin: 'You can\'t delete super admin in this way', + changeEmail: 'Edit Email', + changeNickName: 'Edit Nickname', + changePassword: 'Edit Password', + newUserEmail: 'Please enter the new email:', + newUserNickname: 'Please enter the new nickname:', + newUserPassword: 'Please enter the new password:', + deleteUserNotice: 'Are you sure to delete this user? It\' permanent.', + scoreTip: 'Press ENTER to submit new score', + doubleClickToSeeUser: 'Double click to see info of this user', + doubleClickToSeePlayers: 'Double click to see his/her players', - // Change Player Texture + // Status + banned: 'Banned', + normal: 'Normal', + admin: 'Admin', + superAdmin: 'Super Admin', + + // Players textureType: 'Texture Type', skin: 'Skin (:model Model)', cape: 'Cape', pid: 'Texture ID', - pidNotice: 'Please enter the tid of texture', + pidNotice: 'Please enter the tid of texture. Inputting 0 can clear texture of this player.', changePlayerTexture: 'Change textures of :player', + changeTexture: 'Change Textures', + changePlayerName: 'Change Player Name', + changeOwner: 'Change Owner', + deletePlayer: 'Delete', + changePlayerOwner: 'Please enter the id of user which this player should be transferred to:', + deletePlayerNotice: 'Are you sure to delete this player? It\' permanent.', + targetUser: 'Target user is :nickname', + noSuchUser: 'No such user', + changePlayerNameNotice: 'Please input new player name:', + emptyPlayerName: 'Player name cannot be empty.', // Index textureUploads: 'Texture Uploads', userRegistration: 'User Registration', // Plugins + configurePlugin: 'Configure', + noPluginConfigNotice: 'The plugin has been disabled or no configuration is provided.', + deletePlugin: 'Delete', statusEnabled: 'Enabled', statusDisabled: 'Disabled', enablePlugin: 'Enable', @@ -139,10 +166,14 @@ extracting: 'Extracting update package..' }, general: { + skin: 'Skin', + cape: 'Cape', fatalError: 'Fatal Error (Please contact the author)', confirmLogout: 'Sure to log out?', confirm: 'OK', - cancel: 'Cancel' + cancel: 'Cancel', + more: 'More', + noResult: 'No result.' } }; })(window.jQuery); diff --git a/resources/lang/en/user.yml b/resources/lang/en/user.yml index f49dc4b6..aee3142b 100644 --- a/resources/lang/en/user.yml +++ b/resources/lang/en/user.yml @@ -16,10 +16,11 @@ score-intro: title: What is score? introduction: | We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. - Both adding players and uplaoding textures will consume your score. The score will be returned if you deleted them. - Adding textures from skin library to your closet will not decline your score. + Both adding players and uplaoding textures will consume your score. :return-score The inital score of user on this site is :initial_score, you can acquire :score-from ~ :score-to scores by signing in. + will-return-score: The score will be returned if you deleted them. + no-return-score: But the score will NOT be returned if you deleted them. rates: storage: :score scores = 1 KB storage player: :score scores = 1 player @@ -27,13 +28,11 @@ score-intro: closet: upload: Upload Texture search: Search Texture + type-to-search: Type to search switch-category: Switch Category view: View in skin library more: More set-avatar: Set as avatar - empty-msg: | -

    Nothing in your closet...

    -

    Why not explore the Skin Library for a while?

    use-as: button: Apply... @@ -128,6 +127,7 @@ profile: password: Current Password button: Change Email wrong-password: Wrong password. + existed: This email address is used. success: Email address updated successfully, please log in again. delete: diff --git a/resources/lang/zh_CN/admin.yml b/resources/lang/zh_CN/admin.yml index 1f4e4372..a968d37e 100644 --- a/resources/lang/zh_CN/admin.yml +++ b/resources/lang/zh_CN/admin.yml @@ -6,19 +6,20 @@ index: overview: 概览 users: + players-count: + title: 拥有角色数 status: title: 状态 normal: 普通用户 banned: 封禁 admin: 管理员 super-admin: 超级管理员 - score: - tip: 输入修改后的积分,回车提交 operations: title: 更多操作 non-existent: 用户不存在 email: change: 修改邮箱 + existed: :email 已被占用 success: 邮箱修改成功 nickname: change: 修改昵称 @@ -61,6 +62,8 @@ players: change: 更换材质 non-existent: 材质 tid.:tid 不存在 success: 角色 :player 的材质修改成功 + name: + success: 角色名成功更改为 :player owner: change: 更换角色拥有者 success: 角色 :player 已成功让渡至 :user @@ -100,12 +103,6 @@ plugins: operations: title: 操作 - disable: 禁用插件 - enable: 启用插件 - configure: 插件配置 - no-config-notice: 插件已被禁用或无配置页 - delete: 删除插件 - enabled: :plugin 已启用 disabled: :plugin 已禁用 deleted: 插件已被成功删除 diff --git a/resources/lang/zh_CN/locale.js b/resources/lang/zh_CN/locale.js index 334d212d..49f718dd 100644 --- a/resources/lang/zh_CN/locale.js +++ b/resources/lang/zh_CN/locale.js @@ -62,12 +62,17 @@ setAsPublic: '设为公开', setPublicNotice: '要将此材质设置为公开吗?', - deleteNotice: '真的要删除此材质吗?积分将会被返还' + deleteNotice: '真的要删除此材质吗?' }, user: { signInRemainingTime: ':time 小时后可签到', // Closet + emptyClosetMsg: '

    衣柜里啥都没有哦~

    皮肤库看看吧~

    ', + renameItem: '重命名物品', + removeItem: '从衣柜中移除', + setAsAvatar: '设为头像', + viewInSkinlib: '在皮肤库中查看', switch2dPreview: '切换 2D 预览', switch3dPreview: '切换 3D 预览', removeFromClosetNotice: '确定要从衣柜中移除此材质吗?', @@ -77,11 +82,12 @@ // Player changePlayerName: '请输入角色名:', - playerNameRule: '允许数字、字母以及下划线,是否支持中文角色名请参考本站设置', emptyPlayerName: '你还没有填写名称哦', clearTexture: '确定要重置该用户的皮肤/披风吗?', deletePlayer: '真的要删除该玩家吗?', deletePlayerNotice: '这将是永久性的删除', + chooseClearTexture: '选择要删除的材质类型', + noClearChoice: '您还没选择要删除的材质类型', // Profile setAvatar: '确定要将此材质设置为用户头像吗?', @@ -95,38 +101,59 @@ emptyDeletePassword: '请先输入当前用户密码' }, admin: { - // Change User Profile - newUserEmail: '请输入新邮箱:', - newUserNickname: '请输入新昵称:', - newUserPassword: '请输入新密码:', - deleteUserNotice: '真的要删除此用户吗?此操作不可恢复', - changePlayerOwner: '请输入此角色要让渡至的用户 UID:', - deletePlayerNotice: '真的要删除此角色吗?此操作不可恢复', + operationsTitle: '更多操作', - // Status - banned: '封禁', - normal: '正常', - admin: '管理员', - - // Operations + // Users ban: '封禁', unban: '解封', setAdmin: '设为管理员', unsetAdmin: '解除管理员', + deleteUser: '删除用户', + cannotDeleteAdmin: '你不能删除管理员账号哦', + cannotDeleteSuperAdmin: '超级管理员账号不能被这样删除的啦', + changeEmail: '修改邮箱', + changeNickName: '修改昵称', + changePassword: '更改密码', + newUserEmail: '请输入新邮箱:', + newUserNickname: '请输入新昵称:', + newUserPassword: '请输入新密码:', + deleteUserNotice: '真的要删除此用户吗?此操作不可恢复', + scoreTip: '输入修改后的积分,回车提交', + doubleClickToSeeUser: '双击可查看该用户的信息', + doubleClickToSeePlayers: '双击可查看该用户的角色', - // Change Player Texture + // Status + banned: '封禁', + normal: '普通用户', + admin: '管理员', + superAdmin: '超级管理员', + + // Players textureType: '材质类型', skin: '皮肤(:model 模型)', cape: '披风', pid: '材质 ID', - pidNotice: '输入要更换的材质的 TID', + pidNotice: '输入要更换的材质的 TID,输入 0 即可清除该角色的材质', changePlayerTexture: '更换角色 :player 的材质', + changeTexture: '更换材质', + changePlayerName: '更改角色名', + changeOwner: '更换角色拥有者', + deletePlayer: '删除角色', + changePlayerOwner: '请输入此角色要让渡至的用户 UID:', + deletePlayerNotice: '真的要删除此角色吗?此操作不可恢复', + targetUser: '目标用户::nickname', + noSuchUser: '没有这个用户哦~', + changePlayerNameNotice: '请输入新的角色名:', + emptyPlayerName: '您还没填写角色名呢', // Index textureUploads: '材质上传', userRegistration: '用户注册', // Plugins + configurePlugin: '插件配置', + noPluginConfigNotice: '插件已被禁用或无配置页', + deletePlugin: '删除插件', statusEnabled: '已启用', statusDisabled: '已禁用', enablePlugin: '启用插件', @@ -139,10 +166,14 @@ extracting: '正在解压更新包' }, general: { + skin: '皮肤', + cape: '披风', fatalError: '严重错误(请联系作者)', confirmLogout: '确定要登出吗?', confirm: '确定', - cancel: '取消' + cancel: '取消', + more: '更多', + noResult: '无结果' }, vendor: { datatables: { diff --git a/resources/lang/zh_CN/user.yml b/resources/lang/zh_CN/user.yml index f6205a16..3b10455e 100644 --- a/resources/lang/zh_CN/user.yml +++ b/resources/lang/zh_CN/user.yml @@ -22,10 +22,12 @@ score-intro: 「贯彻爱与真实的。。呸!」上面只是卖下萌~ 为了不出现用户一个劲上传材质导致存储空间爆满,我们决定启用积分系统。 - 添加角色以及上传材质都会消耗积分,而删除已经添加的角色和已上传的材质时积分将会被返还。 + 添加角色以及上传材质都会消耗积分,:return-score。 本站用户初始积分为 :initial_score,每日签到可以随机获得 :score-from ~ :score-to 积分 添加皮肤库里的材质到衣柜不消耗积分。 + will-return-score: 而删除已经添加的角色和已上传的材质时积分将会被返还 + no-return-score: 但删除已经添加的角色和已上传的材质时积分不会被返还 rates: storage: :score 积分 = 1 KB 存储空间 player: :score 积分 = 1 个角色 @@ -33,13 +35,11 @@ score-intro: closet: upload: 上传材质 search: 搜索材质 + type-to-search: 输入即搜索 switch-category: 切换分类 view: 在皮肤库中查看 more: 更多 set-avatar: 设为头像 - empty-msg: | -

    衣柜里啥都没有哦~

    -

    皮肤库看看吧~

    use-as: button: 使用... @@ -134,6 +134,7 @@ profile: password: 当前密码 button: 修改邮箱 wrong-password: 密码错误 + existed: 这个邮箱已经被别人占用啦 success: 邮箱修改成功,请重新登录 delete: diff --git a/resources/views/admin/players.tpl b/resources/views/admin/players.tpl index c5820b7b..d9c62853 100644 --- a/resources/views/admin/players.tpl +++ b/resources/views/admin/players.tpl @@ -43,26 +43,5 @@ $(document).ready(function() { $('.box-body').css('min-height', $('.content-wrapper').height() - $('.content-header').outerHeight() - 120); }); - -$('#player-table').DataTable({ - language: trans('vendor.datatables'), - scrollX: true, - autoWidth: false, - processing: true, - serverSide: true, - ajax: '{{ url("admin/player-data") }}', - createdRow: function (row, data, index) { - $('td', row).eq(2).attr('id', 'player-name'); - }, - columns: [ - {data: 'pid', 'width': '1%'}, - {data: 'uid'}, - {data: 'player_name'}, - {data: 'preference'}, - {data: 'previews', searchable: false, orderable: false}, - {data: 'last_modified'}, - {data: 'operations', searchable: false, orderable: false} - ] -}); @endsection diff --git a/resources/views/admin/plugins.tpl b/resources/views/admin/plugins.tpl index 1c4a5bd7..8b5e4304 100644 --- a/resources/views/admin/plugins.tpl +++ b/resources/views/admin/plugins.tpl @@ -47,32 +47,3 @@ @endsection - -@section('script') - -@endsection diff --git a/resources/views/admin/users.tpl b/resources/views/admin/users.tpl index 64b23e22..8c1bc779 100644 --- a/resources/views/admin/users.tpl +++ b/resources/views/admin/users.tpl @@ -24,6 +24,7 @@ {{ trans('general.user.email') }} {{ trans('general.user.nickname') }} {{ trans('general.user.score') }} + {{ trans('admin.users.players-count.title') }} {{ trans('admin.users.status.title') }} {{ trans('general.user.register-at') }} {{ trans('general.operations') }} @@ -42,28 +43,5 @@ $(document).ready(function() { $('.box-body').css('min-height', $('.content-wrapper').height() - $('.content-header').outerHeight() - 120); }); - -$('#user-table').DataTable({ - language: trans('vendor.datatables'), - scrollX: true, - autoWidth: false, - processing: true, - serverSide: true, - ajax: '{{ url("admin/user-data") }}', - createdRow: function (row, data, index) { - $('td', row).eq(1).attr('id', 'email'); - $('td', row).eq(2).attr('id', 'nickname'); - $('td', row).eq(4).attr('id', 'permission'); - }, - columns: [ - {data: 'uid', 'width': '1%'}, - {data: 'email'}, - {data: 'nickname'}, - {data: 'score'}, - {data: 'permission'}, - {data: 'register_at'}, - {data: 'operations', searchable: false, orderable: false} - ] -}); @endsection diff --git a/resources/views/skinlib/master.tpl b/resources/views/skinlib/master.tpl index 13c2f828..1f8534fc 100644 --- a/resources/views/skinlib/master.tpl +++ b/resources/views/skinlib/master.tpl @@ -39,17 +39,17 @@ {{ trans('skinlib.general.filter') }} diff --git a/resources/views/skinlib/search.tpl b/resources/views/skinlib/search.tpl index 502db3d7..25b61627 100644 --- a/resources/views/skinlib/search.tpl +++ b/resources/views/skinlib/search.tpl @@ -10,7 +10,6 @@

    {{ $__env->getSections()['title'] }} - Search Result

    @include('vendor.breadcrumb') diff --git a/resources/views/skinlib/show.tpl b/resources/views/skinlib/show.tpl index 06981f21..d276b1f5 100644 --- a/resources/views/skinlib/show.tpl +++ b/resources/views/skinlib/show.tpl @@ -51,14 +51,20 @@ {{ $texture->name }} @if (!is_null($user) && ($texture->uploader == $user->uid || $user->isAdmin())) - {{ trans('skinlib.show.edit-name') }} + {{ trans('skinlib.show.edit-name') }} @endif {{ trans('skinlib.show.model') }} - {{ $texture->type }} + + @if ($texture->type == 'cape') + {{ trans('general.cape') }} + @else + {{ $texture->type }} + @endif + Hash @@ -75,7 +81,7 @@ {{ trans('skinlib.show.uploader') }} @if ($uploader = app('users')->get($texture->uploader)) - {{ $uploader->getNickName() }} + {{ $uploader->getNickName() }} @else {{ trans('general.unexistent-user') }} @endif diff --git a/resources/views/user/closet.tpl b/resources/views/user/closet.tpl index 219e1426..993fbaa6 100644 --- a/resources/views/user/closet.tpl +++ b/resources/views/user/closet.tpl @@ -26,51 +26,30 @@ - +
    diff --git a/resources/views/user/index.tpl b/resources/views/user/index.tpl index 22d3bdb4..aaa7aeb9 100644 --- a/resources/views/user/index.tpl +++ b/resources/views/user/index.tpl @@ -110,7 +110,8 @@ {!! nl2br(trans('user.score-intro.introduction', [ 'initial_score' => option('user_initial_score'), 'score-from' => $from, - 'score-to' => $to + 'score-to' => $to, + 'return-score' => option('return_score') ? trans('user.score-intro.will-return-score') : trans('user.score-intro.no-return-score') ])) !!}
    diff --git a/resources/views/vendor/admin-operations/players/operations.tpl b/resources/views/vendor/admin-operations/players/operations.tpl deleted file mode 100644 index 8dbf4e60..00000000 --- a/resources/views/vendor/admin-operations/players/operations.tpl +++ /dev/null @@ -1,11 +0,0 @@ -
    - - -
    - -{{ trans('admin.players.delete.delete') }} diff --git a/resources/views/vendor/admin-operations/players/preference.tpl b/resources/views/vendor/admin-operations/players/preference.tpl deleted file mode 100644 index a5330e12..00000000 --- a/resources/views/vendor/admin-operations/players/preference.tpl +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/resources/views/vendor/admin-operations/players/previews.tpl b/resources/views/vendor/admin-operations/players/previews.tpl deleted file mode 100644 index e975ef46..00000000 --- a/resources/views/vendor/admin-operations/players/previews.tpl +++ /dev/null @@ -1,23 +0,0 @@ -@if ($tid_steve == '0') - -@else - - - -@endif - -@if ($tid_alex == '0') - -@else - - - -@endif - -@if ($tid_cape == '0') - -@else - - - -@endif diff --git a/resources/views/vendor/admin-operations/plugins/operations.tpl b/resources/views/vendor/admin-operations/plugins/operations.tpl deleted file mode 100644 index 6dba4c18..00000000 --- a/resources/views/vendor/admin-operations/plugins/operations.tpl +++ /dev/null @@ -1,13 +0,0 @@ -@if ($plugin->isEnabled()) -{{ trans('admin.plugins.operations.disable') }} -@else -{{ trans('admin.plugins.operations.enable') }} -@endif - -@if ($plugin->isEnabled() && $plugin->hasConfigView()) -{{ trans('admin.plugins.operations.configure') }} -@else -{{ trans('admin.plugins.operations.configure') }} -@endif - -{{ trans('admin.plugins.operations.delete') }} diff --git a/resources/views/vendor/admin-operations/users/operations.tpl b/resources/views/vendor/admin-operations/users/operations.tpl deleted file mode 100644 index 29e714e3..00000000 --- a/resources/views/vendor/admin-operations/users/operations.tpl +++ /dev/null @@ -1,50 +0,0 @@ - -
    - - -
    - -{{-- If current user is super admin --}} -@if (app('user.current')->getPermission() == User::SUPER_ADMIN) - - @if ($permission == "2") - {{ trans('admin.users.operations.delete.delete') }} - @else - {{ trans('admin.users.operations.delete.delete') }} - @endif - -@else - @if ($permission == "1" || $permission == "2") - {{ trans('admin.users.operations.delete.delete') }} - @else - {{ trans('admin.users.operations.delete.delete') }} - @endif - -@endif diff --git a/resources/views/vendor/admin-operations/users/score.tpl b/resources/views/vendor/admin-operations/users/score.tpl deleted file mode 100644 index 312643da..00000000 --- a/resources/views/vendor/admin-operations/users/score.tpl +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/views/vendor/breadcrumb.tpl b/resources/views/vendor/breadcrumb.tpl index abfe7973..636c61e6 100644 --- a/resources/views/vendor/breadcrumb.tpl +++ b/resources/views/vendor/breadcrumb.tpl @@ -5,17 +5,18 @@ {{ trans('skinlib.filter.skin') }} {{ trans('skinlib.filter.any-model') }} @elseif ($filter == "steve") - {{ trans('skinlib.filter.any-model') }} - ({{ trans('skinlib.filter.steve-model') }}) + {{ trans('skinlib.filter.skin') }} + {{ trans('skinlib.filter.steve-model') }} @elseif ($filter == "alex") {{ trans('skinlib.filter.skin') }} {{ trans('skinlib.filter.alex-model') }} @elseif ($filter == "cape") {{ trans('skinlib.filter.cape') }} - @elseif ($filter == "user") - {{ trans('skinlib.filter.uploader', ['name' => App::make('users')->get($_GET['uid'])->getNickName()]) }} @endif + @unless ($uploader == 0) +
  • {{ trans('skinlib.filter.uploader', ['name' => App::make('users')->get($_GET['uid'])->getNickName()]) }}
  • + @endunless
  • @if ($sort == "time") {{ trans('skinlib.sort.newest-uploaded') }} diff --git a/resources/views/vendor/closet-items.tpl b/resources/views/vendor/closet-items.tpl deleted file mode 100644 index 1bbb9dac..00000000 --- a/resources/views/vendor/closet-items.tpl +++ /dev/null @@ -1,30 +0,0 @@ -@forelse ($items as $item) -
    -
    - -
    - -
    -@empty -
    - @if($q) - {{ trans('skinlib.general.no-result') }} - @else - {!! trans('user.closet.empty-msg', ['url' => url('skinlib')]) !!} - @endif -
    - -@endforelse diff --git a/resources/views/vendor/language.tpl b/resources/views/vendor/language.tpl index 80fb447c..88ab9b9f 100644 --- a/resources/views/vendor/language.tpl +++ b/resources/views/vendor/language.tpl @@ -8,7 +8,11 @@