diff --git a/app/Console/Commands/UpdateRewardMaker.php b/app/Console/Commands/UpdateRewardMaker.php new file mode 100644 index 0000000000..e724de7c08 --- /dev/null +++ b/app/Console/Commands/UpdateRewardMaker.php @@ -0,0 +1,103 @@ +info('Already ran conversions.'); + + return; + } + + if ($this->confirm('Have you migrated after installation?')) { + $this->info('If you have edited the reward maker to include custom reward types and other object support, ensure that they have been added to the UpdateRewardMaker command file or errors and data loss may occur.'); + if ($this->confirm('Have you either edited the UpdateRewardMaker file to include your edits, or not edited the reward maker at all?')) { + $this->info('Converting rewards.'); + $rewards = DB::table('prompt_rewards')->get(); + + foreach ($rewards as $promptreward) { + $rewardmodel = getAssetModelString(strtolower($promptreward->rewardable_type)); + + $newreward = ObjectReward::create([ + 'object_id' => $promptreward->prompt_id, + 'object_type' => 'App\Models\Prompt\Prompt', + 'rewardable_type' => $rewardmodel, + 'rewardable_id' => $promptreward->rewardable_id, + 'quantity' => $promptreward->quantity, + 'recipient_type' => 'User', + 'reward_key' => 'objectRewards', + ]); + + if (!$newreward) { + $this->error('Error. Skipping prompt reward for prompt: '.$promptreward->prompt->name); + } + } + $this->info('Dropping prompt rewards'); + Schema::dropIfExists('prompt_rewards'); + + $this->info('Converting any existing rewards...'); + + $objrewards = ObjectReward::all(); + + foreach ($objrewards as $reward) { + switch ($reward->object_type) { + case 'Questline': + $objmodel = 'App\Models\Questline\Questline'; + break; + case 'Prompt': + $objmodel = 'App\Models\Prompt\Prompt'; + break; + } + + switch ($reward->recipient_type) { + case 'User': + $key = 'objectRewards'; + break; + case 'Character': + $key = 'objectCharacterRewards'; + break; + } + + $reward->update([ + 'rewardable_type' => getAssetModelString(strtolower($reward->rewardable_type)), + 'object_type' => $objmodel, + 'reward_key' => $key, + ]); + } + + $this->info('Converted rewards successfully. Happy Lorekeeping! :)'); + } else { + $this->error('Please edit the file to ensure the conversion goes smoothly.'); + + return; + } + } else { + $this->info('Migrating DB. After this is complete, run this command again and confirm that you have to continue.'); + $this->call('migrate'); + $this->info('Migrations complete. Please run the command again to continue.'); + } + } +} diff --git a/app/Helpers/AssetHelpers.php b/app/Helpers/AssetHelpers.php index c870b91f35..9296b1d275 100644 --- a/app/Helpers/AssetHelpers.php +++ b/app/Helpers/AssetHelpers.php @@ -89,7 +89,7 @@ function getAssetKeys($isCharacter = false) { */ function getAssetModelString($type, $namespaced = true) { switch ($type) { - case 'items': + case 'items': case 'item': if ($namespaced) { return '\App\Models\Item\Item'; } else { @@ -97,7 +97,7 @@ function getAssetModelString($type, $namespaced = true) { } break; - case 'currencies': + case 'currencies': case 'currency': if ($namespaced) { return '\App\Models\Currency\Currency'; } else { @@ -105,7 +105,7 @@ function getAssetModelString($type, $namespaced = true) { } break; - case 'raffle_tickets': + case 'raffle_tickets': case 'raffle': if ($namespaced) { return '\App\Models\Raffle\Raffle'; } else { @@ -113,7 +113,7 @@ function getAssetModelString($type, $namespaced = true) { } break; - case 'loot_tables': + case 'loot_tables': case 'loottable': if ($namespaced) { return '\App\Models\Loot\LootTable'; } else { @@ -171,11 +171,12 @@ function createAssetsArray($isCharacter = false) { * * @param array $first * @param array $second + * @param mixed $isCharacter * * @return array */ -function mergeAssetsArrays($first, $second) { - $keys = getAssetKeys(); +function mergeAssetsArrays($first, $second, $isCharacter = false) { + $keys = getAssetKeys($isCharacter); foreach ($keys as $key) { foreach ($second[$key] as $item) { addAsset($first, $item['asset'], $item['quantity']); @@ -253,11 +254,12 @@ function getDataReadyAssets($array, $isCharacter = false) { * Use the data attribute after json_decode()ing it. * * @param array $array + * @param mixed $isCharacter * * @return array */ -function parseAssetData($array) { - $assets = createAssetsArray(); +function parseAssetData($array, $isCharacter = false) { + $assets = createAssetsArray($isCharacter); foreach ($array as $key => $contents) { $model = getAssetModelString($key); if ($model) { diff --git a/app/Helpers/Helpers.php b/app/Helpers/Helpers.php index b3507768a4..6b37ad916d 100644 --- a/app/Helpers/Helpers.php +++ b/app/Helpers/Helpers.php @@ -472,3 +472,19 @@ function faVersion() { return asset($directory.'/'.$version.'.min.css'); } + +/** + * Get the object's rewards. + * + * @param mixed $object + * @param mixed $key + * @param mixed $recipient + */ +function objectRewards($object, $key, $recipient) { + return App\Models\ObjectReward::where([ + ['object_type', get_class($object)], + ['object_id', $object->id], + ['recipient_type', $recipient], + ['reward_key', $key], + ])->get(); +} diff --git a/app/Http/Controllers/Admin/Data/PromptController.php b/app/Http/Controllers/Admin/Data/PromptController.php index ed19ceb6d2..086f863123 100644 --- a/app/Http/Controllers/Admin/Data/PromptController.php +++ b/app/Http/Controllers/Admin/Data/PromptController.php @@ -210,7 +210,7 @@ public function getEditPrompt($id) { public function postCreateEditPrompt(Request $request, PromptService $service, $id = null) { $id ? $request->validate(Prompt::$updateRules) : $request->validate(Prompt::$createRules); $data = $request->only([ - 'name', 'prompt_category_id', 'summary', 'description', 'start_at', 'end_at', 'hide_before_start', 'hide_after_end', 'is_active', 'rewardable_type', 'rewardable_id', 'quantity', 'image', 'remove_image', 'prefix', 'hide_submissions', 'staff_only', + 'name', 'prompt_category_id', 'summary', 'description', 'start_at', 'end_at', 'hide_before_start', 'hide_after_end', 'is_active', 'image', 'remove_image', 'prefix', 'hide_submissions', 'staff_only', ]); if ($id && $service->updatePrompt(Prompt::find($id), $data, Auth::user())) { flash('Prompt updated successfully.')->success(); diff --git a/app/Http/Controllers/Admin/Data/RewardController.php b/app/Http/Controllers/Admin/Data/RewardController.php new file mode 100644 index 0000000000..fb17b51ad5 --- /dev/null +++ b/app/Http/Controllers/Admin/Data/RewardController.php @@ -0,0 +1,49 @@ +only([ + 'rewardable_type', 'rewardable_id', 'reward_quantity', 'recipient_type', 'reward_key', + ]); + + if ($id && $service->editRewards($object, $data)) { + flash('Rewards updated successfully.')->success(); + } else { + foreach ($service->errors()->getMessages()['error'] as $error) { + flash($error)->error(); + } + } + + return redirect()->back(); + } +} diff --git a/app/Http/Controllers/Admin/SubmissionController.php b/app/Http/Controllers/Admin/SubmissionController.php index 85d02b7749..08e40dcc67 100644 --- a/app/Http/Controllers/Admin/SubmissionController.php +++ b/app/Http/Controllers/Admin/SubmissionController.php @@ -152,7 +152,7 @@ public function getClaim($id) { * @return \Illuminate\Http\RedirectResponse */ public function postSubmission(Request $request, SubmissionManager $service, $id, $action) { - $data = $request->only(['slug', 'character_rewardable_quantity', 'character_rewardable_id', 'character_rewardable_type', 'character_currency_id', 'rewardable_type', 'rewardable_id', 'quantity', 'staff_comments']); + $data = $request->only(['slug', 'character_rewardable_quantity', 'character_rewardable_id', 'character_rewardable_type', 'character_currency_id', 'rewardable_type', 'rewardable_id', 'quantity', 'staff_comments', 'character_is_focus']); if ($action == 'reject' && $service->rejectSubmission($request->only(['staff_comments']) + ['id' => $id], Auth::user())) { flash('Submission rejected successfully.')->success(); } elseif ($action == 'cancel' && $service->cancelSubmission($request->only(['staff_comments']) + ['id' => $id], Auth::user())) { diff --git a/app/Http/Controllers/Users/SubmissionController.php b/app/Http/Controllers/Users/SubmissionController.php index 780e7ba76a..2c026fbdc6 100644 --- a/app/Http/Controllers/Users/SubmissionController.php +++ b/app/Http/Controllers/Users/SubmissionController.php @@ -212,7 +212,7 @@ public function postNewSubmission(Request $request, SubmissionManager $service, $request->only([ 'url', 'prompt_id', 'comments', 'slug', 'character_rewardable_type', 'character_rewardable_id', 'character_rewardable_quantity', 'rewardable_type', 'rewardable_id', 'quantity', 'stack_id', 'stack_quantity', 'currency_id', 'currency_quantity', - 'gallery_submission_id', + 'gallery_submission_id', 'character_is_focus', ]), Auth::user(), false, @@ -257,13 +257,13 @@ public function postEditSubmission(Request $request, SubmissionManager $service, if ($submit && $service->editSubmission($submission, $request->only([ 'url', 'prompt_id', 'comments', 'slug', 'character_rewardable_type', 'character_rewardable_id', 'character_rewardable_quantity', 'rewardable_type', 'rewardable_id', 'quantity', 'stack_id', 'stack_quantity', 'currency_id', 'currency_quantity', - 'gallery_submission_id', + 'gallery_submission_id', 'character_is_focus', ]), Auth::user(), false, $submit)) { flash('Draft submitted successfully.')->success(); } elseif ($service->editSubmission($submission, $request->only([ 'url', 'prompt_id', 'comments', 'slug', 'character_rewardable_type', 'character_rewardable_id', 'character_rewardable_quantity', 'rewardable_type', 'rewardable_id', 'quantity', 'stack_id', 'stack_quantity', 'currency_id', 'currency_quantity', - 'gallery_submission_id', + 'gallery_submission_id', 'character_is_focus', ]), Auth::user())) { flash('Draft saved successfully.')->success(); diff --git a/app/Models/ObjectReward.php b/app/Models/ObjectReward.php new file mode 100644 index 0000000000..31ffe29d9a --- /dev/null +++ b/app/Models/ObjectReward.php @@ -0,0 +1,46 @@ +morphTo(__FUNCTION__, 'object_type', 'object_id'); + } + + /** + * Get the reward attached to the prompt reward. + */ + public function reward() { + return $this->morphTo(__FUNCTION__, 'rewardable_type', 'rewardable_id'); + } + + /** + * Get the reward type so we don't have to do the no-no of model names in forms. + */ + public function rewardType() { + return class_basename($this->rewardable_type); + } +} diff --git a/app/Models/Prompt/Prompt.php b/app/Models/Prompt/Prompt.php index 5a79c97d1b..fe369d824d 100644 --- a/app/Models/Prompt/Prompt.php +++ b/app/Models/Prompt/Prompt.php @@ -3,6 +3,7 @@ namespace App\Models\Prompt; use App\Models\Model; +use App\Models\ObjectReward; use Carbon\Carbon; class Prompt extends Model { @@ -78,8 +79,23 @@ public function category() { /** * Get the rewards attached to this prompt. */ - public function rewards() { - return $this->hasMany(PromptReward::class, 'prompt_id'); + public function objectRewards() { + return $this->hasMany(ObjectReward::class, 'object_id')->where([ + ['object_type', get_class($this)], + ['recipient_type', 'User'], + ['reward_key', 'objectRewards'], + ]); + } + + /** + * Get the rewards attached to this prompt. + */ + public function objectCharacterRewards() { + return $this->hasMany(ObjectReward::class, 'object_id')->where([ + ['object_type', get_class($this)], + ['recipient_type', 'Character'], + ['reward_key', 'objectCharacterRewards'], + ]); } /********************************************************************************************** diff --git a/app/Models/Prompt/PromptReward.php b/app/Models/Prompt/PromptReward.php deleted file mode 100644 index 15512ec071..0000000000 --- a/app/Models/Prompt/PromptReward.php +++ /dev/null @@ -1,76 +0,0 @@ - 'required', - 'rewardable_id' => 'required', - 'quantity' => 'required|integer|min:1', - ]; - - /** - * Validation rules for updating. - * - * @var array - */ - public static $updateRules = [ - 'rewardable_type' => 'required', - 'rewardable_id' => 'required', - 'quantity' => 'required|integer|min:1', - ]; - - /********************************************************************************************** - - RELATIONS - - **********************************************************************************************/ - - /** - * Get the reward attached to the prompt reward. - */ - public function reward() { - switch ($this->rewardable_type) { - case 'Item': - return $this->belongsTo(Item::class, 'rewardable_id'); - break; - case 'Currency': - return $this->belongsTo(Currency::class, 'rewardable_id'); - break; - case 'LootTable': - return $this->belongsTo(LootTable::class, 'rewardable_id'); - break; - case 'Raffle': - return $this->belongsTo(Raffle::class, 'rewardable_id'); - break; - } - - return null; - } -} diff --git a/app/Models/Submission/SubmissionCharacter.php b/app/Models/Submission/SubmissionCharacter.php index 006adccdc6..f649b8f7ae 100644 --- a/app/Models/Submission/SubmissionCharacter.php +++ b/app/Models/Submission/SubmissionCharacter.php @@ -12,7 +12,7 @@ class SubmissionCharacter extends Model { * @var array */ protected $fillable = [ - 'submission_id', 'character_id', 'data', + 'submission_id', 'character_id', 'data', 'is_focus', ]; /** diff --git a/app/Services/LootService.php b/app/Services/LootService.php index c615a8ed6b..4ff0e18fc3 100644 --- a/app/Services/LootService.php +++ b/app/Services/LootService.php @@ -4,7 +4,7 @@ use App\Models\Loot\Loot; use App\Models\Loot\LootTable; -use App\Models\Prompt\PromptReward; +use App\Models\ObjectReward; use Illuminate\Support\Arr; use Illuminate\Support\Facades\DB; @@ -127,7 +127,7 @@ public function deleteLootTable($table) { // Check first if the table is currently in use // - Prompts // - Box rewards (unfortunately this can't be checked easily) - if (PromptReward::where('rewardable_type', 'LootTable')->where('rewardable_id', $table->id)->exists()) { + if (ObjectReward::where('rewardable_type', '\App\Models\Loot\LootTable')->where('rewardable_id', $table->id)->exists()) { throw new \Exception('A prompt uses this table to distribute rewards. Please remove it from the rewards list first.'); } diff --git a/app/Services/PromptService.php b/app/Services/PromptService.php index 44127055c8..88631e6ede 100644 --- a/app/Services/PromptService.php +++ b/app/Services/PromptService.php @@ -4,7 +4,6 @@ use App\Models\Prompt\Prompt; use App\Models\Prompt\PromptCategory; -use App\Models\Prompt\PromptReward; use App\Models\Submission\Submission; use Illuminate\Support\Arr; use Illuminate\Support\Facades\DB; @@ -208,8 +207,6 @@ public function createPrompt($data, $user) { $this->handleImage($image, $prompt->imagePath, $prompt->imageFileName); } - $this->populateRewards(Arr::only($data, ['rewardable_type', 'rewardable_id', 'quantity']), $prompt); - return $this->commitReturn($prompt); } catch (\Exception $e) { $this->setError('error', $e->getMessage()); @@ -266,8 +263,6 @@ public function updatePrompt($prompt, $data, $user) { $this->handleImage($image, $prompt->imagePath, $prompt->imageFileName); } - $this->populateRewards(Arr::only($data, ['rewardable_type', 'rewardable_id', 'quantity']), $prompt); - return $this->commitReturn($prompt); } catch (\Exception $e) { $this->setError('error', $e->getMessage()); @@ -292,7 +287,6 @@ public function deletePrompt($prompt) { throw new \Exception('A submission under this prompt exists. Deleting the prompt will break the submission page - consider setting the prompt to be not active instead.'); } - $prompt->rewards()->delete(); if ($prompt->has_image) { $this->deleteImage($prompt->imagePath, $prompt->imageFileName); } @@ -368,26 +362,4 @@ private function populateData($data, $prompt = null) { return $data; } - - /** - * Processes user input for creating/updating prompt rewards. - * - * @param array $data - * @param Prompt $prompt - */ - private function populateRewards($data, $prompt) { - // Clear the old rewards... - $prompt->rewards()->delete(); - - if (isset($data['rewardable_type'])) { - foreach ($data['rewardable_type'] as $key => $type) { - PromptReward::create([ - 'prompt_id' => $prompt->id, - 'rewardable_type' => $type, - 'rewardable_id' => $data['rewardable_id'][$key], - 'quantity' => $data['quantity'][$key], - ]); - } - } - } } diff --git a/app/Services/RewardManager.php b/app/Services/RewardManager.php new file mode 100644 index 0000000000..33acfbc5bd --- /dev/null +++ b/app/Services/RewardManager.php @@ -0,0 +1,126 @@ +delete(); + } + + if (isset($data['rewardable_type'])) { + foreach ($data['rewardable_type'] as $key => $type) { + $model = strtolower($type); + + ObjectReward::create([ + 'object_id' => $object->id, + 'object_type' => get_class($object), + 'rewardable_type' => getAssetModelString($model), + 'rewardable_id' => $data['rewardable_id'][$key] ?? null, + 'quantity' => $data['reward_quantity'][$key], + 'recipient_type' => $data['recipient_type'], + 'reward_key' => $data['reward_key'], + ]); + } + } + + return $this->commitReturn(true); + } catch (\Exception $e) { + $this->setError('error', $e->getMessage()); + } + + return $this->rollbackReturn(false); + } + + /** + * Grant rewards. + * + * @param array $data + * @param \App\Models\User\User $user + * @param mixed $object + * @param mixed $recipient + * @param mixed $isCharacter + * + * @return mixed + */ + public function grantRewards($object, $user, $recipient, $data, $isCharacter = false) { + DB::beginTransaction(); + + try { + if (!$object) { + throw new \Exception('Invalid object.'); + } + + if (!$recipient) { + throw new \Exception('Invalid recipient.'); + } + + if ($isCharacter) { + $recipient_type = 'Character'; + } else { + $recipient_type = 'User'; + } + + $rewards = createAssetsArray(); + + foreach (objectRewards($object, $data['reward_key'], $recipient_type) as $reward) { + addAsset($rewards, $reward->reward, $reward->quantity); + } + + if ($isCharacter) { + // Distribute character rewards + if (!($rewards = fillCharacterAssets($rewards, null, $recipient, $data['log_type'], $data['log_data'], $user))) { + throw new \Exception('Failed to distribute rewards to character.'); + } + } else { + // Distribute user rewards + if (!($rewards = fillUserAssets($rewards, null, $recipient, $data['log_type'], $data['log_data']))) { + throw new \Exception('Failed to distribute rewards to user.'); + } + } + + if (isset($data['flash_rewards']) && $data['flash_rewards'] == 1) { + flash(createRewardsString($rewards))->success(); + } + + flash(($isCharacter ? 'Character' : 'User').' rewards granted successfully.')->success(); + + return $this->commitReturn(true); + } catch (\Exception $e) { + $this->setError('error', $e->getMessage()); + } + + return $this->rollbackReturn(false); + } +} diff --git a/app/Services/SubmissionManager.php b/app/Services/SubmissionManager.php index 71dbefa053..3efd018f42 100644 --- a/app/Services/SubmissionManager.php +++ b/app/Services/SubmissionManager.php @@ -26,7 +26,7 @@ class SubmissionManager extends Service { | | Handles creation and modification of submission data. | - */ + */ /** * Creates a new submission. @@ -54,7 +54,7 @@ public function createSubmission($data, $user, $isClaim = false, $isDraft = fals throw new \Exception('Please select a prompt.'); } if (!$isClaim) { - $prompt = Prompt::active()->where('id', $data['prompt_id'])->with('rewards')->first(); + $prompt = Prompt::active()->where('id', $data['prompt_id'])->with('objectRewards')->first(); if (!$prompt) { throw new \Exception('Invalid prompt selected.'); } @@ -68,11 +68,11 @@ public function createSubmission($data, $user, $isClaim = false, $isDraft = fals // Create the submission itself. $submission = Submission::create([ - 'user_id' => $user->id, - 'url' => $data['url'] ?? null, - 'status' => $isDraft ? 'Draft' : 'Pending', - 'comments' => $data['comments'], - 'data' => null, + 'user_id' => $user->id, + 'url' => $data['url'] ?? null, + 'status' => $isDraft ? 'Draft' : 'Pending', + 'comments' => $data['comments'], + 'data' => null, ] + ($isClaim ? [] : [ 'prompt_id' => $prompt->id, ])); @@ -127,7 +127,7 @@ public function editSubmission($submission, $data, $user, $isClaim = false, $isS throw new \Exception('Please select a prompt.'); } if (!$isClaim) { - $prompt = Prompt::active()->where('id', $data['prompt_id'])->with('rewards')->first(); + $prompt = Prompt::active()->where('id', $data['prompt_id'])->with('objectRewards')->first(); if (!$prompt) { throw new \Exception('Invalid prompt selected.'); } @@ -152,12 +152,12 @@ public function editSubmission($submission, $data, $user, $isClaim = false, $isS // Modify submission $submission->update([ - 'url' => $data['url'] ?? null, - 'updated_at' => Carbon::now(), - 'comments' => $data['comments'], - 'data' => json_encode([ - 'user' => Arr::only(getDataReadyAssets($userAssets), ['user_items', 'currencies']), - 'rewards' => getDataReadyAssets($promptRewards), + 'url' => $data['url'] ?? null, + 'updated_at' => Carbon::now(), + 'comments' => $data['comments'], + 'data' => json_encode([ + 'user' => Arr::only(getDataReadyAssets($userAssets), ['user_items', 'currencies']), + 'rewards' => getDataReadyAssets($promptRewards), ] + (config('lorekeeper.settings.allow_gallery_submissions_on_prompts') ? ['gallery_submission_id' => $data['gallery_submission_id'] ?? null] : [])), ] + ($isClaim ? [] : ['prompt_id' => $prompt->id])); @@ -203,6 +203,13 @@ public function cancelSubmission($data, $user) { $userAssets = $assets['user']; // Remove prompt-only rewards $promptRewards = $this->removePromptAttachments($submission); + // ...aaand the same for characters + if ($submission->characters()->count()) { + foreach ($submission->characters as $character) { + $characterPromptRewards = $this->removeCharacterPromptAttachments($submission, $character); + $character->update(['data' => json_encode(getDataReadyAssets($characterPromptRewards))]); + } + } if ($user->id != $submission->user_id) { // The only things we need to set are: @@ -350,7 +357,7 @@ public function approveSubmission($data, $user) { // Workaround for user not being unset after inventory shuffling, preventing proper staff ID assignment $staff = $user; - foreach ($stacks as $stackId=> $quantity) { + foreach ($stacks as $stackId => $quantity) { $stack = UserItem::find($stackId); $user = User::find($submission->user_id); if (!$inventoryManager->debitStack($user, $submission->prompt_id ? 'Prompt Approved' : 'Claim Approved', ['data' => 'Item used in submission (#'.$submission->id.')'], $stack, $quantity)) { @@ -365,7 +372,7 @@ public function approveSubmission($data, $user) { // Log currency removal, etc. $currencyManager = new CurrencyManager; if (isset($addonData['currencies']) && $addonData['currencies']) { - foreach ($addonData['currencies'] as $currencyId=> $quantity) { + foreach ($addonData['currencies'] as $currencyId => $quantity) { $currency = Currency::find($currencyId); if (!$currencyManager->createLog( $submission->user_id, @@ -422,13 +429,13 @@ public function approveSubmission($data, $user) { } elseif (isset($data['character_rewardable_id'])) { $data['character_rewardable_id'] = array_map([$this, 'innerNull'], $data['character_rewardable_id']); foreach ($data['character_rewardable_id'] as $ckey => $c) { - foreach ($c as $key => $id) { + foreach ($c as $key => $id) { switch ($data['character_rewardable_type'][$ckey][$key]) { - case 'Currency': $currencyIds[] = $id; + case 'Currency':$currencyIds[] = $id; break; - case 'Item': $itemIds[] = $id; + case 'Item':$itemIds[] = $id; break; - case 'LootTable': $tableIds[] = $id; + case 'LootTable':$tableIds[] = $id; break; } } @@ -587,15 +594,15 @@ private function processRewards($data, $isCharacter, $isStaff = false, $isClaim foreach ($data['character_rewardable_id'][$data['character_id']] as $key => $reward) { switch ($data['character_rewardable_type'][$data['character_id']][$key]) { - case 'Currency': if ($data['character_rewardable_quantity'][$data['character_id']][$key]) { + case 'Currency':if ($data['character_rewardable_quantity'][$data['character_id']][$key]) { addAsset($assets, $data['currencies'][$reward], $data['character_rewardable_quantity'][$data['character_id']][$key]); - } break; - case 'Item': if ($data['character_rewardable_quantity'][$data['character_id']][$key]) { + }break; + case 'Item':if ($data['character_rewardable_quantity'][$data['character_id']][$key]) { addAsset($assets, $data['items'][$reward], $data['character_rewardable_quantity'][$data['character_id']][$key]); - } break; - case 'LootTable': if ($data['character_rewardable_quantity'][$data['character_id']][$key]) { + }break; + case 'LootTable':if ($data['character_rewardable_quantity'][$data['character_id']][$key]) { addAsset($assets, $data['tables'][$reward], $data['character_rewardable_quantity'][$data['character_id']][$key]); - } break; + }break; } } } @@ -677,7 +684,7 @@ private function createUserAttachments($submission, $data, $user) { // Attach currencies. if (isset($data['currency_id'])) { - foreach ($data['currency_id'] as $holderKey=>$currencyIds) { + foreach ($data['currency_id'] as $holderKey => $currencyIds) { $holder = explode('-', $holderKey); $holderType = $holder[0]; $holderId = $holder[1]; @@ -685,7 +692,7 @@ private function createUserAttachments($submission, $data, $user) { $holder = User::find($holderId); $currencyManager = new CurrencyManager; - foreach ($currencyIds as $key=>$currencyId) { + foreach ($currencyIds as $key => $currencyId) { $currency = Currency::find($currencyId); if (!$currency) { throw new \Exception('Invalid currency selected.'); @@ -705,7 +712,7 @@ private function createUserAttachments($submission, $data, $user) { // Get a list of rewards, then create the submission itself $promptRewards = createAssetsArray(); if ($submission->status == 'Pending' && isset($submission->prompt_id) && $submission->prompt_id) { - foreach ($submission->prompt->rewards as $reward) { + foreach ($submission->prompt->objectRewards as $reward) { addAsset($promptRewards, $reward->reward, $reward->quantity); } } @@ -728,7 +735,27 @@ private function removePromptAttachments($submission) { $promptRewards = createAssetsArray(); $promptRewards = mergeAssetsArrays($promptRewards, parseAssetData($assets['rewards'])); if (isset($submission->prompt_id) && $submission->prompt_id) { - foreach ($submission->prompt->rewards as $reward) { + foreach ($submission->prompt->objectRewards as $reward) { + removeAsset($promptRewards, $reward->reward, $reward->quantity); + } + } + + return $promptRewards; + } + + /** + * Removes the attachments associated with a prompt from a submission. + * + * @param mixed $submission the submission object + * @param mixed $character + */ + private function removeCharacterPromptAttachments($submission, $character) { + $assets = $character->data; + // Get a list of rewards, then create the submission itself + $promptRewards = createAssetsArray(true); + $promptRewards = mergeAssetsArrays($promptRewards, parseAssetData($assets, true), true); + if (isset($submission->prompt_id) && $submission->prompt_id) { + foreach ($submission->prompt->objectCharacterRewards as $reward) { removeAsset($promptRewards, $reward->reward, $reward->quantity); } } @@ -771,11 +798,11 @@ private function createCharacterAttachments($submission, $data) { foreach ($data['character_rewardable_id'] as $ckey => $c) { foreach ($c as $key => $id) { switch ($data['character_rewardable_type'][$ckey][$key]) { - case 'Currency': $currencyIds[] = $id; + case 'Currency':$currencyIds[] = $id; break; - case 'Item': $itemIds[] = $id; + case 'Item':$itemIds[] = $id; break; - case 'LootTable': $tableIds[] = $id; + case 'LootTable':$tableIds[] = $id; break; } } @@ -793,12 +820,25 @@ private function createCharacterAttachments($submission, $data) { // Users might not pass in clean arrays (may contain redundant data) so we need to clean that up $assets = $this->processRewards($data + ['character_id' => $c->id, 'currencies' => $currencies, 'items' => $items, 'tables' => $tables], true); + // add the preset character rewards with any character rewards in data + if ($submission->status == 'Pending' && isset($submission->prompt_id) && $submission->prompt_id && $submission->prompt->objectCharacterRewards->count() && isset($data['character_is_focus']) && $data['character_is_focus'][$c->id]) { + // Get a list of rewards + $defaultRewards = createAssetsArray(true); + // add to array + foreach ($submission->prompt->objectCharacterRewards as $reward) { + addAsset($defaultRewards, $reward->reward, $reward->quantity); + } + // merge with the cleaned up user-set stuff + $assets = mergeAssetsArrays($defaultRewards, $assets, true); + } + // Now we have a clean set of assets (redundant data is gone, duplicate entries are merged) // so we can attach the character to the submission SubmissionCharacter::create([ 'character_id' => $c->id, 'submission_id' => $submission->id, 'data' => json_encode(getDataReadyAssets($assets)), + 'is_focus' => isset($data['character_is_focus']) && $data['character_is_focus'][$c->id] ? $data['character_is_focus'][$c->id] : 0, ]); } @@ -832,7 +872,7 @@ private function removeAttachments($submission) { // And currencies $currencyManager = new CurrencyManager; if (isset($addonData['currencies']) && $addonData['currencies']) { - foreach ($addonData['currencies'] as $currencyId=>$quantity) { + foreach ($addonData['currencies'] as $currencyId => $quantity) { $currency = Currency::find($currencyId); if (!$currency) { throw new \Exception('Cannot return an invalid currency. ('.$currencyId.')'); diff --git a/database/migrations/2021_07_06_152047_change_focus_character_structure.php b/database/migrations/2021_07_06_152047_change_focus_character_structure.php new file mode 100644 index 0000000000..9b2edd39ce --- /dev/null +++ b/database/migrations/2021_07_06_152047_change_focus_character_structure.php @@ -0,0 +1,27 @@ +boolean('is_focus')->default(0); + }); + } + + /** + * Reverse the migrations. + */ + public function down() { + // + Schema::table('submission_characters', function (Blueprint $table) { + $table->dropColumn('is_focus'); + }); + } +} diff --git a/database/migrations/2024_07_15_214139_add_pluggable_rewards.php b/database/migrations/2024_07_15_214139_add_pluggable_rewards.php new file mode 100644 index 0000000000..d98f56b890 --- /dev/null +++ b/database/migrations/2024_07_15_214139_add_pluggable_rewards.php @@ -0,0 +1,28 @@ +increments('id'); + $table->integer('object_id'); + $table->string('object_type'); + $table->integer('rewardable_id'); + $table->string('rewardable_type')->default('Item'); + $table->integer('quantity')->unsigned(); + }); + } + + /** + * Reverse the migrations. + */ + public function down() { + Schema::dropIfExists('object_rewards'); + } +} diff --git a/database/migrations/2024_10_13_213812_add_character_rewards.php b/database/migrations/2024_10_13_213812_add_character_rewards.php new file mode 100644 index 0000000000..c28f3d8db1 --- /dev/null +++ b/database/migrations/2024_10_13_213812_add_character_rewards.php @@ -0,0 +1,23 @@ +string('earner_type')->default('User'); + }); + } + + /** + * Reverse the migrations. + */ + public function down() { + // + } +} diff --git a/database/migrations/2024_10_18_023955_update_reward_maker.php b/database/migrations/2024_10_18_023955_update_reward_maker.php new file mode 100644 index 0000000000..1509e3de74 --- /dev/null +++ b/database/migrations/2024_10_18_023955_update_reward_maker.php @@ -0,0 +1,25 @@ +renameColumn('earner_type', 'recipient_type'); + }); + } + + /** + * Reverse the migrations. + */ + public function down() { + Schema::table('object_rewards', function (Blueprint $table) { + $table->renameColumn('recipient_type', 'earner_type'); + }); + } +} diff --git a/database/migrations/2024_10_21_003129_add_reward_key.php b/database/migrations/2024_10_21_003129_add_reward_key.php new file mode 100644 index 0000000000..4255d9d5ab --- /dev/null +++ b/database/migrations/2024_10_21_003129_add_reward_key.php @@ -0,0 +1,25 @@ +string('reward_key')->default('objectRewards'); + }); + } + + /** + * Reverse the migrations. + */ + public function down() { + Schema::table('object_rewards', function (Blueprint $table) { + $table->dropColumn('reward_key'); + }); + } +} diff --git a/resources/views/admin/prompts/create_edit_prompt.blade.php b/resources/views/admin/prompts/create_edit_prompt.blade.php index 0c522b9dcd..a5a779679a 100644 --- a/resources/views/admin/prompts/create_edit_prompt.blade.php +++ b/resources/views/admin/prompts/create_edit_prompt.blade.php @@ -93,18 +93,31 @@ {!! Form::select('hide_submissions', [0 => 'Submissions Visible After Approval', 1 => 'Hide Submissions Until Prompt Ends', 2 => 'Hide Submissions Always'], $prompt->hide_submissions, ['class' => 'form-control']) !!} -

Rewards

-

Rewards are credited on a per-user basis. Mods are able to modify the specific rewards granted at approval time.

-

You can add loot tables containing any kind of currencies (both user- and character-attached), but be sure to keep track of which are being distributed! Character-only currencies cannot be given to users.

- @include('widgets._loot_select', ['loots' => $prompt->rewards, 'showLootTables' => true, 'showRaffles' => true]) -
{!! Form::submit($prompt->id ? 'Edit' : 'Create', ['class' => 'btn btn-primary']) !!}
{!! Form::close() !!} - @include('widgets._loot_select_row', ['showLootTables' => true, 'showRaffles' => true]) +

Rewards

+

Mods are able to modify the specific rewards granted at approval time.

+

You can add loot tables containing any kind of currencies (both user- and character-attached), but be sure to keep track of which are being distributed! Character-only currencies cannot be given to users.

+ + @include('widgets._reward_maker', [ + 'object' => $prompt, + 'type' => 'prompt', + 'recipient' => 'User', + 'reward_key' => 'objectRewards', + 'info' => 'Rewards are credited on a per-user basis.', + ]) + + @include('widgets._reward_maker', [ + 'object' => $prompt, + 'type' => 'prompt', + 'recipient' => 'Character', + 'reward_key' => 'objectCharacterRewards', + 'info' => 'Character rewards are only credited to the focus characters of a submission, both users and moderators can add and edit this status. There can be multiple focus characters.', + ]) @if ($prompt->id)

Preview

@@ -118,7 +131,6 @@ @section('scripts') @parent - @include('js._loot_js', ['showLootTables' => true, 'showRaffles' => true]) @include('widgets._datetimepicker_js') +@endif diff --git a/routes/lorekeeper/admin.php b/routes/lorekeeper/admin.php index 54de20aed3..e23f16d272 100644 --- a/routes/lorekeeper/admin.php +++ b/routes/lorekeeper/admin.php @@ -256,6 +256,9 @@ Route::post('prompts/create', 'PromptController@postCreateEditPrompt'); Route::post('prompts/edit/{id?}', 'PromptController@postCreateEditPrompt'); Route::post('prompts/delete/{id}', 'PromptController@postDeletePrompt'); + + // REWARD MAKER + Route::post('reward-maker/edit/{model}/{id}', 'RewardController@editReward'); }); // PAGES