diff --git a/.github/workflows/Lint.yml b/.github/workflows/Lint.yml index 7eae3fc3ec..da191e74c0 100644 --- a/.github/workflows/Lint.yml +++ b/.github/workflows/Lint.yml @@ -9,19 +9,89 @@ on: - '**' types: - opened - - edited - synchronize - reopened jobs: pint: - uses: itinerare/github-actions/.github/workflows/pint.yml@main - with: - php-version: '8.1' + runs-on: ubuntu-latest + + permissions: + contents: write + concurrency: - group: ci-${{ github.head_ref || github.ref_name }} + group: ci-pint-${{ github.head_ref || github.ref_name }} + cancel-in-progress: true + + steps: + - uses: shivammathur/setup-php@bf6b4fbd49ca58e4608c9c89fba0b8d90bd2a39f # v2 + with: + php-version: 8.1 + + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + + - name: Get composer cache directory + id: composer-cache + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache or restore composer cache + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --ignore-platform-reqs + + - name: Run pint + run: composer lint + + - name: Commit changes + uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9 + with: + pull: '--rebase --autostash' + message: 'refactor: fix PHP styling' + committer_name: github-actions[bot] + committer_email: github-actions[bot]@users.noreply.github.com blade-formatter: - uses: itinerare/github-actions/.github/workflows/blade_formatter.yml@main + runs-on: ubuntu-latest + + permissions: + contents: write + concurrency: - group: ci-${{ github.head_ref || github.ref_name }} + group: ci-blade-formatter-${{ github.head_ref || github.ref_name }} + cancel-in-progress: true + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + + - name: Set up node + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5 + with: + node-version: 22.x + cache: 'npm' + + - name: Install packages + run: npm install + + - name: Run blade-formatter + run: npm run format + + - name: Commit changes + uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9 + with: + pull: '--rebase --autostash' + message: 'refactor: fix blade formatting' + committer_name: github-actions[bot] + committer_email: github-actions[bot]@users.noreply.github.com diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5f01e07759..4b4dccb184 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ For support and general questions and discussions, please visit the [support Dis The following are accepted uses for the [issue tracker](https://github.com/corowne/Lorekeeper/issues): - Bug reports -- Feature or enhancement requests (within reason)-- note that these may be denied if they are deemed out of scope of the project and/or are not feasible to implement for any reason. +- Feature or enhancement requests *or* discussion of potential new features (within reason)-- note that these may be denied if they are deemed out of scope of the project and/or are not feasible to implement for any reason. ## Opening an Issue ### Reporting a bug @@ -24,7 +24,7 @@ Avoid listing multiple requests in one issue. One issue per request makes it eas ## Contributing Code -Please see the full [Contribution Guide](http://wiki.lorekeeper.me/index.php?title=Contributing_to_Lorekeeper) for more information! +Please see the full [Contribution Guide](https://lk-arpg.github.io/lk-docs/prerelease/contributing/) for more information! ### About abandoned pull requests diff --git a/app/Actions/Fortify/CreateNewUser.php b/app/Actions/Fortify/CreateNewUser.php index 093462d4e8..c21ab30c70 100644 --- a/app/Actions/Fortify/CreateNewUser.php +++ b/app/Actions/Fortify/CreateNewUser.php @@ -3,6 +3,7 @@ namespace App\Actions\Fortify; use App\Models\Invitation; +use App\Models\Rank\Rank; use App\Models\User\User; use App\Services\InvitationService; use App\Services\UserService; @@ -20,11 +21,14 @@ class CreateNewUser implements CreatesNewUsers { public function create(array $input) { (new UserService)->validator($input)->validate(); + // Create a user with the lowest existing rank + $rank_id = Rank::orderBy('sort')->first()->id; + $user = User::create([ 'name' => $input['name'], 'email' => $input['email'], 'password' => Hash::make($input['password']), - 'rank_id' => 2, + 'rank_id' => $rank_id, 'birthday' => $input['dob'], ]); $user->settings()->create([ diff --git a/app/Console/Commands/FixCharacterImageFormats.php b/app/Console/Commands/FixCharacterImageFormats.php new file mode 100644 index 0000000000..0d4a89a51e --- /dev/null +++ b/app/Console/Commands/FixCharacterImageFormats.php @@ -0,0 +1,72 @@ +count()) { + $this->info('Processing '.$images->count().' images...'); + $images->update(['fullsize_extension' => $fullsizeFormat]); + + foreach ($images->get() as $image) { + if (file_exists($image->imagePath.'/'.$image->id.'_'.$image->hash.'_'.$image->fullsize_hash.'_full.'.$masterlistFormat)) { + Image::make($image->imagePath.'/'.$image->id.'_'.$image->hash.'_'.$image->fullsize_hash.'_full.'.$masterlistFormat)->save($image->imagePath.'/'.$image->fullsizeFileName, 100, $fullsizeFormat); + + if (file_exists($image->imagePath.'/'.$image->fullsizeFileName)) { + unlink($image->imagePath.'/'.$image->id.'_'.$image->hash.'_'.$image->fullsize_hash.'_full.'.$masterlistFormat); + } + } + } + } + + $updates = CharacterDesignUpdate::where('status', '!=', 'Approved'); + if ($updates->count()) { + $this->info('Processing '.$updates->count().' updates...'); + foreach ($updates->get() as $update) { + $updates->update(['extension' => $fullsizeFormat]); + + if (file_exists($update->imagePath.'/'.$update->id.'_'.$update->hash.'.'.$masterlistFormat)) { + Image::make($update->imagePath.'/'.$update->id.'_'.$update->hash.'.'.$masterlistFormat)->save($update->imagePath.'/'.$update->imageFileName, 100, $fullsizeFormat); + + if (file_exists($update->imagePath.'/'.$update->imageFileName)) { + unlink($update->imagePath.'/'.$update->id.'_'.$update->hash.'.'.$masterlistFormat); + } + } + + if (!file_exists($update->imagePath.'/'.$update->thumbnailFileName) && file_exists($update->imagePath.'/'.$update->id.'_'.$update->hash.'_th.'.$fullsizeFormat)) { + Image::make($update->imagePath.'/'.$update->id.'_'.$update->hash.'_th.'.$fullsizeFormat)->save($update->imagePath.'/'.$update->thumbnailFileName, 100, $masterlistFormat); + + if (file_exists($update->imagePath.'/'.$update->thumbnailFileName)) { + unlink($update->imagePath.'/'.$update->id.'_'.$update->hash.'_th.'.$fullsizeFormat); + } + } + } + } + } +} diff --git a/app/Console/Commands/SetupAdminUser.php b/app/Console/Commands/SetupAdminUser.php index c5d3da79dc..a3555ff01b 100644 --- a/app/Console/Commands/SetupAdminUser.php +++ b/app/Console/Commands/SetupAdminUser.php @@ -46,14 +46,16 @@ public function handle() { if (!Rank::count()) { // These need to be created even if the seeder isn't run for the site to work correctly. $adminRank = Rank::create([ - 'name' => 'Admin', - 'description' => 'The site admin. Has the ability to view/edit any data on the site.', - 'sort' => 1, + 'name' => 'Admin', + 'description' => 'The site admin. Has the ability to view/edit any data on the site.', + 'parsed_description' => 'The site admin. Has the ability to view/edit any data on the site.', + 'sort' => 1, ]); Rank::create([ - 'name' => 'Member', - 'description' => 'A regular member of the site.', - 'sort' => 0, + 'name' => 'Member', + 'description' => 'A regular member of the site.', + 'parsed_description' => 'A regular member of the site.', + 'sort' => 0, ]); $this->line('User ranks not found. Default user ranks (admin and basic member) created.'); diff --git a/app/Http/Controllers/Admin/Characters/CharacterImageController.php b/app/Http/Controllers/Admin/Characters/CharacterImageController.php index 391874a3fd..780fa305e7 100644 --- a/app/Http/Controllers/Admin/Characters/CharacterImageController.php +++ b/app/Http/Controllers/Admin/Characters/CharacterImageController.php @@ -249,6 +249,7 @@ public function getImageReupload($id) { * @return \Illuminate\Http\RedirectResponse */ public function postImageReupload(Request $request, CharacterManager $service, $id) { + $request->validate(['image' => CharacterImage::$createRules['image'], 'thumbnail' => CharacterImage::$createRules['thumbnail']]); $data = $request->only(['image', 'thumbnail', 'x0', 'x1', 'y0', 'y1', 'use_cropper']); $image = CharacterImage::find($id); if (!$image) { diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php index dfea74f501..7ab846d571 100644 --- a/app/Http/Controllers/Admin/HomeController.php +++ b/app/Http/Controllers/Admin/HomeController.php @@ -42,6 +42,7 @@ public function getIndex() { 'galleryCurrencyAwards' => $galleryCurrencyAwards, 'gallerySubmissionCount' => GallerySubmission::collaboratorApproved()->where('status', 'Pending')->count(), 'galleryAwardCount' => GallerySubmission::requiresAward()->where('is_valued', 0)->count(), + 'recentUsers' => User::orderBy('id', 'DESC')->take(10)->get(), ]); } diff --git a/app/Http/Controllers/Admin/Users/UserController.php b/app/Http/Controllers/Admin/Users/UserController.php index 49d876c6b9..1b4f30bcc6 100644 --- a/app/Http/Controllers/Admin/Users/UserController.php +++ b/app/Http/Controllers/Admin/Users/UserController.php @@ -460,7 +460,9 @@ public function getUserIpList(Request $request) { $query->orderBy('updated_at', 'ASC'); break; case 'most_users': - $query->select('ip', DB::raw('COUNT(ip) as count'))->groupBy('ip')->orderBy('count', 'DESC'); + $query->select('ip', DB::raw('COUNT(ip) as user_count'), DB::raw('MAX(updated_at) as updated_at')) + ->groupBy('ip') + ->orderBy('user_count', 'DESC'); break; case 'closely_updated': $query->whereExists(function ($query) { @@ -472,10 +474,10 @@ public function getUserIpList(Request $request) { }); break; } + } else { + $query->select('ip', DB::raw('MAX(updated_at) as updated_at'))->groupBy('ip')->orderBy('updated_at', 'DESC'); } - $query->select('ip', DB::raw('MAX(updated_at)'))->groupBy('ip')->orderBy(DB::raw('MAX(updated_at)'), 'DESC'); - return view('admin.users.user_ips', [ 'ips' => $query->paginate(30)->appends($request->query()), 'users' => User::orderBy('name')->pluck('name', 'id')->toArray(), diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 319e53f0f2..dc79783481 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -64,7 +64,7 @@ public function getAuthCallback(LinkService $service, $provider) { $socialite->redirectUrl(str_replace('auth', 'login', url(config('services.'.$provider.'.redirect')))); $result = $socialite->user(); - $user = UserAlias::where('user_snowflake', $result->id)->first(); + $user = UserAlias::where('site', $provider)->where('user_snowflake', $result->id)->first(); if (!$user) { return redirect('/register/'.$provider)->with(['userData' => $result]); } diff --git a/app/Http/Controllers/BrowseController.php b/app/Http/Controllers/BrowseController.php index 733eb3d4e4..069c6196d2 100644 --- a/app/Http/Controllers/BrowseController.php +++ b/app/Http/Controllers/BrowseController.php @@ -32,7 +32,7 @@ class BrowseController extends Controller { * @return \Illuminate\Contracts\Support\Renderable */ public function getUsers(Request $request) { - $query = User::visible()->join('ranks', 'users.rank_id', '=', 'ranks.id')->select('ranks.name AS rank_name', 'users.*'); + $query = User::visible()->with('primaryAlias')->join('ranks', 'users.rank_id', '=', 'ranks.id')->select('ranks.name AS rank_name', 'users.*'); $sort = $request->only(['sort']); if ($request->get('name')) { @@ -106,7 +106,7 @@ public function getDeactivated(Request $request) { 'canView' => $canView, 'privacy' => $privacy, 'key' => $key, - 'users' => $canView ? User::where('is_deactivated', 1)->orderBy('users.name')->paginate(30)->appends($request->query()) : null, + 'users' => $canView ? User::where('is_deactivated', 1)->with('primaryAlias', 'settings')->orderBy('users.name')->paginate(30)->appends($request->query()) : null, ]); } @@ -137,7 +137,7 @@ public function getBlacklist(Request $request) { 'canView' => $canView, 'privacy' => $privacy, 'key' => $key, - 'users' => $canView ? User::where('is_banned', 1)->orderBy('users.name')->paginate(30)->appends($request->query()) : null, + 'users' => $canView ? User::where('is_banned', 1)->with('primaryAlias', 'settings')->orderBy('users.name')->paginate(30)->appends($request->query()) : null, ]); } @@ -147,8 +147,8 @@ public function getBlacklist(Request $request) { * @return \Illuminate\Contracts\Support\Renderable */ public function getCharacters(Request $request) { - $query = Character::with('user.rank')->with('image.features')->with('rarity')->with('image.species')->myo(0); - $imageQuery = CharacterImage::images(Auth::check() ? Auth::user() : null)->with('features')->with('rarity')->with('species')->with('features'); + $query = Character::with('user.rank', 'image.features', 'rarity', 'image.species', 'image.rarity')->myo(0); + $imageQuery = CharacterImage::images(Auth::check() ? Auth::user() : null)->with('features', 'rarity', 'species', 'features'); if ($sublists = Sublist::where('show_main', 0)->get()) { $subCategories = []; @@ -196,9 +196,11 @@ public function getCharacters(Request $request) { if ($request->get('owner')) { $owner = User::find($request->get('owner')); - $query->where(function ($query) use ($owner) { - $query->where('user_id', $owner->id); - }); + if ($owner) { + $query->where(function ($query) use ($owner) { + $query->where('user_id', $owner->id); + }); + } } if ($request->get('owner_url')) { $ownerUrl = $request->get('owner_url'); @@ -229,15 +231,19 @@ public function getCharacters(Request $request) { } if ($request->get('artist')) { $artist = User::find($request->get('artist')); - $imageQuery->whereHas('artists', function ($query) use ($artist) { - $query->where('user_id', $artist->id); - }); + if ($artist) { + $imageQuery->whereHas('artists', function ($query) use ($artist) { + $query->where('user_id', $artist->id); + }); + } } if ($request->get('designer')) { $designer = User::find($request->get('designer')); - $imageQuery->whereHas('designers', function ($query) use ($designer) { - $query->where('user_id', $designer->id); - }); + if ($designer) { + $imageQuery->whereHas('designers', function ($query) use ($designer) { + $query->where('user_id', $designer->id); + }); + } } if ($request->get('artist_url')) { $artistUrl = $request->get('artist_url'); @@ -328,9 +334,9 @@ public function getCharacters(Request $request) { * @return \Illuminate\Contracts\Support\Renderable */ public function getMyos(Request $request) { - $query = Character::with('user.rank')->with('image.features')->with('rarity')->with('image.species')->myo(1); + $query = Character::with('user.rank', 'image.features', 'rarity', 'image.species', 'image.rarity')->myo(1); - $imageQuery = CharacterImage::images(Auth::check() ? Auth::user() : null)->with('features')->with('rarity')->with('species')->with('features'); + $imageQuery = CharacterImage::images(Auth::check() ? Auth::user() : null)->with('features', 'rarity', 'species', 'features'); if ($request->get('name')) { $query->where(function ($query) use ($request) { @@ -363,9 +369,11 @@ public function getMyos(Request $request) { if ($request->get('owner')) { $owner = User::find($request->get('owner')); - $query->where(function ($query) use ($owner) { - $query->where('user_id', $owner->id); - }); + if ($owner) { + $query->where(function ($query) use ($owner) { + $query->where('user_id', $owner->id); + }); + } } if ($request->get('owner_url')) { $ownerUrl = $request->get('owner_url'); @@ -385,15 +393,19 @@ public function getMyos(Request $request) { } if ($request->get('artist')) { $artist = User::find($request->get('artist')); - $imageQuery->whereHas('artists', function ($query) use ($artist) { - $query->where('user_id', $artist->id); - }); + if ($artist) { + $imageQuery->whereHas('artists', function ($query) use ($artist) { + $query->where('user_id', $artist->id); + }); + } } if ($request->get('designer')) { $designer = User::find($request->get('designer')); - $imageQuery->whereHas('designers', function ($query) use ($designer) { - $query->where('user_id', $designer->id); - }); + if ($designer) { + $imageQuery->whereHas('designers', function ($query) use ($designer) { + $query->where('user_id', $designer->id); + }); + } } if ($request->get('artist_url')) { $artistUrl = $request->get('artist_url'); @@ -442,7 +454,7 @@ public function getMyos(Request $request) { return view('browse.myo_masterlist', [ 'isMyo' => true, - 'slots' => $query->paginate(30)->appends($request->query()), + 'slots' => $query->paginate(24)->appends($request->query()), 'specieses' => [0 => 'Any Species'] + Species::visible(Auth::check() ? Auth::user() : null)->orderBy('specieses.sort', 'DESC')->pluck('name', 'id')->toArray(), 'rarities' => [0 => 'Any Rarity'] + Rarity::orderBy('rarities.sort', 'DESC')->pluck('name', 'id')->toArray(), 'features' => Feature::getDropdownItems(), @@ -459,8 +471,8 @@ public function getMyos(Request $request) { * @return \Illuminate\Contracts\Support\Renderable */ public function getSublist(Request $request, $key) { - $query = Character::with('user.rank')->with('image.features')->with('rarity')->with('image.species')->myo(0); - $imageQuery = CharacterImage::with('features')->with('rarity')->with('species')->with('features'); + $query = Character::with('user.rank', 'image.features', 'rarity', 'image.species', 'image.rarity')->myo(0); + $imageQuery = CharacterImage::with('features', 'rarity', 'species', 'features'); $sublist = Sublist::where('key', $key)->first(); if (!$sublist) { @@ -536,9 +548,11 @@ public function getSublist(Request $request, $key) { if ($request->get('owner')) { $owner = User::find($request->get('owner')); - $query->where(function ($query) use ($owner) { - $query->where('user_id', $owner->id); - }); + if ($owner) { + $query->where(function ($query) use ($owner) { + $query->where('user_id', $owner->id); + }); + } } if ($request->get('owner_url')) { $ownerUrl = $request->get('owner_url'); @@ -569,15 +583,19 @@ public function getSublist(Request $request, $key) { } if ($request->get('artist')) { $artist = User::find($request->get('artist')); - $imageQuery->whereHas('artists', function ($query) use ($artist) { - $query->where('user_id', $artist->id); - }); + if ($artist) { + $imageQuery->whereHas('artists', function ($query) use ($artist) { + $query->where('user_id', $artist->id); + }); + } } if ($request->get('designer')) { $designer = User::find($request->get('designer')); - $imageQuery->whereHas('designers', function ($query) use ($designer) { - $query->where('user_id', $designer->id); - }); + if ($designer) { + $imageQuery->whereHas('designers', function ($query) use ($designer) { + $query->where('user_id', $designer->id); + }); + } } if ($request->get('artist_url')) { $artistUrl = $request->get('artist_url'); diff --git a/app/Http/Controllers/Characters/CharacterController.php b/app/Http/Controllers/Characters/CharacterController.php index 74c090a080..cb43a1f4da 100644 --- a/app/Http/Controllers/Characters/CharacterController.php +++ b/app/Http/Controllers/Characters/CharacterController.php @@ -202,7 +202,7 @@ public function getCharacterGallery(Request $request, $slug) { return view('character.gallery', [ 'character' => $this->character, 'extPrevAndNextBtnsUrl' => '/gallery', - 'submissions' => GallerySubmission::whereIn('id', $this->character->gallerySubmissions->pluck('gallery_submission_id')->toArray())->visible()->accepted()->orderBy('created_at', 'DESC')->paginate(20)->appends($request->query()), + 'submissions' => GallerySubmission::whereIn('id', $this->character->gallerySubmissions->pluck('gallery_submission_id')->toArray())->visible(Auth::user() ?? null)->orderBy('created_at', 'DESC')->paginate(20), ]); } @@ -234,6 +234,7 @@ public function getCharacterInventory($slug) { $items = count($categories) ? $this->character->items() + ->with('category') ->where('count', '>', 0) ->orderByRaw('FIELD(item_category_id,'.implode(',', $categories->pluck('id')->toArray()).')') ->orderBy('name') @@ -241,6 +242,7 @@ public function getCharacterInventory($slug) { ->get() ->groupBy(['item_category_id', 'id']) : $this->character->items() + ->with('category') ->where('count', '>', 0) ->orderBy('name') ->orderBy('updated_at') @@ -254,11 +256,8 @@ public function getCharacterInventory($slug) { 'items' => $items, 'logs' => $this->character->getItemLogs(), ] + (Auth::check() && (Auth::user()->hasPower('edit_inventories') || Auth::user()->id == $this->character->user_id) ? [ - 'itemOptions' => $itemOptions->pluck('name', 'id'), - 'userInventory' => UserItem::with('item')->whereIn('item_id', $itemOptions->pluck('id'))->whereNull('deleted_at')->where('count', '>', '0')->where('user_id', Auth::user()->id)->get()->filter(function ($userItem) { - return $userItem->isTransferrable == true; - })->sortBy('item.name'), - 'page' => 'character', + 'itemOptions' => $itemOptions->pluck('name', 'id'), + 'page' => 'character', ] : [])); } diff --git a/app/Http/Controllers/GalleryController.php b/app/Http/Controllers/GalleryController.php index fcace01dc5..85fcd10593 100644 --- a/app/Http/Controllers/GalleryController.php +++ b/app/Http/Controllers/GalleryController.php @@ -4,7 +4,6 @@ use App\Facades\Settings; use App\Models\Character\Character; -use App\Models\Comment\Comment; use App\Models\Currency\Currency; use App\Models\Gallery\Gallery; use App\Models\Gallery\GallerySubmission; @@ -13,7 +12,7 @@ use App\Services\GalleryManager; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; -use View; +use Illuminate\Support\Facades\View; class GalleryController extends Controller { /* @@ -39,10 +38,13 @@ public function __construct() { * @return \Illuminate\Contracts\Support\Renderable */ public function getGalleryIndex() { + $galleries = Gallery::whereNull('parent_id')->active()->sort()->with('children', 'children.submissions', 'submissions')->withCount('submissions', 'children'); + return view('galleries.index', [ - 'galleries' => Gallery::sort()->active()->whereNull('parent_id')->paginate(10), - 'galleryPage' => false, - 'sideGallery' => null, + 'galleries' => $galleries->paginate(10), + 'galleryPage' => false, + 'sideGallery' => null, + 'submissionsOpen' => Settings::get('gallery_submissions_open'), ]); } @@ -54,12 +56,12 @@ public function getGalleryIndex() { * @return \Illuminate\Contracts\Support\Renderable */ public function getGallery($id, Request $request) { - $gallery = Gallery::visible()->where('id', $id)->first(); + $gallery = Gallery::visible()->where('id', $id)->withCount('submissions')->first(); if (!$gallery) { abort(404); } - $query = GallerySubmission::where('gallery_id', $gallery->id)->visible(Auth::check() ? Auth::user() : null)->accepted(); + $query = GallerySubmission::where('gallery_id', $gallery->id)->visible(Auth::check() ? Auth::user() : null); $sort = $request->only(['sort']); if ($request->get('title')) { @@ -99,8 +101,8 @@ public function getGallery($id, Request $request) { return view('galleries.gallery', [ 'gallery' => $gallery, 'submissions' => $query->paginate(20)->appends($request->query()), - 'prompts' => [0 => 'Any Prompt'] + Prompt::whereIn('id', GallerySubmission::where('gallery_id', $gallery->id)->visible(Auth::check() ? Auth::user() : null)->accepted()->whereNotNull('prompt_id')->pluck('prompt_id')->toArray())->orderBy('name')->pluck('name', 'id')->toArray(), - 'childSubmissions' => GallerySubmission::whereIn('gallery_id', $gallery->children->pluck('id')->toArray())->where('is_visible', 1)->where('status', 'Accepted'), + 'prompts' => [0 => 'Any Prompt'] + Prompt::whereIn('id', GallerySubmission::where('gallery_id', $gallery->id)->withOnly('prompt')->visible(Auth::user() ?? null)->whereNotNull('prompt_id')->select('prompt_id')->distinct()->pluck('prompt_id')->toArray())->orderBy('name')->pluck('name', 'id')->toArray(), + 'childSubmissions' => $gallery->through('children')->has('submissions')->where('is_visible', 1)->where('status', 'Accepted'), 'galleryPage' => true, 'sideGallery' => $gallery, ]); @@ -155,7 +157,7 @@ public function getAll(Request $request) { return view('galleries.showall', [ 'submissions' => $query->paginate(20)->appends($request->query()), - 'prompts' => [0 => 'Any Prompt'] + Prompt::whereIn('id', GallerySubmission::visible(Auth::check() ? Auth::user() : null)->accepted()->whereNotNull('prompt_id')->pluck('prompt_id')->toArray())->orderBy('name')->pluck('name', 'id')->toArray(), + 'prompts' => [0 => 'Any Prompt'] + Prompt::whereIn('id', GallerySubmission::visible(Auth::user() ?? null)->accepted()->withOnly('prompt')->whereNotNull('prompt_id')->pluck('prompt_id')->toArray())->orderBy('name')->pluck('name', 'id')->toArray(), 'galleryPage' => false, ]); } @@ -168,7 +170,7 @@ public function getAll(Request $request) { * @return \Illuminate\Contracts\Support\Renderable */ public function getSubmission($id) { - $submission = GallerySubmission::find($id); + $submission = GallerySubmission::where('id', $id)->with('gallery', 'participants', 'characters')->first(); if (!$submission) { abort(404); } @@ -187,7 +189,6 @@ public function getSubmission($id) { return view('galleries.submission', [ 'submission' => $submission, - 'commentCount' => Comment::where('commentable_type', 'App\Models\Gallery\GallerySubmission')->where('commentable_id', $submission->id)->where('type', 'User-User')->count(), 'galleryPage' => true, 'sideGallery' => $submission->gallery, ]); @@ -201,10 +202,12 @@ public function getSubmission($id) { * @return \Illuminate\Contracts\Support\Renderable */ public function getSubmissionFavorites($id) { - $submission = GallerySubmission::find($id); + $submission = GallerySubmission::where('id', $id)->withOnly('favorites')->first(); + $favorites = $submission->favorites()->with('user')->get(); return view('galleries._submission_favorites', [ 'submission' => $submission, + 'favorites' => $favorites, ]); } @@ -216,7 +219,7 @@ public function getSubmissionFavorites($id) { * @return \Illuminate\Contracts\Support\Renderable */ public function getSubmissionLog($id) { - $submission = GallerySubmission::find($id); + $submission = GallerySubmission::where('id', $id)->with('participants')->without('favorites', 'comments')->first(); if (!$submission) { abort(404); } @@ -242,12 +245,12 @@ public function getSubmissionLog($id) { /** * Shows the user's gallery submission log. * - * @param mixed $type + * @param string $type * * @return \Illuminate\Contracts\Support\Renderable */ public function getUserSubmissions(Request $request, $type) { - $submissions = GallerySubmission::userSubmissions(Auth::user()); + $submissions = GallerySubmission::userSubmissions(Auth::user())->with('gallery')->without('favorites', 'comments'); if (!$type) { $type = 'Pending'; } @@ -300,8 +303,8 @@ public function getEditGallerySubmission($id) { if (!Auth::check()) { abort(404); } - $submission = GallerySubmission::find($id); - if (!$submission) { + $submission = GallerySubmission::where('id', $id)->with('gallery')->with('participants', 'characters')->without('comments', 'favorites')->first(); + if (!$submission || $submission->status == 'Rejected') { abort(404); } $isMod = Auth::user()->hasPower('manage_submissions'); diff --git a/app/Http/Controllers/PermalinkController.php b/app/Http/Controllers/PermalinkController.php index 02dfb9de79..f27c7bc36a 100644 --- a/app/Http/Controllers/PermalinkController.php +++ b/app/Http/Controllers/PermalinkController.php @@ -16,7 +16,7 @@ class PermalinkController extends Controller { * @return \Illuminate\Contracts\Support\Renderable */ public function getComment($id) { - $comments = Comment::withTrashed()->get(); + $comments = Comment::withTrashed(); //$comments = $comments->sortByDesc('created_at'); $comment = $comments->find($id); diff --git a/app/Http/Controllers/Users/UserController.php b/app/Http/Controllers/Users/UserController.php index 4077f7c17f..6aa87bc3ff 100644 --- a/app/Http/Controllers/Users/UserController.php +++ b/app/Http/Controllers/Users/UserController.php @@ -313,7 +313,7 @@ public function getUserSubmissions($name) { public function getUserGallery(Request $request, $name) { return view('user.gallery', [ 'user' => $this->user, - 'submissions' => $this->user->gallerySubmissions()->paginate(20)->appends($request->query()), + 'submissions' => $this->user->gallerySubmissions()->visible(Auth::user() ?? null)->paginate(20)->appends($request->query()), ]); } @@ -328,7 +328,7 @@ public function getUserFavorites(Request $request, $name) { return view('user.favorites', [ 'user' => $this->user, 'characters' => false, - 'favorites' => GallerySubmission::whereIn('id', $this->user->galleryFavorites()->pluck('gallery_submission_id')->toArray())->visible(Auth::check() ? Auth::user() : null)->accepted()->orderBy('created_at', 'DESC')->paginate(20)->appends($request->query()), + 'favorites' => GallerySubmission::whereIn('id', $this->user->galleryFavorites()->pluck('gallery_submission_id')->toArray())->visible(Auth::check() ? Auth::user() : null)->orderBy('created_at', 'DESC')->paginate(20)->appends($request->query()), ]); } @@ -347,7 +347,7 @@ public function getUserOwnCharacterFavorites(Request $request, $name) { return view('user.favorites', [ 'user' => $this->user, 'characters' => true, - 'favorites' => $this->user->characters->count() ? GallerySubmission::whereIn('id', $userFavorites)->whereIn('id', GalleryCharacter::whereIn('character_id', $userCharacters)->pluck('gallery_submission_id')->toArray())->visible(Auth::check() ? Auth::user() : null)->accepted()->orderBy('created_at', 'DESC')->paginate(20)->appends($request->query()) : null, + 'favorites' => $this->user->characters->count() ? GallerySubmission::whereIn('id', $userFavorites)->whereIn('id', GalleryCharacter::whereIn('character_id', $userCharacters)->pluck('gallery_submission_id')->toArray())->visible(Auth::check() ? Auth::user() : null)->orderBy('created_at', 'DESC')->paginate(20)->appends($request->query()) : null, ]); } } diff --git a/app/Http/Controllers/WorldController.php b/app/Http/Controllers/WorldController.php index 8968a6b3bc..52b47eeee4 100644 --- a/app/Http/Controllers/WorldController.php +++ b/app/Http/Controllers/WorldController.php @@ -10,7 +10,6 @@ use App\Models\Item\ItemCategory; use App\Models\Rarity; use App\Models\Shop\Shop; -use App\Models\Shop\ShopStock; use App\Models\Species\Species; use App\Models\Species\Subtype; use App\Models\User\User; @@ -78,6 +77,11 @@ public function getRarities(Request $request) { */ public function getSpecieses(Request $request) { $query = Species::query(); + + if (config('lorekeeper.extensions.species_trait_index.enable')) { + $query->withCount('features'); + } + $name = $request->get('name'); if ($name) { $query->where('name', 'LIKE', '%'.$name.'%'); @@ -96,14 +100,14 @@ public function getSpecieses(Request $request) { * @return \Illuminate\Contracts\Support\Renderable */ public function getSubtypes(Request $request) { - $query = Subtype::query(); + $query = Subtype::query()->with('species'); $name = $request->get('name'); if ($name) { $query->where('name', 'LIKE', '%'.$name.'%'); } return view('world.subtypes', [ - 'subtypes' => $query->with('species')->visible(Auth::check() ? Auth::user() : null)->orderBy('sort', 'DESC')->orderBy('id')->paginate(20)->appends($request->query()), + 'subtypes' => $query->visible(Auth::check() ? Auth::user() : null)->orderBy('sort', 'DESC')->orderBy('id')->paginate(20)->appends($request->query()), ]); } @@ -147,8 +151,10 @@ public function getFeatureCategories(Request $request) { * @return \Illuminate\Contracts\Support\Renderable */ public function getFeatures(Request $request) { - $query = Feature::visible(Auth::check() ? Auth::user() : null)->with('category')->with('rarity')->with('species'); + $query = Feature::visible(Auth::check() ? Auth::user() : null)->with('category', 'rarity', 'species', 'subtype'); + $data = $request->only(['rarity_id', 'feature_category_id', 'species_id', 'subtype_id', 'name', 'sort']); + if (isset($data['rarity_id']) && $data['rarity_id'] != 'none') { $query->where('rarity_id', $data['rarity_id']); } @@ -230,6 +236,7 @@ public function getFeatures(Request $request) { public function getSpeciesFeatures($id) { $categories = FeatureCategory::orderBy('sort', 'DESC')->get(); $rarities = Rarity::orderBy('sort', 'ASC')->get(); + $species = Species::visible(Auth::check() ? Auth::user() : null)->where('id', $id)->first(); if (!$species) { abort(404); @@ -241,6 +248,7 @@ public function getSpeciesFeatures($id) { $features = count($categories) ? $species->features() ->visible(Auth::check() ? Auth::user() : null) + ->with('rarity', 'subtype') ->orderByRaw('FIELD(feature_category_id,'.implode(',', $categories->pluck('id')->toArray()).')') ->orderByRaw('FIELD(rarity_id,'.implode(',', $rarities->pluck('id')->toArray()).')') ->orderBy('has_image', 'DESC') @@ -256,6 +264,7 @@ public function getSpeciesFeatures($id) { ->groupBy(['feature_category_id', 'id']) : $species->features() ->visible(Auth::check() ? Auth::user() : null) + ->with('rarity', 'subtype') ->orderByRaw('FIELD(rarity_id,'.implode(',', $rarities->pluck('id')->toArray()).')') ->orderBy('has_image', 'DESC') ->orderBy('name') @@ -286,7 +295,7 @@ public function getSpeciesFeatures($id) { * @return \Illuminate\Contracts\Support\Renderable */ public function getSpeciesFeatureDetail($speciesId, $id) { - $feature = Feature::where('id', $id)->first(); + $feature = Feature::where('id', $id)->with('species', 'subtype', 'rarity')->first(); if (!$feature) { abort(404); @@ -308,6 +317,10 @@ public function getSpeciesFeatureDetail($speciesId, $id) { public function getItems(Request $request) { $query = Item::with('category')->released(Auth::user() ?? null); + if (config('lorekeeper.extensions.item_entry_expansion.extra_fields')) { + $query->with('artist', 'shopStock')->withCount('shopStock'); + } + $categoryVisibleCheck = ItemCategory::visible(Auth::check() ? Auth::user() : null)->pluck('id', 'name')->toArray(); // query where category is visible, or, no category and released $query->where(function ($query) use ($categoryVisibleCheck) { @@ -366,9 +379,13 @@ public function getItems(Request $request) { * @return \Illuminate\Contracts\Support\Renderable */ public function getItem($id) { - $categories = ItemCategory::orderBy('sort', 'DESC')->get(); + $item = Item::where('id', $id)->released(Auth::user() ?? null)->with('category'); - $item = Item::where('id', $id)->released(Auth::user() ?? null)->first(); + if (config('lorekeeper.extensions.item_entry_expansion.extra_fields')) { + $item->with('artist', 'shopStock')->withCount('shopStock'); + } + + $item = $item->first(); if (!$item) { abort(404); @@ -384,8 +401,6 @@ public function getItem($id) { 'imageUrl' => $item->imageUrl, 'name' => $item->displayName, 'description' => $item->parsed_description, - 'categories' => $categories->keyBy('id'), - 'shops' => Shop::whereIn('id', ShopStock::where('item_id', $item->id)->pluck('shop_id')->unique()->toArray())->orderBy('sort', 'DESC')->get(), ]); } @@ -395,7 +410,8 @@ public function getItem($id) { * @return \Illuminate\Contracts\Support\Renderable */ public function getCharacterCategories(Request $request) { - $query = CharacterCategory::query(); + $query = CharacterCategory::query()->with('sublist'); + $name = $request->get('name'); if ($name) { $query->where('name', 'LIKE', '%'.$name.'%')->orWhere('code', 'LIKE', '%'.$name.'%'); diff --git a/app/Http/Middleware/ParsePostRequestFields.php b/app/Http/Middleware/ParsePostRequestFields.php index e8f6774c46..8f64ed8a8d 100644 --- a/app/Http/Middleware/ParsePostRequestFields.php +++ b/app/Http/Middleware/ParsePostRequestFields.php @@ -15,7 +15,7 @@ class ParsePostRequestFields { */ public function handle(Request $request, Closure $next) { if ($request->isMethod('post')) { - $excludedFields = ['_token', 'password', 'email', 'description', 'text']; + $excludedFields = ['_token', 'password', 'email', 'description', 'text', 'criteria']; $strippedFields = ['name', 'title']; $parsedFields = []; @@ -32,6 +32,11 @@ public function handle(Request $request, Closure $next) { } else { $parsedFields[$key] = parse($value); } + + // Decode HTML special chars + if ($parsedFields[$key] != null) { + $parsedFields[$key] = htmlspecialchars_decode($parsedFields[$key]); + } } } @@ -58,6 +63,11 @@ private function parseArray(array $array, array $strippedFields): array { } else { $array[$key] = parse($value); } + + // Decode HTML special chars + if ($array[$key] != null) { + $array[$key] = htmlspecialchars_decode($array[$key]); + } } } diff --git a/app/Models/Character/Character.php b/app/Models/Character/Character.php index 19352a8ea6..e5e866b2ad 100644 --- a/app/Models/Character/Character.php +++ b/app/Models/Character/Character.php @@ -77,9 +77,9 @@ class Character extends Model { 'number' => 'required', 'slug' => 'required|alpha_dash', 'description' => 'nullable', - 'sale_value' => 'nullable', - 'image' => 'required|mimes:jpeg,jpg,gif,png|max:20000', - 'thumbnail' => 'nullable|mimes:jpeg,jpg,gif,png|max:20000', + 'sale_value' => 'nullable|decimal:0,2', + 'image' => 'required|mimes:jpeg,jpg,gif,png|max:2048', + 'thumbnail' => 'nullable|mimes:jpeg,jpg,gif,png|max:2048', 'owner_url' => 'url|nullable', ]; @@ -93,7 +93,9 @@ class Character extends Model { 'number' => 'required', 'slug' => 'required', 'description' => 'nullable', - 'sale_value' => 'nullable', + 'sale_value' => 'nullable|decimal:0,2', + 'image' => 'nullable|mimes:jpeg,jpg,gif,png|max:2048', + 'thumbnail' => 'nullable|mimes:jpeg,jpg,gif,png|max:2048', ]; /** @@ -107,10 +109,10 @@ class Character extends Model { 'number' => 'nullable', 'slug' => 'nullable', 'description' => 'nullable', - 'sale_value' => 'nullable', + 'sale_value' => 'nullable|decimal:0,2', 'name' => 'required', - 'image' => 'nullable|mimes:jpeg,gif,png|max:20000', - 'thumbnail' => 'nullable|mimes:jpeg,gif,png|max:20000', + 'image' => 'nullable|mimes:jpeg,gif,png|max:2048', + 'thumbnail' => 'nullable|mimes:jpeg,gif,png|max:2048', ]; /********************************************************************************************** @@ -188,7 +190,7 @@ public function gallerySubmissions() { * Get the character's items. */ public function items() { - return $this->belongsToMany(Item::class, 'character_items')->withPivot('count', 'data', 'updated_at', 'id')->whereNull('character_items.deleted_at'); + return $this->belongsToMany(Item::class, 'character_items')->withPivot('count', 'data', 'updated_at', 'id', 'stack_name')->whereNull('character_items.deleted_at'); } /********************************************************************************************** diff --git a/app/Models/Character/CharacterDesignUpdate.php b/app/Models/Character/CharacterDesignUpdate.php index 93bd15bbe5..386703ff79 100644 --- a/app/Models/Character/CharacterDesignUpdate.php +++ b/app/Models/Character/CharacterDesignUpdate.php @@ -302,7 +302,13 @@ public function getImageUrlAttribute() { * @return string */ public function getThumbnailFileNameAttribute() { - return $this->id.'_'.$this->hash.'_th.'.$this->extension; + if (config('lorekeeper.settings.masterlist_image_format') != null && config('lorekeeper.settings.masterlist_image_format') != $this->extension) { + $extension = config('lorekeeper.settings.masterlist_image_format'); + } else { + $extension = $this->extension; + } + + return $this->id.'_'.$this->hash.'_th.'.$extension; } /** diff --git a/app/Models/Character/CharacterImage.php b/app/Models/Character/CharacterImage.php index 84b6fc36ae..ad39130a78 100644 --- a/app/Models/Character/CharacterImage.php +++ b/app/Models/Character/CharacterImage.php @@ -47,8 +47,8 @@ class CharacterImage extends Model { public static $createRules = [ 'species_id' => 'required', 'rarity_id' => 'required', - 'image' => 'required|mimes:jpeg,jpg,gif,png,webp|max:20000', - 'thumbnail' => 'nullable|mimes:jpeg,jpg,gif,png,webp|max:20000', + 'image' => 'required|mimes:jpeg,jpg,gif,png,webp|max:2048', + 'thumbnail' => 'nullable|mimes:jpeg,jpg,gif,png,webp|max:2048', ]; /** @@ -62,6 +62,8 @@ class CharacterImage extends Model { 'species_id' => 'required', 'rarity_id' => 'required', 'description' => 'nullable', + 'image' => 'mimes:jpeg,jpg,gif,png,webp|max:2048', + 'thumbnail' => 'nullable|mimes:jpeg,jpg,gif,png,webp|max:2048', ]; /********************************************************************************************** @@ -225,7 +227,7 @@ public function getFullsizeUrlAttribute() { /** * Gets the file name of the model's fullsize image. * - * @param user + * @param User * @param mixed|null $user * * @return string diff --git a/app/Models/Gallery/Gallery.php b/app/Models/Gallery/Gallery.php index bb1207eab1..7390bcccb5 100644 --- a/app/Models/Gallery/Gallery.php +++ b/app/Models/Gallery/Gallery.php @@ -2,7 +2,6 @@ namespace App\Models\Gallery; -use App\Facades\Settings; use App\Models\Model; use Carbon\Carbon; @@ -202,12 +201,13 @@ public function getAdminPowerAttribute() { /** * Gets whether or not the user can submit to the gallery. * + * @param bool $submissionsOpen * @param mixed|null $user * * @return string */ - public function canSubmit($user = null) { - if (Settings::get('gallery_submissions_open')) { + public function canSubmit($submissionsOpen, $user = null) { + if ($submissionsOpen) { if ((isset($this->start_at) && $this->start_at->isFuture()) || (isset($this->end_at) && $this->end_at->isPast())) { return false; } elseif ($user && $user->hasPower('manage_submissions')) { diff --git a/app/Models/Gallery/GalleryCollaborator.php b/app/Models/Gallery/GalleryCollaborator.php index 6007773a97..5a997e3f30 100644 --- a/app/Models/Gallery/GalleryCollaborator.php +++ b/app/Models/Gallery/GalleryCollaborator.php @@ -25,6 +25,15 @@ class GalleryCollaborator extends Model { */ protected $table = 'gallery_submission_collaborators'; + /** + * The relationships that should always be loaded. + * + * @var array + */ + protected $with = [ + 'user', + ]; + /********************************************************************************************** RELATIONS diff --git a/app/Models/Gallery/GallerySubmission.php b/app/Models/Gallery/GallerySubmission.php index 8607b7e93e..a9ab154304 100644 --- a/app/Models/Gallery/GallerySubmission.php +++ b/app/Models/Gallery/GallerySubmission.php @@ -3,6 +3,7 @@ namespace App\Models\Gallery; use App\Facades\Settings; +use App\Models\Comment\Comment; use App\Models\Currency\Currency; use App\Models\Model; use App\Models\Prompt\Prompt; @@ -34,6 +35,24 @@ class GallerySubmission extends Model { */ protected $table = 'gallery_submissions'; + /** + * The relationships that should always be loaded. + * + * @var array + */ + protected $with = [ + 'user', 'collaborators', 'prompt:id,name,prefix', 'favorites', 'comments:id,commentable_type,commentable_id,type', + ]; + + /** + * The relationship counts that should be eager loaded on every query. + * + * @var array + */ + protected $withCount = [ + 'favorites', + ]; + /** * Whether the model contains timestamps to be saved and updated. * @@ -74,7 +93,7 @@ class GallerySubmission extends Model { * Get the user who made the submission. */ public function user() { - return $this->belongsTo(User::class, 'user_id'); + return $this->belongsTo(User::class); } /** @@ -88,42 +107,49 @@ public function staff() { * Get the collaborating users on the submission. */ public function collaborators() { - return $this->hasMany(GalleryCollaborator::class, 'gallery_submission_id')->where('type', 'Collab'); + return $this->hasMany(GalleryCollaborator::class)->where('type', 'Collab'); } /** * Get the user(s) who are related to the submission in some way. */ public function participants() { - return $this->hasMany(GalleryCollaborator::class, 'gallery_submission_id')->where('type', '!=', 'Collab'); + return $this->hasMany(GalleryCollaborator::class)->where('type', '!=', 'Collab'); } /** * Get the characters associated with the submission. */ public function characters() { - return $this->hasMany(GalleryCharacter::class, 'gallery_submission_id'); + return $this->hasMany(GalleryCharacter::class); } /** * Get any favorites on the submission. */ public function favorites() { - return $this->hasMany(GalleryFavorite::class, 'gallery_submission_id'); + return $this->hasMany(GalleryFavorite::class); } /** * Get the gallery this submission is in. */ public function gallery() { - return $this->belongsTo(Gallery::class, 'gallery_id'); + return $this->belongsTo(Gallery::class); } /** * Get the prompt this submission is for if relevant. */ public function prompt() { - return $this->belongsTo(Prompt::class, 'prompt_id'); + return $this->belongsTo(Prompt::class); + } + + /** + * Get comments made on this submission. + */ + public function comments() { + return $this->morphMany(Comment::class, 'commentable'); } /********************************************************************************************** @@ -151,7 +177,9 @@ public function scopePending($query) { * @return \Illuminate\Database\Eloquent\Builder */ public function scopeCollaboratorApproved($query) { - return $query->whereNotIn('id', GalleryCollaborator::where('has_approved', 0)->pluck('gallery_submission_id')->toArray()); + return $query->whereDoesntHave('collaborators', function ($query) { + $query->where('has_approved', 0); + })->orWhereDoesntHave('collaborators'); } /** @@ -200,7 +228,9 @@ public function scopeRequiresAward($query) { * @return \Illuminate\Database\Eloquent\Builder */ public function scopeUserSubmissions($query, $user) { - return $query->where('user_id', $user->id)->orWhereIn('id', GalleryCollaborator::where('user_id', $user->id)->where('type', 'Collab')->pluck('gallery_submission_id')->toArray()); + return $query->where('user_id', $user->id)->orWhereHas('collaborators', function ($query) use ($user) { + $query->where('user_id', $user->id)->where('type', 'Collab'); + }); } /** @@ -327,15 +357,6 @@ public function getDataAttribute() { return json_decode($this->attributes['data'], true); } - /** - * Gets the voting data of the gallery submission. - * - * @return string - */ - public function getVoteDataAttribute() { - return collect(json_decode($this->attributes['vote_data'], true)); - } - /** * Get the title of the submission, with prefix. * @@ -364,13 +385,11 @@ public function getUrlAttribute() { } /** - * Checks if all of a submission's collaborators have approved or no. + * Get the prefix for a submission. * * @return string */ public function getPrefixAttribute() { - $currencyName = Currency::find(Settings::get('group_currency'))->abbreviation ? Currency::find(Settings::get('group_currency'))->abbreviation : Currency::find(Settings::get('group_currency'))->name; - $prefixList = []; if ($this->promptSubmissions->count()) { foreach ($this->prompts as $prompt) { @@ -394,6 +413,8 @@ public function getPrefixAttribute() { $prefixList[] = 'Comm'; break; case 'Comm (Currency)': + $currencyName = Currency::find(Settings::get('group_currency'))->abbreviation ? Currency::find(Settings::get('group_currency'))->abbreviation : Currency::find(Settings::get('group_currency'))->name; + $prefixList[] = 'Comm ('.$currencyName.')'; break; } @@ -432,7 +453,7 @@ public function getIsVisibleAttribute() { */ public function getCreditsAttribute() { if ($this->collaborators->count()) { - foreach ($this->collaborators as $count=> $collaborator) { + foreach ($this->collaborators as $collaborator) { $collaboratorList[] = $collaborator->user->displayName; } @@ -449,7 +470,7 @@ public function getCreditsAttribute() { */ public function getCreditsPlainAttribute() { if ($this->collaborators->count()) { - foreach ($this->collaborators as $count=> $collaborator) { + foreach ($this->collaborators as $collaborator) { $collaboratorList[] = $collaborator->user->name; } @@ -464,7 +485,7 @@ public function getCreditsPlainAttribute() { * * @return string */ - public function getCollaboratorApprovedAttribute() { + public function getCollaboratorApprovalAttribute() { if ($this->collaborators->where('has_approved', 0)->count()) { return false; } @@ -480,7 +501,7 @@ public function getCollaboratorApprovedAttribute() { public function getPromptSubmissionsAttribute() { // Only returns submissions which are viewable to everyone, // but given that this is for the sake of public display, that's fine - return Submission::viewable()->whereNotNull('prompt_id')->where('url', $this->url)->get(); + return Submission::viewable()->whereNotNull('prompt_id')->where('url', 'like', '%'.request()->getHost().'/gallery/view/'.$this->id)->get(); } /** @@ -506,4 +527,50 @@ public function getExcerptAttribute() { return strip_tags(substr($this->parsed_text, 0, 500)).(strlen($this->parsed_text) > 500 ? '...' : ''); } } + + /********************************************************************************************** + + OTHER FUNCTIONS + + **********************************************************************************************/ + + /** + * Gets the voting data of the gallery submission and performs preliminary processing. + * + * @param bool $withUsers + * + * @return array + */ + public function getVoteData($withUsers = 0) { + $voteData['raw'] = json_decode($this->attributes['vote_data'], true); + + // Only query users if necessary, and condense to one query per submission + if ($withUsers) { + $users = User::whereIn('id', array_keys($voteData['raw']))->select('id', 'name', 'rank_id')->get(); + } else { + $users = null; + } + + $voteData['raw'] = collect($voteData['raw'])->mapWithKeys(function ($vote, $id) use ($users) { + return [$id => [ + 'vote' => $vote, + 'user' => $users ? $users->where('id', $id)->first() : $id, + ]]; + }); + + // Tally approve/reject sums for ease + $voteData['approve'] = $voteData['reject'] = 0; + foreach ($voteData['raw'] as $vote) { + switch ($vote['vote']) { + case 1: + $voteData['reject'] += 1; + break; + case 2: + $voteData['approve'] += 1; + break; + } + } + + return $voteData; + } } diff --git a/app/Models/Item/Item.php b/app/Models/Item/Item.php index d2f9d13148..fab8a78f24 100644 --- a/app/Models/Item/Item.php +++ b/app/Models/Item/Item.php @@ -5,6 +5,7 @@ use App\Models\Model; use App\Models\Prompt\Prompt; use App\Models\Shop\Shop; +use App\Models\Shop\ShopStock; use App\Models\User\User; class Item extends Model { @@ -26,6 +27,16 @@ class Item extends Model { * @var string */ protected $table = 'items'; + + /** + * The relationships that should always be loaded. + * + * @var array + */ + protected $with = [ + 'tags', + ]; + /** * Validation rules for creation. * @@ -86,6 +97,13 @@ public function artist() { return $this->belongsTo(User::class, 'artist_id'); } + /** + * Get shop stock for this item. + */ + public function shopStock() { + return $this->hasMany(ShopStock::class, 'item_id'); + } + /********************************************************************************************** SCOPES @@ -343,17 +361,18 @@ public function getResellAttribute() { } /** - * Get the shops attribute as an associative array. + * Get the shops that stock this item. * - * @return array + * @return \Illuminate\Database\Eloquent\Collection */ public function getShopsAttribute() { - if (!$this->data) { + if (!config('lorekeeper.extensions.item_entry_expansion.extra_fields') || !$this->shop_stock_count) { return null; } - $itemShops = $this->data['shops']; - return Shop::whereIn('id', $itemShops)->get(); + $shops = Shop::whereIn('id', $this->shopStock->pluck('shop_id')->toArray())->orderBy('sort', 'DESC')->get(); + + return $shops; } /** @@ -367,7 +386,11 @@ public function getPromptsAttribute() { } $itemPrompts = $this->data['prompts']; - return Prompt::whereIn('id', $itemPrompts)->get(); + if (count($itemPrompts)) { + return Prompt::whereIn('id', $itemPrompts)->get(); + } else { + return null; + } } /** diff --git a/app/Models/News.php b/app/Models/News.php index 770ba85eec..669a96dab5 100644 --- a/app/Models/News.php +++ b/app/Models/News.php @@ -152,7 +152,7 @@ public function getAdminUrlAttribute() { * @return string */ public function getAdminPowerAttribute() { - return 'edit_pages'; + return 'manage_news'; } /********************************************************************************************** diff --git a/app/Models/Prompt/Prompt.php b/app/Models/Prompt/Prompt.php index bd78af27ef..afb2cb68df 100644 --- a/app/Models/Prompt/Prompt.php +++ b/app/Models/Prompt/Prompt.php @@ -237,7 +237,7 @@ public function scopeSortEnd($query, $reverse = false) { * @return string */ public function getDisplayNameAttribute() { - return ''.$this->name.''; + return ''.$this->name.''; } /** @@ -289,6 +289,15 @@ public function getUrlAttribute() { return url('prompts/prompts?name='.$this->name); } + /** + * Gets the URL of the individual prompt's page, by ID. + * + * @return string + */ + public function getIdUrlAttribute() { + return url('prompts/'.$this->id); + } + /** * Gets the prompt's asset type for asset management. * diff --git a/app/Models/Sales/Sales.php b/app/Models/Sales/Sales.php index 3655337ae3..8c8b183bf3 100644 --- a/app/Models/Sales/Sales.php +++ b/app/Models/Sales/Sales.php @@ -208,7 +208,7 @@ public function getAdminUrlAttribute() { * @return string */ public function getAdminPowerAttribute() { - return 'edit_pages'; + return 'manage_sales'; } /********************************************************************************************** diff --git a/app/Models/Shop/Shop.php b/app/Models/Shop/Shop.php index 4f1b9457fc..b0ba66f982 100644 --- a/app/Models/Shop/Shop.php +++ b/app/Models/Shop/Shop.php @@ -27,7 +27,7 @@ class Shop extends Model { * @var array */ public static $createRules = [ - 'name' => 'required|unique:item_categories|between:3,100', + 'name' => 'required|unique:shops|between:3,100', 'description' => 'nullable', 'image' => 'mimes:png', ]; diff --git a/app/Models/Species/Subtype.php b/app/Models/Species/Subtype.php index 51fadd4e6c..a207153f31 100644 --- a/app/Models/Species/Subtype.php +++ b/app/Models/Species/Subtype.php @@ -29,6 +29,7 @@ class Subtype extends Model { protected $appends = [ 'name_with_species', ]; + /** * Validation rules for creation. * diff --git a/app/Models/User/User.php b/app/Models/User/User.php index 4e1d4acb29..d6a51a024f 100644 --- a/app/Models/User/User.php +++ b/app/Models/User/User.php @@ -67,6 +67,15 @@ class User extends Authenticatable implements MustVerifyEmail { 'verified_name', ]; + /** + * The relationships that should always be loaded. + * + * @var array + */ + protected $with = [ + 'rank', + ]; + /** * Whether the model contains timestamps to be saved and updated. * @@ -168,7 +177,7 @@ public function items() { * Get the user's logged IPs. */ public function ips() { - return $this->hasMany('App\Models\User\UserIp', 'user_id'); + return $this->hasMany(UserIp::class, 'user_id'); } /** @@ -177,8 +186,9 @@ public function ips() { public function gallerySubmissions() { return $this->hasMany(GallerySubmission::class) ->where('user_id', $this->id) - ->orWhereIn('id', GalleryCollaborator::where('user_id', $this->id)->where('type', 'Collab')->pluck('gallery_submission_id')->toArray()) - ->visible($this)->accepted()->orderBy('created_at', 'DESC'); + ->orWhereIn('id', GalleryCollaborator::where('user_id', $this->id) + ->where('type', 'Collab')->pluck('gallery_submission_id')->toArray()) + ->orderBy('created_at', 'DESC'); } /** @@ -373,7 +383,7 @@ public function getDisplayAliasAttribute() { return '(Unverified)'; } - return $this->primaryAlias->displayAlias; + return $this->primaryAlias?->displayAlias ?? '(No Alias)'; } /** diff --git a/app/Services/CharacterManager.php b/app/Services/CharacterManager.php index ada197d45b..f1215a30a2 100644 --- a/app/Services/CharacterManager.php +++ b/app/Services/CharacterManager.php @@ -243,7 +243,7 @@ public function processImage($characterImage) { } // Save the processed image - $image->save($characterImage->imagePath.'/'.$characterImage->fullsizeFileName, 100, config('lorekeeper.settings.masterlist_fullsizes_format')); + $image->save($characterImage->imagePath.'/'.$characterImage->fullsizeFileName, 100, config('lorekeeper.settings.masterlist_fullsizes_format') != null ? config('lorekeeper.settings.masterlist_fullsizes_format') : $characterImage->fullsize_extension); } else { // Delete fullsize if it was previously created. if (isset($characterImage->fullsize_hash) ? file_exists(public_path($characterImage->imageDirectory.'/'.$characterImage->fullsizeFileName)) : false) { @@ -255,7 +255,7 @@ public function processImage($characterImage) { if (config('lorekeeper.settings.masterlist_image_dimension') != 0) { if ($image->width() > $image->height()) { // Landscape - if (config('lorekeeper.settings.masterlist_image_dimension_target') == 'short') { + if (config('lorekeeper.settings.masterlist_image_dimension_target') == 'shorter') { $image->resize(null, config('lorekeeper.settings.masterlist_image_dimension'), function ($constraint) { $constraint->aspectRatio(); $constraint->upsize(); @@ -268,7 +268,7 @@ public function processImage($characterImage) { } } else { // Portrait - if (config('lorekeeper.settings.masterlist_image_dimension_target') == 'short') { + if (config('lorekeeper.settings.masterlist_image_dimension_target') == 'shorter') { $image->resize(config('lorekeeper.settings.masterlist_image_dimension'), null, function ($constraint) { $constraint->aspectRatio(); $constraint->upsize(); @@ -625,6 +625,15 @@ public function updateImageFeatures($data, $image, $user) { } } + //Check that species & rarity are selected + if (!(isset($data['species_id']) && $data['species_id'])) { + throw new \Exception('Characters require a species.'); + } + + if (!(isset($data['rarity_id']) && $data['rarity_id'])) { + throw new \Exception('Characters require a rarity.'); + } + if (!$this->logAdminAction($user, 'Updated Image', 'Updated character image features on #'.$image->id.'')) { throw new \Exception('Failed to log admin action.'); } @@ -1126,7 +1135,7 @@ public function updateCharacterStats($data, $character, $user) { $old['number'] = $character->number; $new['number'] = $characterData['number']; } - if ($characterData['slug'] != $character->number) { + if ($characterData['slug'] != $character->slug) { $result[] = 'character code'; $old['slug'] = $character->slug; $new['slug'] = $characterData['slug']; @@ -1523,7 +1532,7 @@ public function adminTransfer($data, $character, $user) { if ($sender) { Notifications::create('CHARACTER_SENT', $sender, [ 'character_name' => $character->slug, - 'character_slug' => $character->slug, + 'character_url' => $character->is_myo_slot ? 'myo/'.$character->id : 'character/'.$character->slug, 'sender_name' => $user->name, 'sender_url' => $user->url, 'recipient_name' => is_object($recipient) ? $recipient->name : prettyProfileName($recipient), @@ -1533,7 +1542,7 @@ public function adminTransfer($data, $character, $user) { if (is_object($recipient)) { Notifications::create('CHARACTER_RECEIVED', $recipient, [ 'character_name' => $character->slug, - 'character_slug' => $character->slug, + 'character_url' => $character->is_myo_slot ? 'myo/'.$character->id : 'character/'.$character->slug, 'sender_name' => $user->name, 'sender_url' => $user->url, ]); diff --git a/app/Services/DesignUpdateManager.php b/app/Services/DesignUpdateManager.php index e418ab87fc..b9e87732a3 100644 --- a/app/Services/DesignUpdateManager.php +++ b/app/Services/DesignUpdateManager.php @@ -157,7 +157,17 @@ public function saveRequestImage($data, $request, $isAdmin = false) { $imageData['use_cropper'] = isset($data['use_cropper']); } if (!$isAdmin && isset($data['image'])) { - $imageData['extension'] = (config('lorekeeper.settings.masterlist_image_format') ? config('lorekeeper.settings.masterlist_image_format') : ($data['extension'] ?? $data['image']->getClientOriginalExtension())); + if (config('lorekeeper.settings.store_masterlist_fullsizes')) { + if (config('lorekeeper.settings.masterlist_fullsizes_format') != null) { + $imageData['extension'] = config('lorekeeper.settings.masterlist_fullsizes_format'); + } else { + $imageData['extension'] = $data['image']->getClientOriginalExtension(); + } + } elseif (config('lorekeeper.settings.masterlist_image_format') != null) { + $imageData['extension'] = config('lorekeeper.settings.masterlist_image_format'); + } else { + $imageData['extension'] = $data['image']->getClientOriginalExtension(); + } $imageData['has_image'] = true; } $request->update($imageData); @@ -550,24 +560,23 @@ public function approveRequest($data, $request, $user) { } } - $extension = config('lorekeeper.settings.masterlist_image_format') != null ? config('lorekeeper.settings.masterlist_image_format') : $request->extension; - // Create a new image with the request data $image = CharacterImage::create([ - 'character_id' => $request->character_id, - 'is_visible' => 1, - 'hash' => $request->hash, - 'fullsize_hash' => $request->fullsize_hash ? $request->fullsize_hash : randomString(15), - 'extension' => $extension, - 'use_cropper' => $request->use_cropper, - 'x0' => $request->x0, - 'x1' => $request->x1, - 'y0' => $request->y0, - 'y1' => $request->y1, - 'species_id' => $request->species_id, - 'subtype_id' => ($request->character->is_myo_slot && isset($request->character->image->subtype_id)) ? $request->character->image->subtype_id : $request->subtype_id, - 'rarity_id' => $request->rarity_id, - 'sort' => 0, + 'character_id' => $request->character_id, + 'is_visible' => 1, + 'hash' => $request->hash, + 'fullsize_hash' => $request->fullsize_hash ? $request->fullsize_hash : randomString(15), + 'extension' => config('lorekeeper.settings.masterlist_image_format') != null ? config('lorekeeper.settings.masterlist_image_format') : $request->extension, + 'fullsize_extension' => config('lorekeeper.settings.masterlist_fullsizes_format') != null ? config('lorekeeper.settings.masterlist_fullsizes_format') : $request->extension, + 'use_cropper' => $request->use_cropper, + 'x0' => $request->x0, + 'x1' => $request->x1, + 'y0' => $request->y0, + 'y1' => $request->y1, + 'species_id' => $request->species_id, + 'subtype_id' => ($request->character->is_myo_slot && isset($request->character->image->subtype_id)) ? $request->character->image->subtype_id : $request->subtype_id, + 'rarity_id' => $request->rarity_id, + 'sort' => 0, ]); // Shift the image credits over to the new image diff --git a/app/Services/GalleryManager.php b/app/Services/GalleryManager.php index b6daf78ae3..6c88c087af 100644 --- a/app/Services/GalleryManager.php +++ b/app/Services/GalleryManager.php @@ -189,6 +189,10 @@ public function updateSubmission($submission, $data, $user) { throw new \Exception("You can't edit this submission."); } + if ($submission->status == 'Rejected') { + throw new \Exception('This submission has been rejected and cannot be edited.'); + } + // Check that there is text and/or an image, including if there is an existing image (via the existence of a hash) if ((!isset($data['image']) && !isset($submission->hash)) && !$data['text']) { throw new \Exception('Please submit either text or an image.'); @@ -368,7 +372,7 @@ public function editCollaborator($submission, $data, $user) { // Check if all collaborators have approved, and if so send a notification to the // submitting user (unless they are the last to approve-- which shouldn't happen, but) - if ($submission->collaboratorApproved) { + if ($submission->collaboratorApproval) { if (Settings::get('gallery_submissions_require_approval') && $submission->gallery->votes_required > 0) { if ($submission->user->id != $user->id) { Notifications::create('GALLERY_COLLABORATORS_APPROVED', $submission->user, [ @@ -406,7 +410,7 @@ public function castVote($action, $submission, $user) { if ($submission->status != 'Pending') { throw new \Exception('This request cannot be processed.'); } - if (!$submission->collaboratorApproved) { + if (!$submission->collaboratorApproval) { throw new \Exception("This submission's collaborators have not all approved yet."); } @@ -424,30 +428,18 @@ public function castVote($action, $submission, $user) { // Get existing vote data if it exists, remove any existing vote data for the user, // add the new vote data, and json encode it - $voteData = (isset($submission->vote_data) ? collect(json_decode($submission->vote_data, true)) : collect([])); + $voteData = (isset($submission->attributes['vote_data']) ? collect(json_decode($submission->attributes['vote_data'], true)) : collect([])); $voteData->get($user->id) ? $voteData->pull($user->id) : null; $voteData->put($user->id, $vote); $submission->vote_data = $voteData->toJson(); $submission->save(); - // Count up the existing votes to see if the required number has been reached - $rejectSum = 0; - $approveSum = 0; - foreach ($submission->voteData as $voter=> $vote) { - if ($vote == 1) { - $rejectSum += 1; - } - if ($vote == 2) { - $approveSum += 1; - } - } - - // And if so, process the submission - if ($action == 'reject' && $rejectSum >= $submission->gallery->votes_required) { + // Process the submission if the required number of votes has been reached + if ($action == 'reject' && $submission->getVoteData()['reject'] >= $submission->gallery->votes_required) { $this->rejectSubmission($submission, $user); } - if ($action == 'accept' && $approveSum >= $submission->gallery->votes_required) { + if ($action == 'accept' && $submission->getVoteData()['approve'] >= $submission->gallery->votes_required) { $this->acceptSubmission($submission); } @@ -886,7 +878,7 @@ private function acceptSubmission($submission) { // Send a notification to included characters' owners now that the submission is accepted // but not for the submitting user's own characters foreach ($submission->characters as $character) { - if ($character->user && $character->character->user->id != $submission->user->id) { + if ($character->character->user && $character->character->user->id != $submission->user->id) { Notifications::create('GALLERY_SUBMISSION_CHARACTER', $character->character->user, [ 'sender' => $submission->user->name, 'sender_url' => $submission->user->url, diff --git a/app/Services/RankService.php b/app/Services/RankService.php index 4cf1cedb51..c938453fa9 100644 --- a/app/Services/RankService.php +++ b/app/Services/RankService.php @@ -54,6 +54,8 @@ public function createRank($data, $user) { $data['color'] = isset($data['color']) ? str_replace('#', '', $data['color']) : null; if (isset($data['description']) && $data['description']) { $data['parsed_description'] = parse($data['description']); + } else { + $data['parsed_description'] = null; } $data['icon'] ??= 'fas fa-user'; @@ -106,6 +108,8 @@ public function updateRank($rank, $data, $user) { $data['color'] = isset($data['color']) ? str_replace('#', '', $data['color']) : null; if (isset($data['description']) && $data['description']) { $data['parsed_description'] = parse($data['description']); + } else { + $data['parsed_description'] = null; } $data['icon'] ??= 'fas fa-user'; diff --git a/app/Services/TradeManager.php b/app/Services/TradeManager.php index 1a7762f1c9..6726d56210 100644 --- a/app/Services/TradeManager.php +++ b/app/Services/TradeManager.php @@ -691,7 +691,7 @@ private function creditAttachments($trade, $data = []) { if (!$currency) { throw new \Exception('Cannot credit an invalid currency. ('.$currencyId.')'); } - if (!$currencyManager->creditCurrency($trade->{$type}, $trade->{$recipientType}, 'Trade', 'Received in trade [#'.$trade->id.']', $currency, $quantity)) { + if (!$currencyManager->creditCurrency($trade->{$type}, $trade->{$recipientType}, 'Trade', 'Received in trade [#'.$trade->id.']', $currency, $quantity)) { throw new \Exception('Could not credit currency. ('.$currencyId.')'); } } diff --git a/composer.json b/composer.json index eb97151ff4..f0291b2a45 100644 --- a/composer.json +++ b/composer.json @@ -9,13 +9,14 @@ "license": "MIT", "require": { "php": "^8.1", + "bacon/bacon-qr-code": "^3.0", "doctrine/dbal": "^3.7", "erusev/parsedown": "^1.7", "ezyang/htmlpurifier": "^4.10", "intervention/image": "^2.0", "josiasmontag/laravel-recaptchav3": "^1.0.0", "laracasts/flash": "^3.0", - "laravel/fortify": "^1.7", + "laravel/fortify": "^1.25", "laravel/framework": "^10.0", "laravel/helpers": "^1.4", "laravel/socialite": "^5.2", diff --git a/composer.lock b/composer.lock index 0c02a0e2e7..4790ed406c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,32 +4,32 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ac16e377cc2e367f3e2c2d2e9a64634a", + "content-hash": "c55171da67e589f3576e01d21cac6c5a", "packages": [ { "name": "bacon/bacon-qr-code", - "version": "2.0.8", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/Bacon/BaconQrCode.git", - "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22" + "reference": "f9cc1f52b5a463062251d666761178dbdb6b544f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22", - "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/f9cc1f52b5a463062251d666761178dbdb6b544f", + "reference": "f9cc1f52b5a463062251d666761178dbdb6b544f", "shasum": "" }, "require": { "dasprid/enum": "^1.0.3", "ext-iconv": "*", - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "phly/keep-a-changelog": "^2.1", - "phpunit/phpunit": "^7 | ^8 | ^9", - "spatie/phpunit-snapshot-assertions": "^4.2.9", - "squizlabs/php_codesniffer": "^3.4" + "phly/keep-a-changelog": "^2.12", + "phpunit/phpunit": "^10.5.11 || 11.0.4", + "spatie/phpunit-snapshot-assertions": "^5.1.5", + "squizlabs/php_codesniffer": "^3.9" }, "suggest": { "ext-imagick": "to generate QR code images" @@ -56,9 +56,9 @@ "homepage": "https://github.com/Bacon/BaconQrCode", "support": { "issues": "https://github.com/Bacon/BaconQrCode/issues", - "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8" + "source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.1" }, - "time": "2022-12-07T17:46:57+00:00" + "time": "2024-10-01T13:55:55+00:00" }, { "name": "brick/math", @@ -1813,40 +1813,41 @@ }, { "name": "laravel/fortify", - "version": "v1.19.1", + "version": "v1.25.3", "source": { "type": "git", "url": "https://github.com/laravel/fortify.git", - "reference": "1dde858a520f679b4a2f453fa68f8a0e98751875" + "reference": "ee35e5b8ea25cc51f8323e27a839283becd44160" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/fortify/zipball/1dde858a520f679b4a2f453fa68f8a0e98751875", - "reference": "1dde858a520f679b4a2f453fa68f8a0e98751875", + "url": "https://api.github.com/repos/laravel/fortify/zipball/ee35e5b8ea25cc51f8323e27a839283becd44160", + "reference": "ee35e5b8ea25cc51f8323e27a839283becd44160", "shasum": "" }, "require": { - "bacon/bacon-qr-code": "^2.0", + "bacon/bacon-qr-code": "^3.0", "ext-json": "*", - "illuminate/support": "^8.82|^9.0|^10.0", - "php": "^7.3|^8.0", - "pragmarx/google2fa": "^7.0|^8.0" + "illuminate/support": "^10.0|^11.0", + "php": "^8.1", + "pragmarx/google2fa": "^8.0", + "symfony/console": "^6.0|^7.0" }, "require-dev": { "mockery/mockery": "^1.0", - "orchestra/testbench": "^6.34|^7.31|^8.11", + "orchestra/testbench": "^8.16|^9.0", "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.4" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - }, "laravel": { "providers": [ "Laravel\\Fortify\\FortifyServiceProvider" ] + }, + "branch-alias": { + "dev-master": "1.x-dev" } }, "autoload": { @@ -1873,7 +1874,7 @@ "issues": "https://github.com/laravel/fortify/issues", "source": "https://github.com/laravel/fortify" }, - "time": "2023-12-11T16:16:45+00:00" + "time": "2025-01-17T15:17:57+00:00" }, { "name": "laravel/framework", @@ -9790,12 +9791,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.1" }, - "platform-dev": [], + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/config/lorekeeper/admin_sidebar.php b/config/lorekeeper/admin_sidebar.php index f7e1915ef8..b98df9068a 100644 --- a/config/lorekeeper/admin_sidebar.php +++ b/config/lorekeeper/admin_sidebar.php @@ -29,10 +29,6 @@ 'name' => 'Staff Reward Settings', 'url' => 'admin/staff-reward-settings', ], - [ - 'name' => 'User Ips', - 'url' => 'admin/users/ips', - ], ], ], 'Reports' => [ @@ -82,6 +78,10 @@ 'name' => 'Invitation Keys', 'url' => 'admin/invitations', ], + [ + 'name' => 'User Ips', + 'url' => 'admin/users/ips', + ], ], ], 'Queues' => [ diff --git a/config/lorekeeper/extensions.php b/config/lorekeeper/extensions.php index 65f0183599..97106f28cb 100644 --- a/config/lorekeeper/extensions.php +++ b/config/lorekeeper/extensions.php @@ -20,25 +20,25 @@ */ // Navbar News Notif - Juni - 'navbar_news_notif' => 0, + 'navbar_news_notif' => 0, // Species Trait Index - Mercury - 'species_trait_index' => [ + 'species_trait_index' => [ 'enable' => 0, 'trait_modals' => 0, // Enables modals when you click on a trait for more info instead of linking to the traits page - Moif ], // Character Status Badges - Juni - 'character_status_badges' => 0, + 'character_status_badges' => 0, // Character TH Profile Link - Juni - 'character_TH_profile_link' => 0, + 'character_TH_profile_link' => 0, // Design Update Voting - Mercury - 'design_update_voting' => 0, + 'design_update_voting' => 0, // Item Entry Expansion - Mercury - 'item_entry_expansion' => [ + 'item_entry_expansion' => [ 'extra_fields' => 0, 'resale_function' => 0, 'loot_tables' => [ @@ -49,33 +49,33 @@ ], // Group Traits By Category - Uri - 'traits_by_category' => 0, + 'traits_by_category' => 0, // Scroll To Top - Uri - 'scroll_to_top' => 0, // 1 - On, 0 - off + 'scroll_to_top' => 0, // 1 - On, 0 - off // Character Reward Expansion - Uri - 'character_reward_expansion' => [ + 'character_reward_expansion' => [ 'expanded' => 1, 'default_recipient' => 0, // 0 to default to the character's owner (if a user), 1 to default to the submission user. ], // MYO Image Hide/Remove - Mercury // Adds an option when approving MYO submissions to hide or delete the MYO placeholder image - 'remove_myo_image' => 0, + 'remove_myo_image' => 0, // Auto-populate New Image Traits - Mercury // Automatically adds the traits present on a character's active image to the list when uploading a new image for an extant character. - 'autopopulate_image_features' => 0, + 'autopopulate_image_features' => 0, // Staff Rewards - Mercury - 'staff_rewards' => [ + 'staff_rewards' => [ 'enabled' => 0, 'currency_id' => 1, ], // Organised Traits Dropdown - Draginraptor - 'organised_traits_dropdown' => 0, + 'organised_traits_dropdown' => 0, // Previous & Next buttons on Character pages - Speedy // Adds buttons linking to the previous character as well as the next character on all character pages. diff --git a/config/lorekeeper/notifications.php b/config/lorekeeper/notifications.php index 4e80c5b90f..834cac3d6f 100644 --- a/config/lorekeeper/notifications.php +++ b/config/lorekeeper/notifications.php @@ -141,14 +141,14 @@ 18 => [ 'name' => 'Character Sent', 'message' => '{character_name} was transferred to {recipient_name} by {sender_name}. (View Character)', - 'url' => 'character/{character_slug}', + 'url' => '/{character_url}', ], // CHARACTER_RECEIVED 19 => [ 'name' => 'Character Received', 'message' => '{character_name} was transferred to you by {sender_name}. (View Character)', - 'url' => 'character/{character_slug}', + 'url' => '/{character_url}', ], // SUBMISSION_APPROVED diff --git a/config/lorekeeper/settings.php b/config/lorekeeper/settings.php index 5b8e020b40..bb2ffd7fcd 100644 --- a/config/lorekeeper/settings.php +++ b/config/lorekeeper/settings.php @@ -74,7 +74,7 @@ | This is used in the automatic generation of character codes. | {category}: This is replaced by the character category code. | {number}: This is replaced by the character number. - / {year}: This is replaced by the current year. + | {year}: This is replaced by the current year. | | e.g. Under the default setting ({category}-{number}), | a character in a category called "MYO" (code "MYO") with number 001 diff --git a/public/js/bs-custom-file-input.min.js b/public/js/bs-custom-file-input.min.js new file mode 100644 index 0000000000..0815f3768d --- /dev/null +++ b/public/js/bs-custom-file-input.min.js @@ -0,0 +1,7 @@ +/*! + * bsCustomFileInput v1.3.4 (https://github.com/Johann-S/bs-custom-file-input) + * Copyright 2018 - 2020 Johann-S + * Licensed under MIT (https://github.com/Johann-S/bs-custom-file-input/blob/master/LICENSE) + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).bsCustomFileInput=t()}(this,function(){"use strict";var s={CUSTOMFILE:'.custom-file input[type="file"]',CUSTOMFILELABEL:".custom-file-label",FORM:"form",INPUT:"input"},l=function(e){if(0 @endif {!! Form::open(['url' => 'account/avatar', 'files' => true]) !!} -
- {!! Form::label('avatar', 'Update Profile Image', ['class' => 'col-md-2 col-form-label']) !!} -
- {!! Form::file('avatar', ['class' => 'form-control']) !!} -
+
+ {!! Form::label('avatar', 'Update Profile Image', ['class' => 'custom-file-label']) !!} + {!! Form::file('avatar', ['class' => 'custom-file-input']) !!}
{!! Form::submit('Edit', ['class' => 'btn btn-primary']) !!} diff --git a/resources/views/admin/_recent_registrations.blade.php b/resources/views/admin/_recent_registrations.blade.php new file mode 100644 index 0000000000..1d32b95e31 --- /dev/null +++ b/resources/views/admin/_recent_registrations.blade.php @@ -0,0 +1,77 @@ +
+
+
+

+ 10 Recent Registrations +

+
+ +
+ +
+
+
+
+
+ Username +
+
+
+
+ Registered +
+
+
+
+ IP Address{!! add_help('This is the first recorded IP address for this user.') !!} +
+
+
+
+ Shared With +
+
+
+
+
+ @foreach ($recentUsers as $user) +
+
+
+
+ {!! $user->displayName !!} +
+
+
+
+ {!! pretty_date($user->created_at) !!} +
+
+
+
+ {!! $user->ips()->first()->ip ?? '' !!} +
+
+
+
+ {!! $user->ips()->first() && + count( + $user->ips()->first()->users->where('id', '!=', $user->id)->pluck('displayName')->toArray(), + ) + ? implode( + ', ', + $user->ips()->first()->users->where('id', '!=', $user->id)->pluck('displayName')->toArray(), + ) + : '---' !!} +
+
+
+
+ @endforeach +
+
+
diff --git a/resources/views/admin/characters/create_edit_character_category.blade.php b/resources/views/admin/characters/create_edit_character_category.blade.php index 184c6eba9f..10f2958ccb 100644 --- a/resources/views/admin/characters/create_edit_character_category.blade.php +++ b/resources/views/admin/characters/create_edit_character_category.blade.php @@ -38,7 +38,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($category->has_image)
diff --git a/resources/views/admin/currencies/create_edit_currency.blade.php b/resources/views/admin/currencies/create_edit_currency.blade.php index 26b88dec23..740b1ed872 100644 --- a/resources/views/admin/currencies/create_edit_currency.blade.php +++ b/resources/views/admin/currencies/create_edit_currency.blade.php @@ -35,7 +35,10 @@
{!! Form::label('Icon Image (Optional)') !!} {!! add_help('This will be used to denote the currency. If not provided, the abbreviation will be used.') !!} - {!! Form::file('icon') !!} +
+ {!! Form::label('icon', 'Choose icon file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('icon', ['class' => 'custom-file-input']) !!} +
Recommended height: 16px
@if ($currency->has_icon)
@@ -48,7 +51,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} - {!! Form::file('image') !!} +
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($currency->has_image)
diff --git a/resources/views/admin/features/create_edit_feature.blade.php b/resources/views/admin/features/create_edit_feature.blade.php index 5164eb8f96..847a803df3 100644 --- a/resources/views/admin/features/create_edit_feature.blade.php +++ b/resources/views/admin/features/create_edit_feature.blade.php @@ -34,7 +34,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($feature->has_image)
diff --git a/resources/views/admin/features/create_edit_feature_category.blade.php b/resources/views/admin/features/create_edit_feature_category.blade.php index aa84a6fe23..8ffeb20b2b 100644 --- a/resources/views/admin/features/create_edit_feature_category.blade.php +++ b/resources/views/admin/features/create_edit_feature_category.blade.php @@ -28,7 +28,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($category->has_image)
diff --git a/resources/views/admin/files/images.blade.php b/resources/views/admin/files/images.blade.php index d31734fc21..2ddf6e5c77 100644 --- a/resources/views/admin/files/images.blade.php +++ b/resources/views/admin/files/images.blade.php @@ -14,15 +14,18 @@ @foreach ($images as $key => $image)
-
-
Site image: {{ $image['name'] }}
+
+
Site image: {{ $image['name'] }}

{{ $image['name'] }} View Current

{{ $image['description'] }}

{!! Form::open(['url' => 'admin/images/upload', 'files' => true]) !!}
- {!! Form::file('file', ['class' => 'form-control mr-2']) !!} - {!! Form::submit('Upload', ['class' => 'btn btn-primary']) !!} +
+ {!! Form::label('file', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('file', ['class' => 'custom-file-input']) !!} +
+ {!! Form::submit('Upload', ['class' => 'ml-1 btn btn-primary']) !!}
{!! Form::hidden('key', $key) !!} {!! Form::close() !!} @@ -42,8 +45,11 @@

CSS View Current

{!! Form::open(['url' => 'admin/images/upload/css', 'files' => true]) !!}
- {!! Form::file('file', ['class' => 'form-control mr-2']) !!} - {!! Form::submit('Upload', ['class' => 'btn btn-primary']) !!} +
+ {!! Form::label('file', 'Choose CSS...', ['class' => 'custom-file-label']) !!} + {!! Form::file('file', ['class' => 'custom-file-input']) !!} +
+ {!! Form::submit('Upload', ['class' => 'ml-1 btn btn-primary']) !!}
{!! Form::close() !!}
diff --git a/resources/views/admin/files/index.blade.php b/resources/views/admin/files/index.blade.php index 172ef658d5..1d8e277f18 100644 --- a/resources/views/admin/files/index.blade.php +++ b/resources/views/admin/files/index.blade.php @@ -33,28 +33,36 @@ @endif - - - - - - - - +
+
+
+
+
Files
+
+
+
+
+
+
+
@foreach ($files as $file) -
- - - +
+
+ +
+
+ Move + Rename + Delete +
+
+
+
@endforeach - -
Files
- {{ $file }} - - Move - Rename - Delete -
+
+
@if ($folder && !count($files)) @@ -205,6 +217,7 @@ function addFileRow() { $('#fileList').append($clone); $clone.removeClass('hide file-row'); $clone.addClass('d-flex'); + bsCustomFileInput.init(); } ///////// diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 1c97258e19..6be0456696 100644 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -202,4 +202,8 @@ @endif @endif
+ + @if (Auth::user()->hasPower('edit_user_info')) + @include('admin._recent_registrations', ['recentUsers' => $recentUsers]) + @endif @endsection diff --git a/resources/views/admin/items/create_edit_item.blade.php b/resources/views/admin/items/create_edit_item.blade.php index 40ce3b8c6a..fe0b6fd531 100644 --- a/resources/views/admin/items/create_edit_item.blade.php +++ b/resources/views/admin/items/create_edit_item.blade.php @@ -24,7 +24,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 100px x 100px
@if ($item->has_image)
diff --git a/resources/views/admin/items/create_edit_item_category.blade.php b/resources/views/admin/items/create_edit_item_category.blade.php index 6e85d589d6..b3ca92923b 100644 --- a/resources/views/admin/items/create_edit_item_category.blade.php +++ b/resources/views/admin/items/create_edit_item_category.blade.php @@ -28,7 +28,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($category->has_image)
diff --git a/resources/views/admin/layout.blade.php b/resources/views/admin/layout.blade.php index df42903da1..619127e616 100644 --- a/resources/views/admin/layout.blade.php +++ b/resources/views/admin/layout.blade.php @@ -1,8 +1,7 @@ @extends('layouts.app') @section('title') - Admin :: - @yield('admin-title') + Admin{!! View::hasSection('admin-title') ? ' :: ' . trim(View::getSection('admin-title')) : '' !!} @endsection @section('sidebar') diff --git a/resources/views/admin/logs.blade.php b/resources/views/admin/logs.blade.php index 2e02609dbd..babdd352d6 100644 --- a/resources/views/admin/logs.blade.php +++ b/resources/views/admin/logs.blade.php @@ -24,23 +24,43 @@
{!! $logs->render() !!} - - - - - - - - +
+
+
+
+
Staff
+
+
+
Action
+
+
+
Action Details
+
+
+
Date
+
+
+
+
@foreach ($logs as $log) -
- - - - - +
+
+
+
{!! $log->user->displayName !!}
+
+
+
{!! $log->action !!}
+
+
+
{!! $log->action_details !!}
+
+
+
{!! format_date($log->created_at) !!} ({!! pretty_date($log->created_at) !!})
+
+
+
@endforeach - -
StaffActionAction DetailsDate
{!! $log->user->displayName !!}{!! $log->action !!}{!! $log->action_details !!}{!! format_date($log->created_at) !!} ({!! pretty_date($log->created_at) !!})
+
+
{!! $logs->render() !!} @endsection diff --git a/resources/views/admin/loot_tables/_roll_loot_table.blade.php b/resources/views/admin/loot_tables/_roll_loot_table.blade.php index b825ae47b0..9940e7d43a 100644 --- a/resources/views/admin/loot_tables/_roll_loot_table.blade.php +++ b/resources/views/admin/loot_tables/_roll_loot_table.blade.php @@ -1,25 +1,41 @@

You rolled {{ $quantity }} time{{ $quantity != 1 ? 's' : '' }} for the following:

- - - - - - - +
+
+
+
+
#
+
+
+
Reward
+
+
+
Quantity
+
+
+
+
@foreach ($results as $result) @foreach ($result as $type) @if (count($type)) @foreach ($type as $t) -
- - - - +
+
+
+
{{ $count++ }}
+
+
+
{!! $t['asset']->displayName !!}
+
+
+
{{ $t['quantity'] }}
+
+
+
@endforeach @endif @endforeach @endforeach - -
#RewardQuantity
{{ $count++ }}{!! $t['asset']->displayName !!}{{ $t['quantity'] }}
+
+

Note: "None" results are not shown in this table.

diff --git a/resources/views/admin/masterlist/create_character.blade.php b/resources/views/admin/masterlist/create_character.blade.php index f9777f66c8..956b01d60a 100644 --- a/resources/views/admin/masterlist/create_character.blade.php +++ b/resources/views/admin/masterlist/create_character.blade.php @@ -134,7 +134,10 @@ @else {!! add_help('This is the full masterlist image. Note that the image is not protected in any way, so take precautions to avoid art/design theft.') !!} @endif -
{!! Form::file('image', ['id' => 'mainImage']) !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input', 'id' => 'mainImage']) !!} +
@if (config('lorekeeper.settings.masterlist_image_automation') === 1)
@@ -169,7 +172,10 @@
{!! Form::label('Thumbnail Image') !!} {!! add_help('This image is shown on the masterlist page.') !!} -
{!! Form::file('thumbnail') !!}
+
+ {!! Form::label('thumbnail', 'Choose thumbnail...', ['class' => 'custom-file-label']) !!} + {!! Form::file('thumbnail', ['class' => 'custom-file-input']) !!} +
Recommended size: {{ config('lorekeeper.settings.masterlist_thumbnails.width') }}px x {{ config('lorekeeper.settings.masterlist_thumbnails.height') }}px
diff --git a/resources/views/admin/prompts/create_edit_prompt.blade.php b/resources/views/admin/prompts/create_edit_prompt.blade.php index c02c43672f..92edce4be2 100644 --- a/resources/views/admin/prompts/create_edit_prompt.blade.php +++ b/resources/views/admin/prompts/create_edit_prompt.blade.php @@ -34,7 +34,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 100px x 100px
@if ($prompt->has_image)
diff --git a/resources/views/admin/prompts/create_edit_prompt_category.blade.php b/resources/views/admin/prompts/create_edit_prompt_category.blade.php index f13c417bfb..6db2e538de 100644 --- a/resources/views/admin/prompts/create_edit_prompt_category.blade.php +++ b/resources/views/admin/prompts/create_edit_prompt_category.blade.php @@ -28,7 +28,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($category->has_image)
diff --git a/resources/views/admin/raffle/ticket_index.blade.php b/resources/views/admin/raffle/ticket_index.blade.php index a54f2afcc7..4b7057355b 100644 --- a/resources/views/admin/raffle/ticket_index.blade.php +++ b/resources/views/admin/raffle/ticket_index.blade.php @@ -35,20 +35,32 @@
Winner(s)
- - - - - - +
+
+
+
+
#
+
+
+
User
+
+
+
+
@foreach ($raffle->tickets()->winners()->get() as $winner) -
- - - +
+
+
+
{{ $winner->position }}
+
+
+
{!! $winner->displayHolderName !!}
+
+
+
@endforeach - -
#User
{{ $winner->position }}{!! $winner->displayHolderName !!}
+
+
@endif @@ -57,26 +69,42 @@
{!! $tickets->render() !!}
- - - - - @if ($raffle->is_active < 2) - - @endif - - +
+
+
+
+
#
+
+
+
User
+
+ @if ($raffle->is_active < 2) +
+
+
+ @endif +
+
+
@foreach ($tickets as $count => $ticket) -
- - - @if ($raffle->is_active < 2) - - @endif - +
+
+
+
{{ $page * 200 + $count + 1 }}
+
+
+
{!! $ticket->displayHolderName !!}
+
+ @if ($raffle->is_active < 2) +
+
{!! Form::open(['url' => 'admin/raffles/view/ticket/delete/' . $ticket->id]) !!}{!! Form::submit('Delete', ['class' => 'btn btn-danger btn-sm']) !!}{!! Form::close() !!}
+
+ @endif +
+
@endforeach - -
#User
{{ $page * 200 + $count + 1 }}{!! $ticket->displayHolderName !!}{!! Form::open(['url' => 'admin/raffles/view/ticket/delete/' . $ticket->id]) !!}{!! Form::submit('Delete', ['class' => 'btn btn-danger btn-sm']) !!}{!! Form::close() !!}
+
+
{!! $tickets->render() !!}
diff --git a/resources/views/admin/rarities/create_edit_rarity.blade.php b/resources/views/admin/rarities/create_edit_rarity.blade.php index c7bde4b474..5b155f544e 100644 --- a/resources/views/admin/rarities/create_edit_rarity.blade.php +++ b/resources/views/admin/rarities/create_edit_rarity.blade.php @@ -34,7 +34,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($rarity->has_image)
@@ -65,6 +68,10 @@ 'description' => $rarity->parsed_description, 'searchFeaturesUrl' => $rarity->searchFeaturesUrl, 'searchCharactersUrl' => $rarity->searchCharactersUrl, + 'edit' => [ + 'title' => 'Edit Rarity', + 'object' => $rarity, + ], ])
diff --git a/resources/views/admin/sales/sales.blade.php b/resources/views/admin/sales/sales.blade.php index afb4c00e95..c076c49d52 100644 --- a/resources/views/admin/sales/sales.blade.php +++ b/resources/views/admin/sales/sales.blade.php @@ -16,39 +16,53 @@

No sales found.

@else {!! $saleses->render() !!} - - - - - - - - - - +
+
+
+
+
Title
+
+
+
Posted At
+
+
+
Last Edited
+
+
+
+
@foreach ($saleses as $sales) -
- - - - - +
+
+
+
+ @if (!$sales->is_visible) + @if ($sales->post_at) + + @else + + @endif + @endif + {{ $sales->title }} +
+
+
+
{!! pretty_date($sales->post_at ?: $sales->created_at) !!}
+
+
+
{!! pretty_date($sales->updated_at) !!}
+
+
+ +
+
+
@endforeach - - -
TitlePosted AtLast Edited
- @if (!$sales->is_visible) - @if ($sales->post_at) - - @else - - @endif - @endif - {{ $sales->title }} - {!! format_date($sales->post_at ?: $sales->created_at) !!}{!! format_date($sales->updated_at) !!} - Edit -
+
+
{!! $saleses->render() !!} + +
{{ $saleses->total() }} result{{ $saleses->total() == 1 ? '' : 's' }} found.
@endif @endsection diff --git a/resources/views/admin/settings/settings.blade.php b/resources/views/admin/settings/settings.blade.php index 45ebffa788..725bfff41c 100644 --- a/resources/views/admin/settings/settings.blade.php +++ b/resources/views/admin/settings/settings.blade.php @@ -16,35 +16,48 @@

No settings found.

@else {!! $settings->render() !!} - - - - - - - - - - +
+
+
+
+
Key
+
+
+
Description
+
+
+
Value
+
+
+
+
@foreach ($settings as $setting) -
- - - - +
+
+ {!! Form::open(['url' => 'admin/settings/' . $setting->key, 'class' => 'd-flex justify-content-end']) !!} +
+ {!! Form::text('value', $setting->value, ['class' => 'form-control']) !!} +
+
+ {!! Form::submit('Edit', ['class' => 'btn btn-primary']) !!} +
+ {!! Form::close() !!} +
+
+ + @endforeach - + -
KeyDescriptionValue
{{ $setting->key }}{{ $setting->description }} - {!! Form::open(['url' => 'admin/settings/' . $setting->key, 'class' => 'd-flex justify-content-end']) !!} -
- {!! Form::text('value', $setting->value, ['class' => 'form-control']) !!} +
+
+
+
{{ $setting->key }}
-
- {!! Form::submit('Edit', ['class' => 'btn btn-primary']) !!} +
+
{{ $setting->description }}
- {!! Form::close() !!} -
+
{!! $settings->render() !!} @endif diff --git a/resources/views/admin/shops/create_edit_shop.blade.php b/resources/views/admin/shops/create_edit_shop.blade.php index 5bcd734eaa..28cac4e3ed 100644 --- a/resources/views/admin/shops/create_edit_shop.blade.php +++ b/resources/views/admin/shops/create_edit_shop.blade.php @@ -25,7 +25,10 @@
{!! Form::label('Shop Image (Optional)') !!} {!! add_help('This image is used on the shop index and on the shop page as a header.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: None (Choose a standard size for all shop images)
@if ($shop->has_image)
diff --git a/resources/views/admin/specieses/create_edit_species.blade.php b/resources/views/admin/specieses/create_edit_species.blade.php index a6af130942..de027040ba 100644 --- a/resources/views/admin/specieses/create_edit_species.blade.php +++ b/resources/views/admin/specieses/create_edit_species.blade.php @@ -29,7 +29,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($species->has_image)
diff --git a/resources/views/admin/specieses/create_edit_subtype.blade.php b/resources/views/admin/specieses/create_edit_subtype.blade.php index fabbe3308d..543a710629 100644 --- a/resources/views/admin/specieses/create_edit_subtype.blade.php +++ b/resources/views/admin/specieses/create_edit_subtype.blade.php @@ -29,7 +29,10 @@
{!! Form::label('World Page Image (Optional)') !!} {!! add_help('This image is used only on the world information pages.') !!} -
{!! Form::file('image') !!}
+
+ {!! Form::label('image', 'Choose file...', ['class' => 'custom-file-label']) !!} + {!! Form::file('image', ['class' => 'custom-file-input']) !!} +
Recommended size: 200px x 200px
@if ($subtype->has_image)
diff --git a/resources/views/admin/staff_reward_settings.blade.php b/resources/views/admin/staff_reward_settings.blade.php index 6fa8437ad9..8558a31fce 100644 --- a/resources/views/admin/staff_reward_settings.blade.php +++ b/resources/views/admin/staff_reward_settings.blade.php @@ -22,35 +22,46 @@

No settings found.

@else {!! $settings->render() !!} - - - - - - - - - - +
+
+
+
+
Name
+
+
+
Description
+
+
+
Value
+
+
+
+
@foreach ($settings as $setting) -
- - - - + + @endforeach - + -
NameDescriptionValue
{{ $setting->name }}{{ $setting->description }} - {!! Form::open(['url' => 'admin/staff-reward-settings/' . $setting->key, 'class' => 'd-flex justify-content-end']) !!} -
- {!! Form::text('value', $setting->value, ['class' => 'form-control']) !!} +
+
+
{{ $setting->name }}
+
+
+
{{ $setting->description }}
+
+
+
+ {!! Form::open(['url' => 'admin/staff-reward-settings/' . $setting->key, 'class' => 'd-flex justify-content-end']) !!} +
+ {!! Form::text('value', $setting->value, ['class' => 'form-control']) !!} +
+
+ {!! Form::submit('Edit', ['class' => 'btn btn-primary']) !!} +
+ {!! Form::close() !!}
-
- {!! Form::submit('Edit', ['class' => 'btn btn-primary']) !!} -
- {!! Form::close() !!} -
+
{!! $settings->render() !!} @endif diff --git a/resources/views/admin/users/user.blade.php b/resources/views/admin/users/user.blade.php index 719746183e..4d380d4571 100644 --- a/resources/views/admin/users/user.blade.php +++ b/resources/views/admin/users/user.blade.php @@ -134,33 +134,72 @@
@php - $ips = $user->ips()->paginate(10); + $ips = $user->ips()->paginate(15); @endphp

Logged IPs

{!! $ips->render() !!} - - - - - - - - - - +
+
+
+
+
+ IP +
+
+
+
+ Stored On +
+
+
+
+ Last Used +
+
+
+
+ Shared With +
+
+
+
+
@foreach ($ips as $ip) -
- - - - - +
+
+
+
+ {{ $ip->ip }} +
+
+
+
+ {!! $ip->created_at ? pretty_date($ip->created_at) : 'Unknown' !!} +
+
+
+
+ {!! $ip->updated_at ? pretty_date($ip->updated_at) : 'Unknown' !!} +
+
+
+
+ {!! count( + $ip->users->where('id', '!=', $user->id)->pluck('displayName')->toArray(), + ) + ? implode( + ', ', + $ip->users->where('id', '!=', $user->id)->pluck('displayName')->toArray(), + ) + : '---' !!} +
+
+
+
@endforeach - -
IPStored AtLast Used AtShared With
{{ $ip->ip }}{!! $ip->created_at ? format_date($ip->created_at) : 'Unknown' !!}{!! $ip->updated_at ? format_date($ip->updated_at) : 'Unknown' !!} - {!! $ip->usersString ?? 'None' !!} -
+
+
{!! $ips->render() !!}
@endsection diff --git a/resources/views/admin/users/user_ban.blade.php b/resources/views/admin/users/user_ban.blade.php index a39bb15851..b3cc4d5113 100644 --- a/resources/views/admin/users/user_ban.blade.php +++ b/resources/views/admin/users/user_ban.blade.php @@ -1,11 +1,11 @@ @extends('admin.layout') @section('admin-title') - User: {{ $user->name }} + Ban User: {{ $user->name }} @endsection @section('admin-content') - {!! breadcrumbs(['Admin Panel' => 'admin', 'User Index' => 'admin/users', $user->name => 'admin/users/' . $user->name . '/edit', 'Account Updates' => 'admin/users/' . $user->name . '/updates']) !!} + {!! breadcrumbs(['Admin Panel' => 'admin', 'User Index' => 'admin/users', $user->name => 'admin/users/' . $user->name . '/edit', 'Ban User' => 'admin/users/' . $user->name . '/ban']) !!}

User: {!! $user->displayName !!}