1
0
Fork 0

Compare commits

...

29 commits

Author SHA1 Message Date
d079cb3934 Update README.md 2026-04-19 06:43:55 +02:00
aeecf0d395 add sail 2026-02-25 15:17:54 +01:00
4f104fe4f9 npm: update laravel mix as it fails with openssl on node >= 17 2026-02-25 15:10:51 +01:00
eef96841d6 composer: update packages. 2023-09-14 12:51:42 +02:00
93beb11442 package-lock.json: fix name 2023-09-14 11:27:59 +02:00
836f1e83ac resources/lang/se.json: Adding missing translations 2023-09-14 11:27:06 +02:00
f3ace72ad6 resources/views/item/show.blade.php: show some more info about the item. 2023-09-14 11:26:20 +02:00
23197cd6e2 app/Http/Middleware/Locale.php: EncryptCookies::handle() did not like $request to be type hinted. 2023-09-14 11:19:39 +02:00
76982af72d tests/Feature/ProfessionImport/BasicTest.php: Fixing an test error that compared reagents in wrong order. 2022-11-17 22:43:53 +01:00
7ddb89069d Merge branch 'description' 2022-11-17 22:33:47 +01:00
8ec20f02e4 resources/views/recipe/show.blade.php: Show description 2022-11-17 22:14:24 +01:00
389a22ff38 app/Jobs/ImportProfession.php: Import description. 2022-11-17 22:14:24 +01:00
b06cf18f51 app/Models/Recipe.php: Add description to fillable array. 2022-11-17 22:14:24 +01:00
3b5b2e3b09 Migration: 2021_07_08_134818_add_description_column_to_recipes_table.php 2022-11-17 22:14:23 +01:00
034fb36560 resources/lang/se.json: fix capital letter for "Import Profession" translation and add "Import profession". 2021-09-01 15:25:38 +02:00
e2cbab0e76 resources/views/profile/index.blade.php: Add link to profession import. 2021-09-01 15:24:50 +02:00
cb04ba9fcc app/Http/Requests/CharacterProfessionImportRequest.php: Rename to ProfessionImportRequest 2021-09-01 15:22:30 +02:00
2c50a372eb view: refactor profession import form to an component. 2021-09-01 15:20:30 +02:00
3692fcc485 Adding Profession Import (without specified character) 2021-09-01 15:17:00 +02:00
aa2b27bc50 tests/Feature/ProfessionImport/BasicTest.php: Add missing test data. 2021-08-29 18:31:58 +02:00
529e6bdda4 resources/views/character/profession/create.blade.php: minor fixes. 2021-08-29 14:46:36 +02:00
f6fd635078 app/Http/Requests/CharacterProfessionRequest.php: Rename to CharacterProfessionImportRequest 2021-08-29 11:50:57 +02:00
08c60a6842 app/Jobs/ImportProfession.php: Fixing Exception class used incorrectly.
"Exception" class used without "use Exception;" results in php trying to find an "App\Jobs\Exception" class (which there is none of)
2021-08-28 17:47:05 +02:00
8eda7a315c app/Jobs/ImportProfession.php: make $character variable optional and require $user. 2021-08-28 17:42:29 +02:00
f82f7c3571 app/Jobs/ImportProfession.php: Typo fix. 2021-08-28 16:57:59 +02:00
8cfa7f34d5 resources/views/layouts/app.blade.php: add flex and spacing to page_links div. 2021-08-28 15:14:22 +02:00
3e77520b29 resources/views/user/show.blade.php: Refactor to "characters" relationship as it sorts main characters first. 2021-08-28 15:08:22 +02:00
df08af6f7d app/Models/User.php: do not reuse "characters" relationship to define "alt_characters" relationship, use a regular hasMany() 2021-08-28 15:06:30 +02:00
77e8792edc app/Models/User.php: sort main characters first for "characters" relationship. 2021-08-28 15:04:32 +02:00
32 changed files with 7825 additions and 6928 deletions

View file

@ -7,11 +7,11 @@ LOG_CHANNEL=stack
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=heritage
DB_USERNAME=heritage
DB_PASSWORD=
DB_DATABASE=laravel
DB_USERNAME=sail
DB_PASSWORD=password
BROADCAST_DRIVER=log
CACHE_DRIVER=file

View file

@ -1,62 +1,77 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p>
# Heritage WoW
<p align="center">
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
Heritage WoW is a Laravel application for managing World of Warcraft characters and profession data.
It supports importing profession exports, browsing recipes/items, and account login with username/password or Discord OAuth.
## About Laravel
## Features
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- Character pages with owned professions and recipes
- Profession import pipeline (queued job) for sync/update
- Recipe and item listing pages
- Local authentication and Discord OAuth login
- Admin-only user management routes
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
## Stack
Laravel is accessible, powerful, and provides tools required for large, robust applications.
- PHP/Laravel: Laravel 8
- Frontend: Blade + Tailwind CSS + Alpine.js
- Build tooling: Laravel Mix
- Database: MySQL (default in `.env.example`)
## Learning Laravel
## Local Setup
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
1. Install dependencies:
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 1500 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
```bash
composer install
npm install
```
## Laravel Sponsors
2. Configure environment:
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).
```bash
cp .env.example .env
php artisan key:generate
```
### Premium Partners
3. Update database and OAuth values in `.env` (minimum: DB_*).
- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
4. Run migrations and seeders:
## Contributing
```bash
php artisan migrate --seed
```
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
5. Start the app and asset pipeline:
## Code of Conduct
```bash
php artisan serve
npm run dev
```
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
6. If using an async queue connection for imports, run a worker:
## Security Vulnerabilities
```bash
php artisan queue:work
```
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
## Useful Commands
- Run tests: `php artisan test`
- Build production assets: `npm run prod`
- Create a user: `php artisan user:create <username> <password>`
- Create an admin user: `php artisan user:create <username> <password> --admin`
## OAuth (Discord)
To enable Discord login, set these variables in `.env`:
- `DISCORD_CLIENT_ID`
- `DISCORD_CLIENT_SECRET`
- `DISCORD_REDIRECT_URI`
The callback route is `/oauth/discord/callback`.
## License
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
This project is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

View file

@ -6,7 +6,7 @@ use App\Models\Character;
use App\Models\Profession;
use App\Models\Recipe;
use App\Models\CharacterProfession;
use App\Http\Requests\CharacterProfessionRequest;
use App\Http\Requests\ProfessionImportRequest;
use App\Jobs\ImportProfession;
class CharacterProfessionController extends Controller
@ -32,7 +32,7 @@ class CharacterProfessionController extends Controller
]);
}
public function store(Character $character, CharacterProfessionRequest $request)
public function store(Character $character, ProfessionImportRequest $request)
{
$this->authorize('import_profession', $character);
@ -41,7 +41,7 @@ class CharacterProfessionController extends Controller
$data = json_decode($request->input('data'));
try {
ImportProfession::dispatch($character, $data);
ImportProfession::dispatch($data, $request->user(), $character);
} catch(\App\ProfessionImport\Exception $e) {
return redirect()->back()->with('error', $e->getMessage());
}

View file

@ -0,0 +1,28 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ProfessionImportRequest;
use App\Jobs\ImportProfession;
class ProfessionController extends Controller
{
public function create()
{
return view('profession.create');
}
public function store(ProfessionImportRequest $request)
{
$request->validated();
$data = json_decode($request->input('data'));
try {
ImportProfession::dispatch($data, $request->user());
} catch(\App\ProfessionImport\Exception $e) {
return redirect()->back()->with('error', $e->getMessage());
}
return redirect()->back()->with('success', 'Profession imported!');
}
}

View file

@ -5,7 +5,6 @@ namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
use Closure;
use Illuminate\Http\Request;
class Locale extends Middleware
{
@ -15,7 +14,7 @@ class Locale extends Middleware
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
public function handle($request, Closure $next)
{
if (session()->has('locale')) {
app()->setlocale(session()->get('locale'));

View file

@ -4,7 +4,7 @@ namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CharacterProfessionRequest extends FormRequest
class ProfessionImportRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.

View file

@ -2,6 +2,7 @@
namespace App\Jobs;
use App\Models\User;
use App\Models\Character;
use App\Models\Profession;
use App\Models\CharacterProfession;
@ -21,6 +22,8 @@ use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
use Exception;
class ImportProfession implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
@ -40,12 +43,22 @@ class ImportProfession implements ShouldQueue
*
* @return void
*/
public function __construct(Character $character, $data)
public function __construct($data, User $user, ?Character $character = null)
{
// Validate character name first.
if ($character->name !== $data->player) {
$message = sprintf('Wrong character: %s expected %s', $data->player, $character->name);
throw new InvalidCharacterException($message);
if ($character) {
if ($character->name !== $data->player) {
$message = sprintf('Wrong character: %s expected %s', $data->player, $character->name);
throw new InvalidCharacterException($message);
}
} else {
$character = Character::where('name', $data->player)
->where('user_id', $user->id)->first();
if (!$character) {
$message = sprintf('Could not find character "%s"', $data->player);
throw new InvalidCharacterException($message);
}
}
// Validate profession
@ -152,7 +165,7 @@ class ImportProfession implements ShouldQueue
// names for reagents. so we skip those.
// 2021-07-08: Also skip items without id.
if (!isset($item->name) || !isset($items->id)) {
if (!isset($item->name) || !isset($item->id)) {
return [];
}
@ -189,7 +202,8 @@ class ImportProfession implements ShouldQueue
$recipe = $profession->recipes()->create([
'item_id' => $crafted ? $crafted->id : null,
'spell_id' => $spell->id,
'category_id' => $category->id
'category_id' => $category->id,
'description' => isset($data->description) ? $data->description : null
]);
}
// Existing record.
@ -203,6 +217,10 @@ class ImportProfession implements ShouldQueue
if (!$recipe->spell) {
$recipe->spell()->associate($spell);
}
if ($recipe->description === NULL && isset($data->description)) {
$recipe->description = $data->description;
}
}
// Insert/Update Reagents

View file

@ -34,7 +34,8 @@ class Recipe extends Model
'profession_id',
'category_id',
'item_id',
'spell_id'
'spell_id',
'description'
];
/**

View file

@ -60,7 +60,8 @@ class User extends Authenticatable
public function alt_characters()
{
$relation = $this->characters();
$relation = $this->hasMany(Character::class);
if ($this->character_id) {
$relation->where('id', '!=', $this->character_id);
}
@ -69,7 +70,13 @@ class User extends Authenticatable
public function characters()
{
return $this->hasMany(Character::class);
$relation = $this->hasMany(Character::class);
// sort main character first if set.
if ($this->character_id) {
$relation->orderByRaw('id = ' . $this->character_id . ' DESC');
}
return $relation;
}
public function getRoleAttribute()

3053
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddDescriptionColumnToRecipesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('recipes', function (Blueprint $table) {
$table->text('description')->nullable();
});
}
}

56
docker-compose.yml Normal file
View file

@ -0,0 +1,56 @@
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.2
dockerfile: Dockerfile
image: sail-8.2/app
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER:-1000}'
WWWGROUP: '${WWWGROUP:-1000}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
IGNITION_LOCAL_SITES_PATH: '${PWD}'
volumes:
- '.:/var/www/html:z'
networks:
- sail
depends_on:
- mysql
mysql:
image: 'heritage/mysql:8.0'
build:
context: './docker/mysql'
dockerfile: Dockerfile
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: '%'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
networks:
- sail
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-p${DB_PASSWORD}'
retries: 3
timeout: 5s
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local

4
docker/mysql/Dockerfile Normal file
View file

@ -0,0 +1,4 @@
FROM mysql/mysql-server:8.0
COPY create-testing-database.sh /docker-entrypoint-initdb.d/10-create-testing-database.sh
RUN chmod +x /docker-entrypoint-initdb.d/10-create-testing-database.sh
RUN chown -R mysql:mysql /docker-entrypoint-initdb.d

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
mysql --user=root --password="$MYSQL_ROOT_PASSWORD" <<-EOSQL
CREATE DATABASE IF NOT EXISTS testing;
GRANT ALL PRIVILEGES ON \`testing%\`.* TO '$MYSQL_USER'@'%';
EOSQL

11003
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@
"@tailwindcss/forms": "^0.3.3",
"autoprefixer": "^10.2.5",
"axios": "^0.21",
"laravel-mix": "^6.0.6",
"laravel-mix": "^6.0.49",
"lodash": "^4.17.19",
"postcss": "^8.2.14",
"tailwindcss": "^2.1.2"

View file

@ -21,8 +21,7 @@
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="DB_CONNECTION" value="mysql"/>
<server name="DB_DATABASE" value="heritage_test"/>
<server name="DB_DATABASE" value="testing"/>
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>

View file

@ -7,11 +7,15 @@
"Crafter": "Hantverkare",
"Crafters": "Hantverkare",
"Create": "Skapa",
"Created by": "Skapad av",
"Download this": "Ladda ner detta",
"Gender": "Kön",
"Import Profession": "Importera yrke",
"Import Profession": "Importera Yrke",
"Import profession": "Importera yrke",
"Import string": "Import sträng",
"Import": "Importera",
"Important": "Viktigt",
"Item": "Föremål",
"Items": "Föremål",
"Login": "Logga in",
"Logout": "Logga ut",
@ -35,5 +39,6 @@
"of": "av",
"or": "eller",
"results": "resultat",
"to": "till"
"to": "till",
"to generate the import string": "för att generera import strängen"
}

View file

@ -9,22 +9,8 @@
</div>
</x-slot>
<div class="mx-auto max-w-sm p-4">
<p>
{{ __('Download this') }}
<x-link href="https://www.curseforge.com/wow/addons/professions-exporter" target="_blank">{{ __('addon') }}</x-link>
</p>
<x-form action="{{ route('character.profession.store', [ 'character' => $character->slug ]) }}">
<div class="mb-2">
<x-form.label for="data">{{ __('Import string') }}</x-form.label>
<x-textarea class="h-64" name="data" />
</div>
<div class="mt-2">
<x-button element="input" type="submit" value="{{ __('Import') }}" />
</div>
</x-form>
<div class="p-4">
<x-profession-import-form route="{{ route('character.profession.store', [ 'character' => $character->slug ]) }}" />
</div>
</x-layout>

View file

@ -0,0 +1,17 @@
<p class="text-center">
<strong>{{ __("Important") }}!</strong>
{{ __('Download this') }}
<x-link href="https://www.curseforge.com/wow/addons/professions-exporter" target="_blank">{{ __('addon') }}</x-link>
{{ __('to generate the import string') }}
</p>
<x-form action="{{ $route }}">
<div class="mb-2">
<x-form.label for="data">{{ __('Import string') }}</x-form.label>
<x-textarea class="h-64" name="data" />
</div>
<div class="mt-2">
<x-button element="input" type="submit" value="{{ __('Import') }}" />
</div>
</x-form>

View file

@ -3,6 +3,43 @@
<x-slot name="title">{{ __('Item') }} - {{ $item->name }}</x-slot>
<div class="p-4">
<div class="mb-4">
<x-wowhead-link wh-id="{{ $item->external_id }}">{{ $item->name }}</x-wowhead-link>
</div>
@if (count($item->recipes) > 0)
<div class="mb-4">
<x-section-heading>
<h2 class="text-3xl">{{ __('Created by') }}</h2>
</x-section-heading>
<ul class="px-4 space-y-2">
@foreach($item->recipes as $recipe)
<li>
@if ($recipe->spell_id)
<x-wowhead-link type="spell" wh-id="{{ $recipe->spell_id }}" href="{{ route('recipe.show', [ 'recipe' => $recipe ]) }}">{{ $recipe->name }}</x-wowhead-link>
@else
{{ $recipe->name }}
@endif
</li>
@endforeach
</li>
</div>
@endif
@if (count($item->reagent_for) > 0)
<div class="mb-4">
<x-section-heading>
<h2 class="text-3xl">{{ __('Reagent for') }}</h2>
</x-section-heading>
<ul class="px-4 space-y-2">
@foreach($item->reagent_for as $recipe)
<li><x-recipe-link :recipe="$recipe" /></li>
@endforeach
</ul>
</div>
@endif
</div>
</x-layout>

View file

@ -12,7 +12,7 @@
</div>
@if (isset($page_links))
<div>
<div class="flex space-x-2">
{{ $page_links }}
</div>
@endif

View file

@ -0,0 +1,13 @@
<x-layout name="app">
<x-slot name="title">
<div class="flex">
{{ __('Import Profession') }}
</div>
</x-slot>
<div class="p-4">
<x-profession-import-form route="{{ route('profession.store') }}" />
</div>
</x-layout>

View file

@ -16,10 +16,14 @@
<x-section-heading>
<h2 class="text-3xl">{{ __('Characters') }}</h2>
<div>
<div class="flex space-x-2">
<x-button element="a" class="flex items-center" href="{{ route('character.create') }}">
<x-icon name="plus" class="h-6 h-6 mr-1"/> {{ __('Add character') }}
</x-button>
<x-button element="a" class="flex items-center" href="{{ route('profession.create') }}">
<x-icon name="plus" class="h-6 h-6 mr-1"/> {{ __('Import profession') }}
</x-button>
</div>
</x-section-heading>

View file

@ -9,6 +9,10 @@
<div class="p-4">
@if ($recipe->description)
<p>{{ $recipe->description }}</p>
@endif
@if ($recipe->craft)
<div class="mb-4">
<x-section-heading>

View file

@ -10,12 +10,8 @@
@if ($user->characters->count())
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-4">
@if ($user->main_character)
<x-character-card :character="$user->main_character" frame="true" />
@endif
@foreach($user->alt_characters as $character)
<x-character-card :character="$character" />
@foreach($user->characters as $character)
<x-character-card :character="$character" :frame="$character->isMain()" />
@endforeach
</div>
@else

View file

@ -82,6 +82,12 @@ Route::prefix('items')->name('item.')->group(function () {
// ----------------------------
Route::middleware(['auth'])->group(function() {
// Profession
Route::prefix('profession')->name('profession.')->group(function() {
Route::get('/create', [ProfessionController::class, 'create'])->name('create');
Route::post('/', [ProfessionController::class, 'store'])->name('store');
});
Route::prefix('profile')->name('profile.')->group(function () {
Route::get('/', [ProfileController::class, 'index'])->name('index');
Route::get('/edit', [ProfileController::class, 'edit'])->name('edit');

View file

@ -11,7 +11,6 @@ use App\Models\Recipe;
use App\Models\Spell;
use App\Jobs\ImportProfession;
use App\ProfessionImport\InvalidCharacterException;
use App\ProfessionImport\InvalidProfessionException;
use Illuminate\Foundation\Testing\RefreshDatabase;
@ -96,7 +95,7 @@ class BasicTest extends TestCase
Profession::factory()->create([ 'name' => 'Alchemy' ]);
$character = Character::factory()->create([ 'name' => 'Superduper']);
ImportProfession::dispatch($character, $data);
ImportProfession::dispatch($data, $character->user, $character);
$this->assertEquals('Alchemy', $character->professions[0]->name);
$recipes = $character->professions[0]->recipes;
@ -131,35 +130,13 @@ class BasicTest extends TestCase
$this->assertEquals('Imbued Vial', $recipes[1]->reagents[0]->name);
$this->assertEquals(1, $recipes[1]->reagents[0]->quantity);
$this->assertEquals(22789, $recipes[1]->reagents[1]->external_id);
$this->assertEquals('Terocone', $recipes[1]->reagents[1]->name);
$this->assertEquals(1, $recipes[1]->reagents[1]->quantity);
$this->assertEquals(22785, $recipes[1]->reagents[1]->external_id);
$this->assertEquals('Felweed', $recipes[1]->reagents[1]->name);
$this->assertEquals(2, $recipes[1]->reagents[1]->quantity);
$this->assertEquals(22785, $recipes[1]->reagents[2]->external_id);
$this->assertEquals('Felweed', $recipes[1]->reagents[2]->name);
$this->assertEquals(2, $recipes[1]->reagents[2]->quantity);
}
public function test_wrong_character_name()
{
Profession::factory()->create([ 'name' => 'Alchemy' ]);
$character = Character::factory()->create([ 'name' => 'Actualname']);
$data = (object) [
"server" => "Ashbringer",
"player" => "Wrongname",
"guild" => "Flat Azeroth Research Team",
"profession" => (object) [
"name" => "Alchemy",
"level" => 375,
"maxLevel" => 375,
"recipes" => []
]
];
$this->expectException(InvalidCharacterException::class);
ImportProfession::dispatch($character, $data);
$this->assertEquals(22789, $recipes[1]->reagents[2]->external_id);
$this->assertEquals('Terocone', $recipes[1]->reagents[2]->name);
$this->assertEquals(1, $recipes[1]->reagents[2]->quantity);
}
public function test_invalid_profession()
@ -170,7 +147,7 @@ class BasicTest extends TestCase
$character = Character::factory()->create();
$data = (object) [
"server" => "Ashbringer",
"server" => "Sulfuron",
"player" => $character->name,
"guild" => "Futuramalama",
"profession" => (object) [
@ -183,6 +160,6 @@ class BasicTest extends TestCase
$this->expectException(InvalidProfessionException::class);
ImportProfession::dispatch($character, $data);
ImportProfession::dispatch($data, $character->user, $character);
}
}

View file

@ -0,0 +1,152 @@
<?php
namespace Tests\Feature\ProfessionImport;
use App\Models\User;
use App\Models\Character;
use App\Models\Profession;
use App\Jobs\ImportProfession;
use App\ProfessionImport\InvalidCharacterException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class CharacterTest extends TestCase
{
use RefreshDatabase;
public function test_character_found()
{
Profession::factory()->create([ 'name' => 'Alchemy' ]);
$character = Character::factory()->create([ 'name' => 'Charfound']);
$data = (object) [
"server" => "Darkshore",
"player" => "Charfound",
"guild" => "ABOBA",
"profession" => (object) [
"name" => "Alchemy",
"level" => 375,
"maxLevel" => 375,
"recipes" => [
(object) [
"name" => "Elixir of Major Defense",
"color" => "ffffff",
"id" => 22834,
"num" => 1,
"categorie" => "Elixir",
"items" => [
(object) [
"name" => "Ancient Lichen",
"color" => "ffffff",
"num" => 3,
"id" => 22790
],
(object) [
"name" => "Terocone",
"color" => "ffffff",
"num" => 1,
"id" => 22789
],
(object) [
"name" => "Imbued Vial",
"color" => "ffffff",
"num" => 1,
"id" => 18256
],
],
"spellId" => 28557
],
]
]
];
ImportProfession::dispatch($data, $character->user);
$this->assertEquals('Alchemy', $character->professions[0]->name);
$recipes = $character->professions[0]->recipes;
$this->assertEquals(22834, $recipes[0]->craft->external_id);
$this->assertEquals('Elixir of Major Defense', $recipes[0]->craft->name);
$this->assertEquals(28557, $recipes[0]->spell->id);
$this->assertEquals('Elixir of Major Defense', $recipes[0]->spell->name);
$this->assertEquals(22790, $recipes[0]->reagents[0]->external_id);
$this->assertEquals('Ancient Lichen', $recipes[0]->reagents[0]->name);
$this->assertEquals(3, $recipes[0]->reagents[0]->quantity);
$this->assertEquals(18256, $recipes[0]->reagents[1]->external_id);
$this->assertEquals('Imbued Vial', $recipes[0]->reagents[1]->name);
$this->assertEquals(1, $recipes[0]->reagents[1]->quantity);
$this->assertEquals(22789, $recipes[0]->reagents[2]->external_id);
$this->assertEquals('Terocone', $recipes[0]->reagents[2]->name);
$this->assertEquals(1, $recipes[0]->reagents[2]->quantity);
}
public function test_character_not_found()
{
$character = Character::factory()->create([ 'name' => 'Findme']);
$data = (object) [
"server" => "Ashbringer",
"player" => "Anotherdude",
"guild" => "Raiders of the Last Mark",
"profession" => (object) [
"name" => "Alchemy",
"level" => 375,
"maxLevel" => 375,
"recipes" => []
]
];
$this->expectException(InvalidCharacterException::class);
ImportProfession::dispatch($data, $character->user);
}
public function test_other_users_characters_is_not_found()
{
$character = Character::factory()->create([ 'name' => 'Otherchar']);
$data = (object) [
"server" => "Rattlegore",
"player" => "Otherchar",
"guild" => "The A-Team",
"profession" => (object) [
"name" => "Alchemy",
"level" => 375,
"maxLevel" => 375,
"recipes" => []
]
];
$this->expectException(InvalidCharacterException::class);
ImportProfession::dispatch($data, User::factory()->create());
}
public function test_character_is_not_the_same_as_imported_name()
{
$character = Character::factory()->create([ 'name' => 'Actualname']);
$data = (object) [
"server" => "Benediction",
"player" => "Wrongname",
"guild" => "Spaceballs",
"profession" => (object) [
"name" => "Alchemy",
"level" => 375,
"maxLevel" => 375,
"recipes" => []
]
];
$this->expectException(InvalidCharacterException::class);
ImportProfession::dispatch($data, $character->user, $character);
}
}

View file

@ -22,7 +22,7 @@ class RecipesTest extends TestCase
$this->seed(\Database\Seeders\ProductionSeeders\ItemSeeder::class);
$data = (object) [
"server" => "Ashbringer",
"server" => "Whitemane",
"player" => "Scumbag",
"guild" => "Method",
"profession" => (object) [
@ -68,7 +68,7 @@ class RecipesTest extends TestCase
Profession::factory()->create([ 'name' => 'Enchanting' ]);
$character = Character::factory()->create([ 'name' => 'Scumbag']);
ImportProfession::dispatch($character, $data);
ImportProfession::dispatch($data, $character->user, $character);
$this->assertEquals('Enchanting', $character->professions[0]->name);
$recipes = $character->professions[0]->recipes;
@ -106,7 +106,9 @@ class RecipesTest extends TestCase
->create(['spell_id' => null]);
$data = (object) [
"server" => "Mograine",
"player" => $character->name,
"guild" => "Odyssey",
"profession" => (object) [
"name" => $profession->name,
"level" => 375,
@ -123,7 +125,7 @@ class RecipesTest extends TestCase
]
];
ImportProfession::dispatch($character, $data);
ImportProfession::dispatch($data, $character->user, $character);
$this->assertEquals(1, Recipe::count());
$this->assertDatabaseHas('recipes', [

View file

@ -22,7 +22,9 @@ class SpecializationTest extends TestCase
$specialization = Spell::factory()->create(['id' => 28672, 'name' => 'Transmutation Master']);
$data = (object) [
"server" => "Firemaw",
"player" => $character->name,
"guild" => "Salad Bakers",
"profession" => (object) [
"name" => $profession->name,
"specializationId" => 28672,
@ -32,7 +34,7 @@ class SpecializationTest extends TestCase
]
];
ImportProfession::dispatch($character, $data);
ImportProfession::dispatch($data, $character->user, $character);
$this->assertNotNull($character->professions[0]->specialization, "specalization was not imported");
$this->assertEquals(28672, $character->professions[0]->specialization->id);
@ -47,7 +49,9 @@ class SpecializationTest extends TestCase
$profession = Profession::factory()->create([ 'name' => 'Carpenter' ]);
$data = (object) [
"server" => "Loatheb",
"player" => $character->name,
"guild" => "Progress",
"profession" => (object) [
"name" => $profession->name,
"level" => 375,
@ -55,7 +59,7 @@ class SpecializationTest extends TestCase
]
];
ImportProfession::dispatch($character, $data);
ImportProfession::dispatch($data, $character->user, $character);
$this->assertNull($character->professions[0]->specialization);
}

View file

@ -0,0 +1,89 @@
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\Models\Profession;
use App\Models\Character;
use App\Models\User;
class ProfessionTest extends TestCase
{
use RefreshDatabase;
public function test_guest_is_not_allowed_to_create_profession()
{
$response = $this->get(route('profession.create'));
$response->assertRedirect(route('auth.login'));
}
public function test_user_is_allowed_to_create_profession()
{
$user = User::factory()->create();
$response = $this->actingAs($user)
->get(route('profession.create'));
$response->assertStatus(200); // OK
}
public function test_user_is_allowed_to_import_profession_for_their_own_character()
{
Profession::factory()->create(['name' => 'Influencer']);
$user = User::factory()->create();
$character = Character::factory()
->for($user)
->create(['name' => 'Rambone']);
$data = '{
"server":"Bigglesworth",
"player":"Rambone",
"guild":"First Blood",
"profession": {
"locale":"enUS",
"name":"Influencer",
"specializationId":null,
"specializationName":null,
"level":375,
"maxLevel":375,
"recipes": []
}
}';
$response = $this->actingAs($user)
->post(route('profession.store'), ['data' => $data]);
$response->assertSessionHas(['success' => "Profession imported!"]);
}
public function test_user_is_not_allowed_to_import_profession_for_someone_elses_character()
{
Profession::factory()->create(['name' => 'Alchemy']);
$user = User::factory()->create();
$character = Character::factory()->create(['name' => 'Angus']);
$data = '{
"server":"Deviate Delight",
"player":"Angus",
"guild":"Phoenix",
"profession": {
"locale":"enUS",
"name":"Alchemy",
"specializationId":null,
"specializationName":null,
"level":375,
"maxLevel":375,
"recipes": []
}
}';
$response = $this->actingAs($user)
->post(route('profession.store'), ['data' => $data]);
$response->assertSessionHas(['error' => 'Could not find character "Angus"']);
}
}