diff --git a/app/Actions/CreateAndAttachRating.php b/app/Actions/CreateAndAttachRating.php new file mode 100644 index 000000000..2ab7c7004 --- /dev/null +++ b/app/Actions/CreateAndAttachRating.php @@ -0,0 +1,48 @@ + $entry->id, + 'user_id' => $entry->dungeon_master_id, + 'author_id' => $entry->user_id, + 'categories' => 0, + ]); + + $ratingMap = collect([ + Rating::CREATIVE_LABEL => Rating::CREATIVE_BITMASK , + Rating::FLEXIBLE_LABEL => Rating::FLEXIBLE_BITMASK, + Rating::FRIENDLY_LABEL => Rating::FRIENDLY_BITMASK, + Rating::HELPFUL_LABEL => Rating::HELPFUL_BITMASK, + Rating::PREPARED_LABEL => Rating::PREPARED_BITMASK, + ]); + + foreach ($ratingData as $category => $value) { + if ($value) { + $key = strtoupper($category); + $rating->addCategory($ratingMap[$key]); + } + } + + $rating->save(); + + return $rating; + } +} diff --git a/app/Http/Controllers/EntryController.php b/app/Http/Controllers/EntryController.php index 2740b0104..6a65c7995 100644 --- a/app/Http/Controllers/EntryController.php +++ b/app/Http/Controllers/EntryController.php @@ -3,12 +3,14 @@ namespace App\Http\Controllers; use App\Actions\CreateEntryItems; +use App\Actions\CreateAndAttachRating; use App\Http\Requests\EntryStoreRequest; use App\Http\Requests\EntryUpdateRequest; use App\Models\Entry; use Illuminate\Http\Request; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Auth; +use function PHPUnit\Framework\isEmpty; class EntryController extends Controller { @@ -42,8 +44,13 @@ public function create(Request $request) */ public function store(EntryStoreRequest $request) { - $entryData = collect($request->validated())->except('items'); + $entryData = collect($request->validated())->except('items', 'rating_data'); $itemData = collect($request->validated())->only('items'); + $ratingData = collect($request->validated())->only('rating_data'); + + if ($ratingData->has('rating_data')) { + $ratingData = $ratingData['rating_data']; + } if ($itemData->has('items')) { $itemData = $itemData['items']; @@ -53,26 +60,17 @@ public function store(EntryStoreRequest $request) $itemData = $itemData->toArray(); } - //possibly implement as function for reusability - if ($entryData->get('choice') == 'advancement') { - // advancement: increment character's level - $entryData['levels'] = 1; - $itemData = []; - } elseif ($entryData->get('choice') == 'magic_item') { - // magic_item: attach item to character of choice, and set entry's levels to 0 - $itemData = [$itemData[0] ?? []]; - $entryData['levels'] = 0; - } elseif ($entryData->get('choice') == 'campaign_reward') { - // campaign reward: set levels = 0, no item(s), should contain custom note - $itemData = []; - $entryData['levels'] = 0; - } + list($entryData, $itemData) = $this->chooseReward($entryData, $itemData); $entry = Entry::create($entryData->toArray()); // attach any associated items to the entry in question. CreateEntryItems::run($entry, $itemData ?? []); $request->session()->flash('entry.id', $entry->id); + if (!empty($ratingData) && is_array($ratingData)) { + CreateAndAttachRating::run($entry, $ratingData); + } + if ($request->type == Entry::TYPE_DM) { return redirect()->route('dm-entry.index'); } @@ -107,8 +105,13 @@ public function edit(Request $request, Entry $entry) */ public function update(EntryUpdateRequest $request, Entry $entry) { - $entryData = collect($request->validated())->except('items'); + $entryData = collect($request->validated())->except('items', 'rating_data'); $itemData = collect($request->validated())->only('items'); + $ratingData = collect($request->validated())->only('rating_data'); + + if ($ratingData->has('rating_data')) { + $ratingData = $ratingData['rating_data']; + } if ($itemData->has('items')) { $itemData = $itemData['items']; @@ -118,25 +121,17 @@ public function update(EntryUpdateRequest $request, Entry $entry) $itemData = $itemData->toArray(); } - //replace with function call when implemented - if ($entryData->get('choice') == 'advancement') { - // advancement: increment character's level - $entryData['levels'] = 1; - $itemData = []; - } elseif ($entryData->get('choice') == 'magic_item') { - // magic_item: attach item to character of choice, and set entry's levels to 0 - $itemData = [$itemData[0] ?? []]; - $entryData['levels'] = 0; - } elseif ($entryData->get('choice') == 'campaign_reward') { - // campaign reward: set levels = 0, no item(s), should contain custom note - $itemData = []; - $entryData['levels'] = 0; - } + list($entryData, $itemData) = $this->chooseReward($entryData, $itemData); $entry->update($entryData->toArray()); CreateEntryItems::run($entry, $itemData ?? []); $request->session()->flash('entry.id', $entry->id); + // need to find alternative to empty, this is true even if no rating_data found + if (!empty($ratingData) && is_array($ratingData)) { + CreateAndAttachRating::run($entry, $ratingData); + } + if ($request->type == Entry::TYPE_DM) { return redirect()->route('dm-entry.index'); } @@ -155,4 +150,27 @@ public function destroy(Request $request, Entry $entry) return redirect()->route('entry.index'); } + + /** + * @param Collection $entryData + * @param array $itemData + * @return array + */ + private function chooseReward(Collection $entryData, array $itemData): array + { + if ($entryData->get('choice') == 'advancement') { + // advancement: increment character's level + $entryData['levels'] = 1; + $itemData = []; + } elseif ($entryData->get('choice') == 'magic_item') { + // magic_item: attach item to character of choice, and set entry's levels to 0 + $itemData = [$itemData[0] ?? []]; + $entryData['levels'] = 0; + } elseif ($entryData->get('choice') == 'campaign_reward') { + // campaign reward: set levels = 0, no item(s), should contain custom note + $itemData = []; + $entryData['levels'] = 0; + } + return array($entryData, $itemData); + } } diff --git a/app/Http/Requests/EntryStoreRequest.php b/app/Http/Requests/EntryStoreRequest.php index 9597a8d8f..e4eb0e365 100644 --- a/app/Http/Requests/EntryStoreRequest.php +++ b/app/Http/Requests/EntryStoreRequest.php @@ -48,7 +48,8 @@ public function rules() 'items' => ['sometimes', 'array'], 'items.*.name' => ['string', 'required_with:items'], 'items.*.rarity' => ["in:{$rarities}", 'required_with:items'], - 'choice' => ['sometimes', 'nullable', 'string'] + 'choice' => ['sometimes', 'nullable', 'string'], + 'rating_data' => ['nullable', 'array'], ]; } } diff --git a/app/Http/Requests/EntryUpdateRequest.php b/app/Http/Requests/EntryUpdateRequest.php index ab607337a..31809658c 100644 --- a/app/Http/Requests/EntryUpdateRequest.php +++ b/app/Http/Requests/EntryUpdateRequest.php @@ -45,7 +45,8 @@ public function rules() 'items' => ['sometimes', 'array'], 'items.*.name' => ['string', 'required_with:items'], 'items.*.rarity' => ["in:{$rarities}", 'required_with:items'], - 'choice' => ['sometimes', 'string'] + 'choice' => ['sometimes', 'string'], + 'rating_data' => ['nullable', 'array'] ]; } } diff --git a/app/Models/User.php b/app/Models/User.php index dafa5149d..ebf780e97 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -135,7 +135,7 @@ public function getTotalRatingsAttribute() Rating::HELPFUL_LABEL, Rating::PREPARED_LABEL ]; - + $total = collect([ $labels[0] => 0, $labels[1] => 0, diff --git a/config/gravatar.php b/config/gravatar.php index 3555f1bdb..0e1379675 100644 --- a/config/gravatar.php +++ b/config/gravatar.php @@ -1,34 +1,34 @@ [ + 'default' => [ - // By default, images are presented at 80px by 80px if no size parameter is supplied. - // You may request a specific image size, which will be dynamically delivered from Gravatar - // by passing a single pixel dimension (since the images are square): - 'size' => 80, + // By default, images are presented at 80px by 80px if no size parameter is supplied. + // You may request a specific image size, which will be dynamically delivered from Gravatar + // by passing a single pixel dimension (since the images are square): + 'size' => 80, - // the fallback image, can be a string or a url - // for more info, visit: http://en.gravatar.com/site/implement/images/#default-image - 'fallback' => 'mp', + // the fallback image, can be a string or a url + // for more info, visit: http://en.gravatar.com/site/implement/images/#default-image + 'fallback' => 'mp', - // would you like to return a https://... image - 'secure' => false, + // would you like to return a https://... image + 'secure' => false, - // Gravatar allows users to self-rate their images so that they can indicate if an image - // is appropriate for a certain audience. By default, only 'G' rated images are displayed - // unless you indicate that you would like to see higher ratings. - // Available options: - // g: suitable for display on all websites with any audience type. - // pg: may contain rude gestures, provocatively dressed individuals, the lesser swear words, or mild violence. - // r: may contain such things as harsh profanity, intense violence, nudity, or hard drug use. - // x: may contain hardcore sexual imagery or extremely disturbing violence. - 'maximumRating' => 'g', + // Gravatar allows users to self-rate their images so that they can indicate if an image + // is appropriate for a certain audience. By default, only 'G' rated images are displayed + // unless you indicate that you would like to see higher ratings. + // Available options: + // g: suitable for display on all websites with any audience type. + // pg: may contain rude gestures, provocatively dressed individuals, the lesser swear words, or mild violence. + // r: may contain such things as harsh profanity, intense violence, nudity, or hard drug use. + // x: may contain hardcore sexual imagery or extremely disturbing violence. + 'maximumRating' => 'g', - // If for some reason you wanted to force the default image to always load, you can do that setting this to true - 'forceDefault' => false, + // If for some reason you wanted to force the default image to always load, you can do that setting this to true + 'forceDefault' => false, - // If you require a file-type extension (some places do) then you may also add an (optional) .jpg extension to that URL - 'forceExtension' => 'jpg', - ] + // If you require a file-type extension (some places do) then you may also add an (optional) .jpg extension to that URL + 'forceExtension' => 'jpg', + ] ]; diff --git a/tests/Feature/Http/Controllers/EntryControllerTest.php b/tests/Feature/Http/Controllers/EntryControllerTest.php index 6680b86db..70015bba7 100644 --- a/tests/Feature/Http/Controllers/EntryControllerTest.php +++ b/tests/Feature/Http/Controllers/EntryControllerTest.php @@ -8,6 +8,7 @@ use App\Models\Entry; use App\Models\Event; use App\Models\Item; +use App\Models\Rating; use App\Models\User; use Carbon\Carbon; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -190,7 +191,6 @@ public function store_saves_and_redirects() 'gp' => $gp, ]); - $entries = Entry::query() ->where('user_id', $this->user->id) ->where('adventure_id', $adventure->id) @@ -247,7 +247,7 @@ public function store_saves_entry_with_items() 'type' => $type, 'levels' => $levels, 'gp' => $gp, - 'items' => $itemData + 'items' => $itemData, ]); $entry = Entry::query() @@ -540,7 +540,7 @@ public function store_dm_entry_on_character_updates_level() 'location' => $location, 'type' => $type, 'gp' => $gp, - 'choice' => 'advancement' + 'choice' => 'advancement', ]); $character->refresh(); @@ -682,4 +682,86 @@ public function destroy_deletes_and_redirects() $this->assertDeleted($entry); } + + /** + * @test + */ + public function store_creates_rating() + { + $adventure = Adventure::factory()->create(); + $character = Character::factory()->create(['user_id' => $this->user->id]); + $dungeon_master_user = User::factory()->create(); + $dungeon_master = $this->faker->word; + $date_played = $this->faker->dateTime(); + $type = $this->faker->word; + + + $ratingData = [ + "creative" => true, + "flexible" => false, + "friendly" => true, + "helpful" => false, + "prepared" => true + ]; + + + + $response = $this->actingAs($this->user)->post(route('entry.store'), [ + 'user_id' => $this->user->id, + 'adventure_id' => $adventure->id, + 'character_id' => $character->id, + 'dungeon_master_id' => $dungeon_master_user->id, + 'dungeon_master' => $dungeon_master, + 'date_played' => $date_played, + 'type' => $type, + 'rating_data' => [ + "creative" => true, + "flexible" => false, + "friendly" => true, + "helpful" => false, + "prepared" => true + ] + ]); + + $entry = Entry::first(); + $rating = Rating::first(); + + $this->assertCount(1, Rating::all()); + $this->assertEquals(21, $rating->categories); + } + + /** + * @test + */ + public function update_creates_rating() + { + $entry = Entry::factory()->create(); + $character = Character::factory()->create(); + + $this->assertCount(0, Rating::all()); + + $character->user()->associate($this->user)->save(); + $entry->user()->associate($this->user)->save(); + $entry->character()->associate($character)->save(); + + $response = $this->actingAs($this->user)->put(route('entry.update', $entry), [ + 'adventure_id' => $entry->adventure_id, + 'character_id' => $character->id, + 'date_played' => $entry->date_played, + 'type' => $entry->type, + 'rating_data' => [ + "creative" => true, + "flexible" => false, + "friendly" => true, + "helpful" => false, + "prepared" => true + ] + ]); + + $rating = Rating::first(); + + $response->assertRedirect(); + $this->assertCount(1, Rating::all()); + $this->assertEquals(21, $rating->categories); + } }