mirror of
https://github.com/bs-community/blessing-skin-server.git
synced 2025-01-24 14:04:07 +08:00
Reimplementing closet
This commit is contained in:
parent
fb89859dd2
commit
5915b3ec17
65
app/Console/Commands/MigrateCloset.php
Normal file
65
app/Console/Commands/MigrateCloset.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use DB;
|
||||
use Schema;
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class MigrateCloset extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'bs:migrate-v4:closet';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Migrate the closet for v4';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (!Schema::hasTable('closets')) {
|
||||
$this->info('Nothing to do.');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->info('We will migrate all closets data. Please wait...');
|
||||
|
||||
$rows = DB::table('closets')->select('*')->get();
|
||||
$bar = $this->output->createProgressBar($rows->count());
|
||||
|
||||
$rows->map(function ($row) use ($bar) {
|
||||
$closet = User::find($row->uid)->closet();
|
||||
collect(json_decode($row->textures, true))->each(function ($item) use ($closet) {
|
||||
$closet->attach($item['tid'], ['item_name' => $item['name']]);
|
||||
});
|
||||
$bar->advance();
|
||||
});
|
||||
|
||||
Schema::drop('closets');
|
||||
$bar->finish();
|
||||
$this->info("\nCongrats! Everything are done.");
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ class Kernel extends ConsoleKernel
|
||||
Commands\KeyRandomCommand::class,
|
||||
Commands\SaltRandomCommand::class,
|
||||
Commands\MigratePlayersTable::class,
|
||||
Commands\MigrateCloset::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Closet;
|
||||
|
||||
class ClosetWasFiltered extends Event
|
||||
{
|
||||
public $closet;
|
||||
|
||||
public function __construct(Closet $closet)
|
||||
{
|
||||
$this->closet = $closet;
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Closet;
|
||||
|
||||
class ClosetWillBeFiltered extends Event
|
||||
{
|
||||
public $closet;
|
||||
|
||||
public function __construct(Closet $closet)
|
||||
{
|
||||
$this->closet = $closet;
|
||||
}
|
||||
}
|
@ -5,29 +5,12 @@ namespace App\Http\Controllers;
|
||||
use View;
|
||||
use Option;
|
||||
use App\Models\User;
|
||||
use App\Models\Closet;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ClosetController extends Controller
|
||||
{
|
||||
/**
|
||||
* Instance of Closet.
|
||||
*
|
||||
* @var \App\Models\Closet
|
||||
*/
|
||||
private $closet;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware(function ($request, $next) {
|
||||
$this->closet = new Closet(Auth::id());
|
||||
|
||||
return $next($request);
|
||||
});
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return view('user.closet')->with('user', Auth::user());
|
||||
@ -37,29 +20,39 @@ class ClosetController extends Controller
|
||||
{
|
||||
$category = $request->input('category', 'skin');
|
||||
$page = abs($request->input('page', 1));
|
||||
$per_page = (int) $request->input('perPage', 6);
|
||||
$perPage = (int) $request->input('perPage', 6);
|
||||
$q = $request->input('q', null);
|
||||
|
||||
$per_page = $per_page > 0 ? $per_page : 6;
|
||||
$perPage = $perPage > 0 ? $perPage : 6;
|
||||
|
||||
$items = collect();
|
||||
$user = auth()->user();
|
||||
$closet = $user->closet();
|
||||
|
||||
if ($q) {
|
||||
// Do search
|
||||
$items = $this->closet->getItems($category)->filter(function ($item) use ($q) {
|
||||
return stristr($item['name'], $q);
|
||||
});
|
||||
if ($category == 'cape') {
|
||||
$closet = $closet->where('type', 'cape');
|
||||
} else {
|
||||
$items = $this->closet->getItems($category);
|
||||
$closet = $closet->where(function ($query) {
|
||||
return $query->where('type', 'steve')->orWhere('type', 'alex');
|
||||
});
|
||||
}
|
||||
|
||||
if ($q) {
|
||||
$closet = $closet->where('item_name', 'like', "%$q%");
|
||||
}
|
||||
|
||||
$closet->offset(($page - 1) * $perPage)->limit($perPage);
|
||||
|
||||
// Pagination
|
||||
$total_pages = ceil($items->count() / $per_page);
|
||||
$items = $closet->get()->map(function ($t) {
|
||||
$t->name = $t->pivot->item_name;
|
||||
return $t;
|
||||
});
|
||||
$totalPages = ceil($items->count() / $perPage);
|
||||
|
||||
return response()->json([
|
||||
'category' => $category,
|
||||
'items' => $items->forPage($page, $per_page)->values(),
|
||||
'total_pages' => $total_pages,
|
||||
'items' => $items,
|
||||
'total_pages' => $totalPages,
|
||||
]);
|
||||
}
|
||||
|
||||
@ -70,9 +63,9 @@ class ClosetController extends Controller
|
||||
'name' => 'required|no_special_chars',
|
||||
]);
|
||||
|
||||
$currentUser = Auth::user();
|
||||
$user = Auth::user();
|
||||
|
||||
if ($currentUser->getScore() < option('score_per_closet_item')) {
|
||||
if ($user->getScore() < option('score_per_closet_item')) {
|
||||
return json(trans('user.closet.add.lack-score'), 7);
|
||||
}
|
||||
|
||||
@ -81,19 +74,14 @@ class ClosetController extends Controller
|
||||
return json(trans('user.closet.add.not-found'), 1);
|
||||
}
|
||||
|
||||
if ($this->closet->add($tid, $request->name)) {
|
||||
$t = Texture::find($tid);
|
||||
$t->likes += 1;
|
||||
$t->save();
|
||||
|
||||
$this->closet->save();
|
||||
|
||||
$currentUser->setScore(option('score_per_closet_item'), 'minus');
|
||||
|
||||
return json(trans('user.closet.add.success', ['name' => $request->input('name')]), 0);
|
||||
} else {
|
||||
if ($user->closet()->where('tid', $request->tid)->count() > 0) {
|
||||
return json(trans('user.closet.add.repeated'), 1);
|
||||
}
|
||||
|
||||
$user->closet()->attach($tid, ['item_name' => $request->name]);
|
||||
$user->setScore(option('score_per_closet_item'), 'minus');
|
||||
|
||||
return json(trans('user.closet.add.success', ['name' => $request->input('name')]), 0);
|
||||
}
|
||||
|
||||
public function rename(Request $request)
|
||||
@ -103,35 +91,34 @@ class ClosetController extends Controller
|
||||
'new_name' => 'required|no_special_chars',
|
||||
]);
|
||||
|
||||
if ($this->closet->rename($request->tid, $request->new_name)) {
|
||||
$this->closet->save();
|
||||
$user = auth()->user();
|
||||
|
||||
return json(trans('user.closet.rename.success', ['name' => $request->new_name]), 0);
|
||||
} else {
|
||||
if ($user->closet()->where('tid', $request->tid)->count() == 0) {
|
||||
return json(trans('user.closet.remove.non-existent'), 1);
|
||||
}
|
||||
|
||||
$user->closet()->updateExistingPivot($request->tid, ['item_name' => $request->new_name]);
|
||||
return json(trans('user.closet.rename.success', ['name' => $request->new_name]), 0);
|
||||
}
|
||||
|
||||
public function remove(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'tid' => 'required|integer',
|
||||
'tid' => 'required|integer',
|
||||
]);
|
||||
|
||||
if ($this->closet->remove($request->tid)) {
|
||||
$t = Texture::find($request->tid);
|
||||
$t->likes = $t->likes - 1;
|
||||
$t->save();
|
||||
$user = auth()->user();
|
||||
|
||||
$this->closet->save();
|
||||
|
||||
if (option('return_score')) {
|
||||
Auth::user()->setScore(option('score_per_closet_item'), 'plus');
|
||||
}
|
||||
|
||||
return json(trans('user.closet.remove.success'), 0);
|
||||
} else {
|
||||
if ($user->closet()->where('tid', $request->tid)->count() == 0) {
|
||||
return json(trans('user.closet.remove.non-existent'), 1);
|
||||
}
|
||||
|
||||
$user->closet()->detach($request->tid);
|
||||
|
||||
if (option('return_score')) {
|
||||
$user->setScore(option('score_per_closet_item'), 'plus');
|
||||
}
|
||||
|
||||
return json(trans('user.closet.remove.success'), 0);
|
||||
}
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ class SetupController extends Controller
|
||||
}
|
||||
|
||||
$existingTables = [];
|
||||
$tables = $tables ?: ['users', 'closets', 'players', 'textures', 'options'];
|
||||
$tables = $tables ?: ['users', 'user_closet', 'players', 'textures', 'options'];
|
||||
|
||||
foreach ($tables as $tableName) {
|
||||
// Table prefix will be added automatically
|
||||
|
@ -7,7 +7,6 @@ use Option;
|
||||
use Session;
|
||||
use Storage;
|
||||
use App\Models\User;
|
||||
use App\Models\Closet;
|
||||
use App\Models\Player;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Http\Request;
|
||||
@ -48,7 +47,7 @@ class SkinlibController extends Controller
|
||||
*/
|
||||
public function getSkinlibFiltered(Request $request)
|
||||
{
|
||||
$currentUser = Auth::user();
|
||||
$user = Auth::user();
|
||||
|
||||
// Available filters: skin, steve, alex, cape
|
||||
$filter = $request->input('filter', 'skin');
|
||||
@ -74,7 +73,7 @@ class SkinlibController extends Controller
|
||||
if ($filter == 'skin') {
|
||||
$query = Texture::where(function ($innerQuery) {
|
||||
// Nested condition, DO NOT MODIFY
|
||||
$innerQuery->where('type', '=', 'steve')->orWhere('type', '=', 'alex');
|
||||
$innerQuery->where('type', 'steve')->orWhere('type', 'alex');
|
||||
});
|
||||
} else {
|
||||
$query = Texture::where('type', $filter);
|
||||
@ -88,14 +87,14 @@ class SkinlibController extends Controller
|
||||
$query = $query->where('uploader', $uploader);
|
||||
}
|
||||
|
||||
if (! $currentUser) {
|
||||
if (! $user) {
|
||||
// Show public textures only to anonymous visitors
|
||||
$query = $query->where('public', true);
|
||||
} else {
|
||||
// Show private textures when show uploaded textures of current user
|
||||
if ($uploader != $currentUser->uid && ! $currentUser->isAdmin()) {
|
||||
$query = $query->where(function ($innerQuery) use ($currentUser) {
|
||||
$innerQuery->where('public', true)->orWhere('uploader', '=', $currentUser->uid);
|
||||
if ($uploader != $user->uid && ! $user->isAdmin()) {
|
||||
$query = $query->where(function ($innerQuery) use ($user) {
|
||||
$innerQuery->where('public', true)->orWhere('uploader', '=', $user->uid);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -107,16 +106,16 @@ class SkinlibController extends Controller
|
||||
->take($itemsPerPage)
|
||||
->get();
|
||||
|
||||
if ($currentUser) {
|
||||
$closet = new Closet($currentUser->uid);
|
||||
if ($user) {
|
||||
$closet = $user->closet()->get();
|
||||
foreach ($textures as $item) {
|
||||
$item->liked = $closet->has($item->tid);
|
||||
$item->liked = $closet->contains('tid', $item->tid);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'items' => $textures,
|
||||
'current_uid' => $currentUser ? $currentUser->uid : 0,
|
||||
'current_uid' => $user ? $user->uid : 0,
|
||||
'total_pages' => $totalPages,
|
||||
]);
|
||||
}
|
||||
@ -152,7 +151,7 @@ class SkinlibController extends Controller
|
||||
public function info($tid)
|
||||
{
|
||||
if ($t = Texture::find($tid)) {
|
||||
return json($t->toArray());
|
||||
return json(array_merge($t->toArray(), ['likes' => $t->likes]));
|
||||
} else {
|
||||
return json([]);
|
||||
}
|
||||
@ -176,7 +175,6 @@ class SkinlibController extends Controller
|
||||
$t = new Texture();
|
||||
$t->name = $request->input('name');
|
||||
$t->type = $request->input('type');
|
||||
$t->likes = 1;
|
||||
$t->hash = bs_hash_file($request->file('file'));
|
||||
$t->size = ceil($request->file('file')->getSize() / 1024);
|
||||
$t->public = $request->input('public') == 'true';
|
||||
@ -212,11 +210,10 @@ class SkinlibController extends Controller
|
||||
|
||||
$user->setScore($cost, 'minus');
|
||||
|
||||
if ($user->getCloset()->add($t->tid, $t->name)) {
|
||||
return json(trans('skinlib.upload.success', ['name' => $request->input('name')]), 0, [
|
||||
'tid' => $t->tid,
|
||||
]);
|
||||
}
|
||||
$user->closet()->attach($t->tid, ['item_name' => $t->name]);
|
||||
return json(trans('skinlib.upload.success', ['name' => $request->input('name')]), 0, [
|
||||
'tid' => $t->tid,
|
||||
]);
|
||||
}
|
||||
|
||||
// @codeCoverageIgnore
|
||||
@ -281,10 +278,14 @@ class SkinlibController extends Controller
|
||||
$type = $t->type == 'cape' ? 'cape' : 'skin';
|
||||
Player::where("tid_$type", $t->tid)
|
||||
->where('uid', '<>', session('uid'))
|
||||
->get()
|
||||
->each(function ($player) use ($type) {
|
||||
$player->setTexture(["tid_$type" => 0]);
|
||||
});
|
||||
->update(["tid_$type" => 0]);
|
||||
|
||||
$t->likers()->get()->each(function ($user) use ($t) {
|
||||
$user->closet()->detach($t->tid);
|
||||
if (option('return_score')) {
|
||||
$user->setScore(option('score_per_closet_item'), 'plus');
|
||||
}
|
||||
});
|
||||
|
||||
@$users->get($t->uploader)->setScore($score_diff, 'plus');
|
||||
|
||||
|
@ -1,268 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use DB;
|
||||
use App\Events;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class Closet
|
||||
{
|
||||
public $uid;
|
||||
|
||||
/**
|
||||
* Instance of Query Builder.
|
||||
*
|
||||
* @var \Illuminate\Database\Query\Builder
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* Textures array generated from json.
|
||||
*
|
||||
* @var Collection
|
||||
*/
|
||||
private $textures;
|
||||
|
||||
/**
|
||||
* Indicates if closet has been modified.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $closet_modified = false;
|
||||
|
||||
/**
|
||||
* Construct Closet object with owner's uid.
|
||||
*
|
||||
* @param int $uid
|
||||
*/
|
||||
public function __construct($uid)
|
||||
{
|
||||
$this->uid = $uid;
|
||||
$this->db = DB::table('closets');
|
||||
|
||||
// Create a new closet if not exists
|
||||
if ($this->db->where('uid', $uid)->count() == 0) {
|
||||
$this->db->insert([
|
||||
'uid' => $uid,
|
||||
'textures' => '[]',
|
||||
]);
|
||||
}
|
||||
|
||||
// Load items from json string
|
||||
$this->textures = collect(json_decode(
|
||||
$this->db->where('uid', $uid)->first()->textures,
|
||||
true
|
||||
));
|
||||
|
||||
event(new Events\ClosetWillBeFiltered($this));
|
||||
|
||||
// Traverse items in the closet
|
||||
$removedCount = $this->textures->filter(function ($texture) use ($uid) {
|
||||
$t = Texture::find($texture['tid']);
|
||||
|
||||
// If the texture was deleted
|
||||
if (is_null($t)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! $t->public && $t->uploader != $uid && ! app('users')->get($uid)->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})->each(function ($texture) use ($uid) {
|
||||
$this->remove($texture['tid']);
|
||||
})->count();
|
||||
|
||||
event(new Events\ClosetWasFiltered($this));
|
||||
|
||||
// Return scores if the texture was deleted or set as private
|
||||
if (option('return_score')) {
|
||||
app('users')->get($uid)->setScore(
|
||||
option('score_per_closet_item') * $removedCount,
|
||||
'plus'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array of instances of App\Models\Texture.
|
||||
*
|
||||
* @param string $category "skin" or "cape" or "all".
|
||||
* @return array
|
||||
*/
|
||||
public function getItems($category = 'all')
|
||||
{
|
||||
$textures = Texture::whereIn('tid', $this->textures->pluck('tid')->all())
|
||||
->get()
|
||||
->map(function ($texture) {
|
||||
$in_closet = $this->textures
|
||||
->where('tid', $texture->tid)
|
||||
->first();
|
||||
|
||||
return [
|
||||
'tid' => $texture->tid,
|
||||
'name' => $in_closet['name'],
|
||||
'type' => $texture->type,
|
||||
'add_at' => $in_closet['add_at'],
|
||||
];
|
||||
})
|
||||
->sortByDesc('add_at');
|
||||
if ($category == 'all') {
|
||||
return $textures->values()->all();
|
||||
} elseif ($category == 'cape') {
|
||||
return $textures->filter(function ($texture) {
|
||||
return $texture['type'] == 'cape';
|
||||
})->values();
|
||||
} else {
|
||||
return $textures->reject(function ($texture) {
|
||||
return $texture['type'] == 'cape';
|
||||
})->values();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to the closet.
|
||||
*
|
||||
* @param int $tid
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function add($tid, $name)
|
||||
{
|
||||
if ($this->has($tid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->textures->push([
|
||||
'tid' => (int) $tid,
|
||||
'name' => $name,
|
||||
'add_at' => time(),
|
||||
]);
|
||||
|
||||
$this->closet_modified = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if texture is in the closet.
|
||||
*
|
||||
* @param int $tid
|
||||
* @return bool
|
||||
*/
|
||||
public function has($tid)
|
||||
{
|
||||
return $this->textures->contains('tid', $tid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one texture info.
|
||||
*
|
||||
* @param int $tid
|
||||
* @return array|null Result
|
||||
*/
|
||||
public function get($tid)
|
||||
{
|
||||
return $this->textures->where('tid', $tid)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename closet item.
|
||||
*
|
||||
* @param int $tid
|
||||
* @param string $newName
|
||||
* @return bool
|
||||
*/
|
||||
public function rename($tid, $newName)
|
||||
{
|
||||
if (! $this->has($tid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->textures->transform(function ($texture) use ($tid, $newName) {
|
||||
if ($texture['tid'] == $tid) {
|
||||
$texture['name'] = $newName;
|
||||
}
|
||||
|
||||
return $texture;
|
||||
});
|
||||
|
||||
$this->closet_modified = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a texture from closet.
|
||||
*
|
||||
* @param int $tid
|
||||
* @return bool
|
||||
*/
|
||||
public function remove($tid)
|
||||
{
|
||||
if (! $this->has($tid)) {
|
||||
return false;
|
||||
}
|
||||
$this->textures = $this->textures->reject(function ($texture) use ($tid) {
|
||||
return $texture['tid'] == $tid;
|
||||
});
|
||||
|
||||
$this->closet_modified = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set textures string manually.
|
||||
*
|
||||
* @param string $textures
|
||||
* @return int
|
||||
*/
|
||||
public function setTextures($textures)
|
||||
{
|
||||
return $this->db->where('uid', $this->uid)->update(['textures' => $textures]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do really database operations.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if (! $this->closet_modified) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->closet_modified = false;
|
||||
|
||||
return $this->setTextures($this->textures->values()->toJson());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save when the object will be destructed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all closets.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function all()
|
||||
{
|
||||
$result = [];
|
||||
foreach (DB::table('closets')->pluck('uid') as $uid) {
|
||||
$result[] = new Closet($uid);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -16,14 +16,23 @@ class Texture extends Model
|
||||
*/
|
||||
protected $casts = [
|
||||
'tid' => 'integer',
|
||||
'likes' => 'integer',
|
||||
'size' => 'integer',
|
||||
'uploader' => 'integer',
|
||||
'public' => 'boolean',
|
||||
];
|
||||
|
||||
public function getLikesAttribute()
|
||||
{
|
||||
return $this->likers()->count();
|
||||
}
|
||||
|
||||
public function scopeLike($query, $field, $value)
|
||||
{
|
||||
return $query->where($field, 'LIKE', "%$value%");
|
||||
}
|
||||
|
||||
public function likers()
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'user_closet')->withPivot('item_name');
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,6 @@ class User extends Authenticatable
|
||||
const ADMIN = 1;
|
||||
const SUPER_ADMIN = 2;
|
||||
|
||||
/**
|
||||
* Instance of Closet.
|
||||
* @var \App\Models\Closet
|
||||
*/
|
||||
protected $closet;
|
||||
|
||||
/**
|
||||
* Properties for Eloquent Model.
|
||||
*/
|
||||
@ -61,18 +55,9 @@ class User extends Authenticatable
|
||||
return $this->permission >= static::ADMIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get closet instance.
|
||||
*
|
||||
* @return \App\Models\Closet
|
||||
*/
|
||||
public function getCloset()
|
||||
public function closet()
|
||||
{
|
||||
if (! $this->closet) {
|
||||
$this->closet = new Closet($this->uid);
|
||||
}
|
||||
|
||||
return $this->closet;
|
||||
return $this->belongsToMany(Texture::class, 'user_closet')->withPivot('item_name');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -332,11 +317,7 @@ class User extends Authenticatable
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
// Delete the players he owned
|
||||
Player::where('uid', $this->uid)->delete();
|
||||
// Delete his closet
|
||||
DB::table('closets')->where('uid', $this->uid)->delete();
|
||||
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Closet;
|
||||
|
||||
$factory->define(Closet::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'uid' => factory(User::class)->create()->uid,
|
||||
'textures' => '[]',
|
||||
];
|
||||
});
|
@ -6,7 +6,6 @@ $factory->define(Texture::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'name' => $faker->firstName,
|
||||
'type' => 'steve',
|
||||
'likes' => rand(0, 50),
|
||||
'hash' => $faker->sha256,
|
||||
'size' => rand(1, 2048),
|
||||
'uploader' => factory(App\Models\User::class)->create()->uid,
|
||||
@ -19,7 +18,6 @@ $factory->defineAs(Texture::class, 'alex', function (Faker\Generator $faker) {
|
||||
return [
|
||||
'name' => $faker->firstName,
|
||||
'type' => 'alex',
|
||||
'likes' => rand(0, 50),
|
||||
'hash' => $faker->sha256,
|
||||
'size' => rand(1, 2048),
|
||||
'uploader' => factory(App\Models\User::class)->create()->uid,
|
||||
@ -32,7 +30,6 @@ $factory->defineAs(Texture::class, 'cape', function (Faker\Generator $faker) {
|
||||
return [
|
||||
'name' => $faker->firstName,
|
||||
'type' => 'cape',
|
||||
'likes' => rand(0, 50),
|
||||
'hash' => $faker->sha256,
|
||||
'size' => rand(1, 2048),
|
||||
'uploader' => factory(App\Models\User::class)->create()->uid,
|
||||
|
@ -25,11 +25,6 @@ class CreateAllTables extends Migration
|
||||
$table->dateTime('register_at');
|
||||
});
|
||||
|
||||
Schema::create('closets', function (Blueprint $table) {
|
||||
$table->increments('uid');
|
||||
$table->longText('textures');
|
||||
});
|
||||
|
||||
Schema::create('players', function (Blueprint $table) {
|
||||
$table->increments('pid');
|
||||
$table->integer('uid');
|
||||
@ -42,7 +37,6 @@ class CreateAllTables extends Migration
|
||||
$table->increments('tid');
|
||||
$table->string('name', 50);
|
||||
$table->string('type', 10);
|
||||
$table->integer('likes');
|
||||
$table->string('hash', 64);
|
||||
$table->integer('size');
|
||||
$table->integer('uploader');
|
||||
@ -65,7 +59,6 @@ class CreateAllTables extends Migration
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('users');
|
||||
Schema::drop('closets');
|
||||
Schema::drop('players');
|
||||
Schema::drop('textures');
|
||||
Schema::drop('options');
|
||||
|
32
database/migrations/2019_03_14_174727_create_closet.php
Normal file
32
database/migrations/2019_03_14_174727_create_closet.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCloset extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('user_closet', function (Blueprint $table) {
|
||||
$table->integer('user_uid');
|
||||
$table->integer('texture_tid');
|
||||
$table->text('item_name')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('user_closet');
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ Object.defineProperty(blessing, 'extra', {
|
||||
download: {{ option('allow_downloading_texture') ? 'true' : 'false' }},
|
||||
currentUid: {{ is_null($user) ? '0' : $user->uid }},
|
||||
admin: {{ $user && $user->isAdmin() ? 'true' : 'false' }},
|
||||
inCloset: {{ $user && $user->getCloset()->has($texture->tid) ? 'true' : 'false' }},
|
||||
inCloset: {{ $user && $user->closet()->where('tid', $texture->tid)->count() > 0 ? 'true' : 'false' }},
|
||||
nickname: @php echo ($up = app('users')->get($texture->uploader)) ? '"'.$up->nickname.'"' : 'null' @endphp
|
||||
})
|
||||
})
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace Tests;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Closet;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
@ -31,18 +30,16 @@ class ClosetControllerTest extends TestCase
|
||||
public function testGetClosetData()
|
||||
{
|
||||
$textures = factory(Texture::class, 10)->create();
|
||||
$closet = new Closet($this->user->uid);
|
||||
$textures->each(function ($texture) use ($closet) {
|
||||
$closet->add($texture->tid, $texture->name);
|
||||
$textures->each(function ($t) {
|
||||
$this->user->closet()->attach($t->tid, ['item_name' => $t->name]);
|
||||
});
|
||||
$closet->save();
|
||||
|
||||
// Use default query parameters
|
||||
$this->getJson('/user/closet-data')
|
||||
->assertJsonStructure([
|
||||
'category',
|
||||
'total_pages',
|
||||
'items' => [['tid', 'name', 'type', 'add_at']],
|
||||
'items' => [['tid', 'name', 'type']],
|
||||
]);
|
||||
|
||||
// Responsive
|
||||
@ -55,8 +52,7 @@ class ClosetControllerTest extends TestCase
|
||||
|
||||
// Get capes
|
||||
$cape = factory(Texture::class, 'cape')->create();
|
||||
$closet->add($cape->tid, 'custom_name');
|
||||
$closet->save();
|
||||
$this->user->closet()->attach($cape->tid, ['item_name' => 'custom_name']);
|
||||
$this->getJson('/user/closet-data?category=cape')
|
||||
->assertJson([
|
||||
'category' => 'cape',
|
||||
@ -65,7 +61,6 @@ class ClosetControllerTest extends TestCase
|
||||
'tid' => $cape->tid,
|
||||
'name' => 'custom_name',
|
||||
'type' => 'cape',
|
||||
'add_at' => $closet->get($cape->tid)['add_at'],
|
||||
]],
|
||||
]);
|
||||
|
||||
@ -79,7 +74,6 @@ class ClosetControllerTest extends TestCase
|
||||
'tid' => $random->tid,
|
||||
'name' => $random->name,
|
||||
'type' => $random->type,
|
||||
'add_at' => $closet->get($random->tid)['add_at'],
|
||||
]],
|
||||
]);
|
||||
}
|
||||
@ -87,6 +81,7 @@ class ClosetControllerTest extends TestCase
|
||||
public function testAdd()
|
||||
{
|
||||
$texture = factory(Texture::class)->create();
|
||||
$likes = $texture->likes;
|
||||
$name = 'my';
|
||||
option(['score_per_closet_item' => 10]);
|
||||
|
||||
@ -152,11 +147,10 @@ class ClosetControllerTest extends TestCase
|
||||
'errno' => 0,
|
||||
'msg' => trans('user.closet.add.success', ['name' => $name]),
|
||||
]);
|
||||
$this->assertEquals($texture->likes + 1, Texture::find($texture->tid)->likes);
|
||||
$this->assertEquals($likes + 1, Texture::find($texture->tid)->likes);
|
||||
$this->user = User::find($this->user->uid);
|
||||
$this->assertEquals(90, $this->user->score);
|
||||
$closet = new Closet($this->user->uid);
|
||||
$this->assertTrue($closet->has($texture->tid));
|
||||
$this->assertEquals(1, $this->user->closet()->count());
|
||||
|
||||
// If the texture is duplicated, should be warned
|
||||
$this->postJson(
|
||||
@ -217,10 +211,7 @@ class ClosetControllerTest extends TestCase
|
||||
]);
|
||||
|
||||
// Rename a closet item successfully
|
||||
$closet = new Closet($this->user->uid);
|
||||
$closet->add($texture->tid, 'name');
|
||||
$closet->save();
|
||||
$closet = new Closet($this->user->uid);
|
||||
$this->user->closet()->attach($texture->tid, ['item_name' => 'name']);
|
||||
$this->postJson(
|
||||
'/user/closet/rename',
|
||||
['tid' => $texture->tid, 'new_name' => $name]
|
||||
@ -228,14 +219,13 @@ class ClosetControllerTest extends TestCase
|
||||
'errno' => 0,
|
||||
'msg' => trans('user.closet.rename.success', ['name' => 'new']),
|
||||
]);
|
||||
$closet->save();
|
||||
$closet = new Closet($this->user->uid);
|
||||
$this->assertFalse(collect($closet->getItems())->where('name', 'new')->isEmpty());
|
||||
$this->assertEquals(1, $this->user->closet()->where('item_name', 'new')->count());
|
||||
}
|
||||
|
||||
public function testRemove()
|
||||
{
|
||||
$texture = factory(Texture::class)->create();
|
||||
$likes = $texture->likes;
|
||||
|
||||
// Missing `tid` field
|
||||
$this->postJson('/user/closet/remove')
|
||||
@ -263,9 +253,7 @@ class ClosetControllerTest extends TestCase
|
||||
]);
|
||||
|
||||
// Should return score if `return_score` is true
|
||||
$closet = new Closet($this->user->uid);
|
||||
$closet->add($texture->tid, 'name');
|
||||
$closet->save();
|
||||
$this->user->closet()->attach($texture->tid, ['item_name' => 'name']);
|
||||
$score = $this->user->score;
|
||||
$this->postJson(
|
||||
'/user/closet/remove',
|
||||
@ -274,17 +262,15 @@ class ClosetControllerTest extends TestCase
|
||||
'errno' => 0,
|
||||
'msg' => trans('user.closet.remove.success'),
|
||||
]);
|
||||
$closet = new Closet($this->user->uid);
|
||||
$this->assertEquals($texture->likes - 1, Texture::find($texture->tid)->likes);
|
||||
$this->assertEquals($likes, Texture::find($texture->tid)->likes);
|
||||
$this->assertEquals($score + option('score_per_closet_item'), $this->user->score);
|
||||
$this->assertFalse($closet->has($texture->tid));
|
||||
$this->assertEquals(0, $this->user->closet()->count());
|
||||
|
||||
$texture = Texture::find($texture->tid);
|
||||
$likes = $texture->likes;
|
||||
// Should not return score if `return_score` is false
|
||||
option(['return_score' => false]);
|
||||
$closet = new Closet($this->user->uid);
|
||||
$closet->add($texture->tid, 'name');
|
||||
$closet->save();
|
||||
$this->user->closet()->attach($texture->tid, ['item_name' => 'name']);
|
||||
$score = $this->user->score;
|
||||
$this->postJson(
|
||||
'/user/closet/remove',
|
||||
@ -293,9 +279,8 @@ class ClosetControllerTest extends TestCase
|
||||
'errno' => 0,
|
||||
'msg' => trans('user.closet.remove.success'),
|
||||
]);
|
||||
$closet = new Closet($this->user->uid);
|
||||
$this->assertEquals($texture->likes - 1, Texture::find($texture->tid)->likes);
|
||||
$this->assertEquals($likes, Texture::find($texture->tid)->likes);
|
||||
$this->assertEquals($score, $this->user->score);
|
||||
$this->assertFalse($closet->has($texture->tid));
|
||||
$this->assertEquals(0, $this->user->closet()->count());
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ class MiddlewareTest extends TestCase
|
||||
$this->get('/setup')->assertSee('Already installed');
|
||||
|
||||
$tables = [
|
||||
'closets', 'migrations', 'options', 'players', 'textures', 'users',
|
||||
'user_closet', 'migrations', 'options', 'players', 'textures', 'users',
|
||||
];
|
||||
array_walk($tables, function ($table) {
|
||||
Schema::dropIfExists($table);
|
||||
|
@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Closet;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
class ClosetTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testAll()
|
||||
{
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$user = factory(User::class)->create();
|
||||
(new Closet($user->uid))->save();
|
||||
}
|
||||
$this->assertCount(2, Closet::all());
|
||||
}
|
||||
|
||||
public function testFilterInvalidTexture()
|
||||
{
|
||||
$other = factory(User::class)->create();
|
||||
$texture = factory(Texture::class)->create([
|
||||
'uploader' => $other->uid,
|
||||
'public' => false,
|
||||
]);
|
||||
$user = factory(User::class)->create();
|
||||
$closet = new Closet($user->uid);
|
||||
$closet->add(-1, '');
|
||||
$closet->add($texture->tid, '');
|
||||
$closet->save();
|
||||
|
||||
$this->assertCount(0, (new Closet($user->uid))->getItems());
|
||||
$this->assertEquals(
|
||||
$user->score + 2 * option('score_per_closet_item'),
|
||||
User::find($user->uid)->score
|
||||
);
|
||||
|
||||
option(['return_score' => false]);
|
||||
$closet = new Closet($user->uid);
|
||||
$closet->add(-1, '');
|
||||
$closet->add($texture->tid, '');
|
||||
$closet->save();
|
||||
$user = User::find($user->uid);
|
||||
$this->assertCount(0, (new Closet($user->uid))->getItems());
|
||||
$this->assertEquals($user->score, User::find($user->uid)->score);
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ class SetupControllerTest extends TestCase
|
||||
protected function dropAllTables()
|
||||
{
|
||||
$tables = [
|
||||
'closets', 'migrations', 'options', 'players', 'textures', 'users',
|
||||
'user_closet', 'migrations', 'options', 'players', 'textures', 'users',
|
||||
];
|
||||
array_walk($tables, function ($table) {
|
||||
Schema::dropIfExists($table);
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace Tests;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Closet;
|
||||
use App\Models\Player;
|
||||
use App\Models\Texture;
|
||||
use Illuminate\Support\Str;
|
||||
@ -15,25 +14,6 @@ class SkinlibControllerTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
protected function serializeTextures($textures)
|
||||
{
|
||||
return $textures
|
||||
->map(function ($texture) {
|
||||
return [
|
||||
'tid' => $texture->tid,
|
||||
'name' => $texture->name,
|
||||
'type' => $texture->type,
|
||||
'likes' => $texture->likes,
|
||||
'hash' => $texture->hash,
|
||||
'size' => $texture->size,
|
||||
'uploader' => $texture->uploader,
|
||||
'public' => $texture->public,
|
||||
'upload_at' => $texture->upload_at->format('Y-m-d H:i:s'),
|
||||
];
|
||||
})
|
||||
->all();
|
||||
}
|
||||
|
||||
public function testIndex()
|
||||
{
|
||||
$this->get('/skinlib')->assertViewHas('user');
|
||||
@ -54,26 +34,28 @@ class SkinlibControllerTest extends TestCase
|
||||
$capes = factory(Texture::class, 'cape')->times(5)->create();
|
||||
|
||||
// Default arguments
|
||||
$expected = $skins
|
||||
->sortByDesc('upload_at')
|
||||
->values(); // WTF! DO NOT FORGET IT!!
|
||||
$this->getJson('/skinlib/data')
|
||||
$items = $this->getJson('/skinlib/data')
|
||||
->assertJson([
|
||||
'items' => $this->serializeTextures($expected),
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 1,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$this->assertCount(10, $items);
|
||||
$this->assertTrue(collect($items)->every(function ($item) {
|
||||
return $item['type'] == 'steve' || $item['type'] == 'alex';
|
||||
}));
|
||||
|
||||
// Only steve
|
||||
$expected = $steves
|
||||
->sortByDesc('upload_at')
|
||||
->values();
|
||||
$this->getJson('/skinlib/data?filter=steve')
|
||||
$items = $this->getJson('/skinlib/data?filter=steve')
|
||||
->assertJson([
|
||||
'items' => $this->serializeTextures($expected),
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 1,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$this->assertCount(5, $items);
|
||||
$this->assertTrue(collect($items)->every(function ($item) {
|
||||
return $item['type'] == 'steve';
|
||||
}));
|
||||
|
||||
// Invalid type
|
||||
$this->getJson('/skinlib/data?filter=what')
|
||||
@ -84,70 +66,87 @@ class SkinlibControllerTest extends TestCase
|
||||
]);
|
||||
|
||||
// Only capes
|
||||
$expected = $capes
|
||||
->sortByDesc('upload_at')
|
||||
->values();
|
||||
$this->getJson('/skinlib/data?filter=cape')
|
||||
$items = $this->getJson('/skinlib/data?filter=cape')
|
||||
->assertJson([
|
||||
'items' => $this->serializeTextures($expected),
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 1,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$this->assertCount(5, $items);
|
||||
$this->assertTrue(collect($items)->every(function ($item) {
|
||||
return $item['type'] == 'cape';
|
||||
}));
|
||||
|
||||
// Only specified uploader
|
||||
$uid = $skins->random()->uploader;
|
||||
$expected = $skins
|
||||
$owned = $skins
|
||||
->filter(function ($texture) use ($uid) {
|
||||
return $texture->uploader == $uid;
|
||||
})
|
||||
->sortByDesc('upload_at')
|
||||
->values();
|
||||
$this->getJson('/skinlib/data?uploader='.$uid)
|
||||
});
|
||||
$items = $this->getJson('/skinlib/data?uploader='.$uid)
|
||||
->assertJson([
|
||||
'items' => $this->serializeTextures($expected),
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 1,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$this->assertCount($owned->count(), $items);
|
||||
$this->assertTrue(collect($items)->every(function ($item) use ($uid) {
|
||||
return $item['uploader'] == $uid;
|
||||
}));
|
||||
|
||||
// Sort by `tid`
|
||||
$this->getJson('/skinlib/data?sort=tid')
|
||||
$ordered = $skins->sortByDesc('tid')->map(function ($skin) {
|
||||
return $skin->tid;
|
||||
})->values();
|
||||
$items = $this->getJson('/skinlib/data?sort=tid')
|
||||
->assertJson([
|
||||
'items' => $this->serializeTextures($skins->sortByDesc('tid')->values()),
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 1,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertArraySubset($ordered, $items);
|
||||
|
||||
// Search
|
||||
$keyword = Str::limit($skins->random()->name, 1, '');
|
||||
$expected = $skins
|
||||
$keyworded = $skins
|
||||
->filter(function ($texture) use ($keyword) {
|
||||
return Str::contains($texture->name, $keyword) ||
|
||||
Str::contains($texture->name, strtolower($keyword));
|
||||
})
|
||||
->sortByDesc('upload_at')
|
||||
->values();
|
||||
$this->getJson('/skinlib/data?keyword='.$keyword)
|
||||
});
|
||||
$items = $this->getJson('/skinlib/data?keyword='.$keyword)
|
||||
->assertJson([
|
||||
'items' => $this->serializeTextures($expected),
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 1,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$this->assertCount($keyworded->count(), $items);
|
||||
|
||||
// More than one argument
|
||||
$keyword = Str::limit($skins->random()->name, 1, '');
|
||||
$expected = $skins
|
||||
$filtered = $skins
|
||||
->filter(function ($texture) use ($keyword) {
|
||||
return Str::contains($texture->name, $keyword) ||
|
||||
Str::contains($texture->name, strtolower($keyword));
|
||||
})
|
||||
->sortByDesc('likes')
|
||||
->sortByDesc('size')
|
||||
->map(function ($skin) {
|
||||
return $skin->tid;
|
||||
})
|
||||
->values();
|
||||
$this->getJson('/skinlib/data?sort=likes&keyword='.$keyword)
|
||||
$items = $this->getJson('/skinlib/data?sort=size&keyword='.$keyword)
|
||||
->assertJson([
|
||||
'items' => $this->serializeTextures($expected),
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 1,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertCount($filtered->count(), $items);
|
||||
$this->assertArraySubset($filtered, $items);
|
||||
|
||||
// Pagination
|
||||
$steves = factory(Texture::class)
|
||||
@ -155,58 +154,88 @@ class SkinlibControllerTest extends TestCase
|
||||
->create()
|
||||
->merge($steves);
|
||||
$skins = $steves->merge($alexs);
|
||||
$expected = $skins
|
||||
$page1 = $skins
|
||||
->sortByDesc('upload_at')
|
||||
->values()
|
||||
->map(function ($skin) {
|
||||
return $skin->tid;
|
||||
})
|
||||
->forPage(1, 20);
|
||||
$expected = $this->serializeTextures($expected);
|
||||
$this->getJson('/skinlib/data')
|
||||
$items = $this->getJson('/skinlib/data')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
$this->getJson('/skinlib/data?page=-5')
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertCount(20, $items);
|
||||
$this->assertArraySubset($page1, $items);
|
||||
$items = $this->getJson('/skinlib/data?page=-5')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
$expected = $skins
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertCount(20, $items);
|
||||
$this->assertArraySubset($page1, $items);
|
||||
$page2 = $skins
|
||||
->sortByDesc('upload_at')
|
||||
->values()
|
||||
->map(function ($skin) {
|
||||
return $skin->tid;
|
||||
})
|
||||
->forPage(2, 20)
|
||||
->values();
|
||||
$expected = $this->serializeTextures($expected);
|
||||
$this->getJson('/skinlib/data?page=2')
|
||||
$items = $this->getJson('/skinlib/data?page=2')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertCount(5, $items);
|
||||
$this->assertArraySubset($page2, $items);
|
||||
$this->getJson('/skinlib/data?page=8')
|
||||
->assertJson([
|
||||
'items' => [],
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
$this->getJson('/skinlib/data?items_per_page=-6&page=2')
|
||||
$items = $this->getJson('/skinlib/data?items_per_page=-6&page=2')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
$expected = $skins
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertCount($page2->count(), $items);
|
||||
$this->assertArraySubset($page2, $items);
|
||||
$page3 = $skins
|
||||
->sortByDesc('upload_at')
|
||||
->values()
|
||||
->map(function ($skin) {
|
||||
return $skin->tid;
|
||||
})
|
||||
->forPage(3, 8)
|
||||
->values();
|
||||
$this->getJson('/skinlib/data?page=3&items_per_page=8')
|
||||
$items = $this->getJson('/skinlib/data?page=3&items_per_page=8')
|
||||
->assertJson([
|
||||
'items' => $this->serializeTextures($expected),
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 4,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertCount($page3->count(), $items);
|
||||
$this->assertArraySubset($page3, $items);
|
||||
|
||||
// Add some private textures
|
||||
$uploader = factory(User::class)->create();
|
||||
@ -216,85 +245,82 @@ class SkinlibControllerTest extends TestCase
|
||||
->create(['public' => false, 'uploader' => $uploader->uid]);
|
||||
|
||||
// If not logged in, private textures should not be shown
|
||||
$expected = $skins
|
||||
$paged = $skins
|
||||
->sortByDesc('upload_at')
|
||||
->map(function ($skin) {
|
||||
return $skin->tid;
|
||||
})
|
||||
->values()
|
||||
->forPage(1, 20);
|
||||
$expected = $this->serializeTextures($expected);
|
||||
$this->getJson('/skinlib/data')
|
||||
$items = $this->getJson('/skinlib/data')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'current_uid' => 0,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertArraySubset($paged, $items);
|
||||
|
||||
// Other users should not see someone's private textures
|
||||
for ($i = 0, $length = count($expected); $i < $length; $i++) {
|
||||
$expected[$i]['liked'] = false;
|
||||
}
|
||||
$this->actAs($otherUser)
|
||||
$items = $this->actAs($otherUser)
|
||||
->getJson('/skinlib/data')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'current_uid' => $otherUser->uid,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$this->assertTrue(collect($items)->every(function ($item) {
|
||||
return !$item['liked'];
|
||||
}));
|
||||
|
||||
// A user has added a texture from skin library to his closet
|
||||
$texture = $skins
|
||||
->sortByDesc('upload_at')
|
||||
->values()
|
||||
->first();
|
||||
$closet = new Closet($otherUser->uid);
|
||||
$closet->add($texture->tid, $texture->name);
|
||||
$closet->save();
|
||||
for ($i = 0, $length = count($expected); $i < $length; $i++) {
|
||||
if ($expected[$i]['tid'] == $texture->tid) {
|
||||
$expected[$i]['liked'] = true;
|
||||
} else {
|
||||
$expected[$i]['liked'] = false;
|
||||
}
|
||||
}
|
||||
$texture = $skins->sortByDesc('upload_at')->values()->first();
|
||||
$otherUser->closet()->attach($texture->tid, ['item_name' => $texture->name]);
|
||||
$this->getJson('/skinlib/data')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'items' => [
|
||||
['tid' => $texture->tid, 'liked' => true]
|
||||
],
|
||||
'current_uid' => $otherUser->uid,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
|
||||
// Uploader can see his private textures
|
||||
$expected = $skins
|
||||
$withPrivate = $skins
|
||||
->merge($private)
|
||||
->sortByDesc('upload_at')
|
||||
->map(function ($skin) {
|
||||
return $skin->tid;
|
||||
})
|
||||
->values()
|
||||
->forPage(1, 20);
|
||||
$expected = $this->serializeTextures($expected);
|
||||
for ($i = 0, $length = count($expected); $i < $length; $i++) {
|
||||
// The reason we use `false` here is that some textures just were
|
||||
// uploaded by this user, but these textures are not in his closet.
|
||||
// By default(not in testing like now), when you uploaded a texture,
|
||||
// that texture will be added to your closet.
|
||||
// So here, we can assume that a user upload some textures, but he
|
||||
// has deleted them from his closet.
|
||||
$expected[$i]['liked'] = false;
|
||||
}
|
||||
$this->actAs($uploader)
|
||||
$items = $this->actAs($uploader)
|
||||
->getJson('/skinlib/data')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'current_uid' => $uploader->uid,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertArraySubset($withPrivate, $items);
|
||||
|
||||
// Administrators can see private textures
|
||||
$admin = factory(User::class, 'admin')->create();
|
||||
$this->actAs($admin)
|
||||
$items = $this->actAs($admin)
|
||||
->getJson('/skinlib/data')
|
||||
->assertJson([
|
||||
'items' => $expected,
|
||||
'current_uid' => $admin->uid,
|
||||
'total_pages' => 2,
|
||||
]);
|
||||
])
|
||||
->decodeResponseJson('items');
|
||||
$items = array_map(function ($item) {
|
||||
return $item['tid'];
|
||||
}, $items);
|
||||
$this->assertArraySubset($withPrivate, $items);
|
||||
}
|
||||
|
||||
public function testShow()
|
||||
@ -769,6 +795,8 @@ class SkinlibControllerTest extends TestCase
|
||||
$uploader->score += $texture->size * option('private_score_per_storage');
|
||||
$uploader->save();
|
||||
$player = factory(Player::class)->create(['tid_skin' => $texture->tid]);
|
||||
$other = factory(User::class)->create();
|
||||
$other->closet()->attach($texture->tid, ['item_name' => 'a']);
|
||||
$this->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
->assertJson([
|
||||
'errno' => 0,
|
||||
@ -776,6 +804,26 @@ class SkinlibControllerTest extends TestCase
|
||||
'public' => false,
|
||||
]);
|
||||
$this->assertEquals(0, Player::find($player->pid)->tid_skin);
|
||||
$this->assertEquals(0, $other->closet()->count());
|
||||
$this->assertEquals(
|
||||
$other->score + option('score_per_closet_item'),
|
||||
User::find($other->uid)->score
|
||||
);
|
||||
|
||||
// Without returning score
|
||||
option(['return_score' => false]);
|
||||
$texture = factory(Texture::class)->create(['public' => 'false', 'uploader' => $uploader->uid]);
|
||||
$other = factory(User::class)->create();
|
||||
$other->closet()->attach($texture->tid, ['item_name' => 'a']);
|
||||
$this->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
->assertJson([
|
||||
'errno' => 0,
|
||||
'public' => false,
|
||||
]);
|
||||
$this->assertEquals(
|
||||
$other->score,
|
||||
User::find($other->uid)->score
|
||||
);
|
||||
}
|
||||
|
||||
public function testRename()
|
||||
|
Loading…
Reference in New Issue
Block a user