Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement action to create dm rating upon entry store/update #257

Merged
merged 10 commits into from
Jan 12, 2022
48 changes: 48 additions & 0 deletions app/Actions/CreateAndAttachRating.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace App\Actions;

use App\Models\Entry;
use App\Models\Rating;
use Illuminate\Support\Facades\Auth;
use Lorisleiva\Actions\Concerns\AsAction;

class CreateAndAttachRating
{
use AsAction;

/**
* Expect an array of rating_data, create Rating and modify categories as required
*
* @param Entry $entry
* @param array $ratingData
*/
public function handle(Entry $entry, array $ratingData)
{
$rating = Rating::create([
m-triassi marked this conversation as resolved.
Show resolved Hide resolved
'entry_id' => $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;
}
}
80 changes: 50 additions & 30 deletions app/Http/Controllers/EntryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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'];
Expand All @@ -53,26 +60,18 @@ 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;
}
//run tests to make sure this works
m-triassi marked this conversation as resolved.
Show resolved Hide resolved
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');
}
Expand Down Expand Up @@ -107,8 +106,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'];
Expand All @@ -118,25 +122,18 @@ 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;
}
//run tests to make sure this works
m-triassi marked this conversation as resolved.
Show resolved Hide resolved
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');
}
Expand All @@ -155,4 +152,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);
}
}
3 changes: 2 additions & 1 deletion app/Http/Requests/EntryStoreRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
];
}
}
3 changes: 2 additions & 1 deletion app/Http/Requests/EntryUpdateRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']
];
}
}
2 changes: 1 addition & 1 deletion app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public function getTotalRatingsAttribute()
Rating::HELPFUL_LABEL,
Rating::PREPARED_LABEL
];

$total = collect([
$labels[0] => 0,
$labels[1] => 0,
Expand Down
48 changes: 24 additions & 24 deletions config/gravatar.php
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
<?php

return [
'default' => [
'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',
]
];
88 changes: 85 additions & 3 deletions tests/Feature/Http/Controllers/EntryControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -247,7 +247,7 @@ public function store_saves_entry_with_items()
'type' => $type,
'levels' => $levels,
'gp' => $gp,
'items' => $itemData
'items' => $itemData,
]);

$entry = Entry::query()
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}