From 63395481f748e674ec269122a4ff4fb75dcd86cb Mon Sep 17 00:00:00 2001 From: Kyrch Date: Fri, 16 May 2025 08:05:31 -0300 Subject: [PATCH] feat: added likes support (#819) --- .../Aggregate/SyncLikeAggregatesAction.php | 47 ++++++++++ .../SyncViewAggregatesAction.php | 2 +- .../Storage/Admin/Dump/DumpAdminAction.php | 2 - .../Storage/Admin/Dump/DumpViewAction.php | 2 +- .../Models/Aggregate/AggregatesLike.php | 29 ++++++ .../{Service => Aggregate}/AggregatesView.php | 4 +- app/Concerns/Models/InteractsWithLikes.php | 53 +++++++++++ .../Models/SyncLikeAggregatesCommand.php | 57 ++++++++++++ .../Models/SyncViewAggregatesCommand.php | 2 +- app/Console/Kernel.php | 7 ++ app/Contracts/Models/HasAggregateLikes.php | 23 +++++ app/Contracts/Models/HasAggregateViews.php | 2 +- app/Contracts/Models/Likeable.php | 35 ++++++++ app/GraphQL/Mutations/User/LikeMutator.php | 74 +++++++++++++++ app/GraphQL/Policies/User/LikePolicy.php | 29 ++++++ app/GraphQL/Resolvers/LikesCountResolver.php | 34 +++++++ app/GraphQL/Resolvers/ViewsCountResolver.php | 2 +- app/GraphQL/Schemas/Auth/user.graphql | 2 + .../List/Playlist/playlisttrack.graphql | 4 +- app/GraphQL/Schemas/List/playlist.graphql | 13 ++- app/GraphQL/Schemas/User/like.graphql | 27 ++++++ app/GraphQL/Schemas/Wiki/audio.graphql | 6 +- app/GraphQL/Schemas/Wiki/video.graphql | 10 ++- .../CreatePlaylistValidator.php | 2 +- .../CreatePlaylistTrackValidator.php | 2 +- .../UpdatePlaylistTrackValidator.php | 2 +- .../UpdatePlaylistValidator.php | 2 +- .../User/Like/CreateLikeValidator.php | 32 +++++++ .../User/Like/DeleteLikeValidator.php | 32 +++++++ .../List/Playlist/PlaylistViewCountField.php | 2 +- .../Field/Wiki/Audio/AudioViewCountField.php | 2 +- .../Field/Wiki/Video/VideoViewCountField.php | 2 +- app/Models/Aggregate/LikeAggregate.php | 58 ++++++++++++ .../{Service => Aggregate}/ViewAggregate.php | 2 +- app/Models/Auth/User.php | 42 +++++++++ app/Models/List/Playlist.php | 10 ++- app/Models/Service/View.php | 6 +- app/Models/User/Like.php | 90 +++++++++++++++++++ app/Models/Wiki/Audio.php | 2 +- app/Models/Wiki/Video.php | 10 ++- ...01_070445_create_view_aggregates_table.php | 2 +- .../2025_05_16_013458_create_likes_table.php | 39 ++++++++ ...16_100535_create_like_aggregates_table.php | 34 +++++++ .../Auth/Permission/PermissionSeeder.php | 2 + database/seeders/Auth/Role/AdminSeeder.php | 2 + .../Auth/Role/ContentModeratorRoleSeeder.php | 2 + .../Auth/Role/ContributorRoleSeeder.php | 2 + .../seeders/Auth/Role/DeveloperRoleSeeder.php | 2 + .../Auth/Role/PanelViewerRoleSeeder.php | 2 + .../seeders/Auth/Role/PatronRoleSeeder.php | 2 + .../seeders/Auth/Role/VerifiedRoleSeeder.php | 4 + 51 files changed, 824 insertions(+), 33 deletions(-) create mode 100644 app/Actions/Models/Aggregate/SyncLikeAggregatesAction.php rename app/Actions/Models/{Service => Aggregate}/SyncViewAggregatesAction.php (96%) create mode 100644 app/Concerns/Models/Aggregate/AggregatesLike.php rename app/Concerns/Models/{Service => Aggregate}/AggregatesView.php (86%) create mode 100644 app/Concerns/Models/InteractsWithLikes.php create mode 100644 app/Console/Commands/Models/SyncLikeAggregatesCommand.php create mode 100644 app/Contracts/Models/HasAggregateLikes.php create mode 100644 app/Contracts/Models/Likeable.php create mode 100644 app/GraphQL/Mutations/User/LikeMutator.php create mode 100644 app/GraphQL/Policies/User/LikePolicy.php create mode 100644 app/GraphQL/Resolvers/LikesCountResolver.php create mode 100644 app/GraphQL/Schemas/User/like.graphql rename app/GraphQL/Validators/Mutation/List/{ => Playlist}/CreatePlaylistValidator.php (94%) rename app/GraphQL/Validators/Mutation/List/Playlist/{ => Track}/CreatePlaylistTrackValidator.php (97%) rename app/GraphQL/Validators/Mutation/List/Playlist/{ => Track}/UpdatePlaylistTrackValidator.php (98%) rename app/GraphQL/Validators/Mutation/List/{ => Playlist}/UpdatePlaylistValidator.php (94%) create mode 100644 app/GraphQL/Validators/Mutation/User/Like/CreateLikeValidator.php create mode 100644 app/GraphQL/Validators/Mutation/User/Like/DeleteLikeValidator.php create mode 100644 app/Models/Aggregate/LikeAggregate.php rename app/Models/{Service => Aggregate}/ViewAggregate.php (97%) create mode 100644 app/Models/User/Like.php create mode 100644 database/migrations/2025_05_16_013458_create_likes_table.php create mode 100644 database/migrations/2025_05_16_100535_create_like_aggregates_table.php diff --git a/app/Actions/Models/Aggregate/SyncLikeAggregatesAction.php b/app/Actions/Models/Aggregate/SyncLikeAggregatesAction.php new file mode 100644 index 000000000..b35efd2f5 --- /dev/null +++ b/app/Actions/Models/Aggregate/SyncLikeAggregatesAction.php @@ -0,0 +1,47 @@ +getMessage() + ); + } + + return new ActionResult( + ActionStatus::PASSED, + 'Like aggregates synced successfully', + ); + } +} diff --git a/app/Actions/Models/Service/SyncViewAggregatesAction.php b/app/Actions/Models/Aggregate/SyncViewAggregatesAction.php similarity index 96% rename from app/Actions/Models/Service/SyncViewAggregatesAction.php rename to app/Actions/Models/Aggregate/SyncViewAggregatesAction.php index 0917c44b0..2831e8b03 100644 --- a/app/Actions/Models/Service/SyncViewAggregatesAction.php +++ b/app/Actions/Models/Aggregate/SyncViewAggregatesAction.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Actions\Models\Service; +namespace App\Actions\Models\Aggregate; use App\Actions\ActionResult; use App\Enums\Actions\ActionStatus; diff --git a/app/Actions/Storage/Admin/Dump/DumpAdminAction.php b/app/Actions/Storage/Admin/Dump/DumpAdminAction.php index fca162965..7d8610cdb 100644 --- a/app/Actions/Storage/Admin/Dump/DumpAdminAction.php +++ b/app/Actions/Storage/Admin/Dump/DumpAdminAction.php @@ -10,8 +10,6 @@ use App\Models\Admin\Announcement; use App\Models\Admin\Dump; use App\Models\Admin\Feature; use App\Models\Admin\FeaturedTheme; -use App\Models\Service\View; -use App\Models\Service\ViewAggregate; use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; diff --git a/app/Actions/Storage/Admin/Dump/DumpViewAction.php b/app/Actions/Storage/Admin/Dump/DumpViewAction.php index fac712b49..b6435582f 100644 --- a/app/Actions/Storage/Admin/Dump/DumpViewAction.php +++ b/app/Actions/Storage/Admin/Dump/DumpViewAction.php @@ -6,7 +6,7 @@ namespace App\Actions\Storage\Admin\Dump; use App\Concerns\Repositories\Admin\ReconcilesDumpRepositories; use App\Models\Service\View; -use App\Models\Service\ViewAggregate; +use App\Models\Aggregate\ViewAggregate; use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; diff --git a/app/Concerns/Models/Aggregate/AggregatesLike.php b/app/Concerns/Models/Aggregate/AggregatesLike.php new file mode 100644 index 000000000..b023b897c --- /dev/null +++ b/app/Concerns/Models/Aggregate/AggregatesLike.php @@ -0,0 +1,29 @@ + + */ + public function likeAggregate(): MorphOne + { + return $this->morphOne( + LikeAggregate::class, + LikeAggregate::ATTRIBUTE_LIKEABLE, + ); + } +} diff --git a/app/Concerns/Models/Service/AggregatesView.php b/app/Concerns/Models/Aggregate/AggregatesView.php similarity index 86% rename from app/Concerns/Models/Service/AggregatesView.php rename to app/Concerns/Models/Aggregate/AggregatesView.php index c0ebcb688..6fec22d5d 100644 --- a/app/Concerns/Models/Service/AggregatesView.php +++ b/app/Concerns/Models/Aggregate/AggregatesView.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace App\Concerns\Models\Service; +namespace App\Concerns\Models\Aggregate; -use App\Models\Service\ViewAggregate; +use App\Models\Aggregate\ViewAggregate; use Illuminate\Database\Eloquent\Relations\MorphOne; /** diff --git a/app/Concerns/Models/InteractsWithLikes.php b/app/Concerns/Models/InteractsWithLikes.php new file mode 100644 index 000000000..d9e1b3e0e --- /dev/null +++ b/app/Concerns/Models/InteractsWithLikes.php @@ -0,0 +1,53 @@ +create([ + Like::ATTRIBUTE_USER => Auth::id(), + Like::ATTRIBUTE_LIKEABLE_TYPE => $this->getMorphClass(), + Like::ATTRIBUTE_LIKEABLE_ID => $this->getKey(), + ]); + } + + /** + * Remove the like from the model for the current authenticated user. + * + * @return mixed + */ + public function unlike(): mixed + { + return Like::query() + ->whereBelongsTo(Auth::user()) + ->whereMorphedTo(Like::RELATION_LIKEABLE, $this) + ->delete(); + } + + /** + * Get the likes for the model. + * + * @return MorphMany + */ + public function likes(): MorphMany + { + return $this->morphMany(Like::class, Like::RELATION_LIKEABLE); + } +} diff --git a/app/Console/Commands/Models/SyncLikeAggregatesCommand.php b/app/Console/Commands/Models/SyncLikeAggregatesCommand.php new file mode 100644 index 000000000..e6bf475d0 --- /dev/null +++ b/app/Console/Commands/Models/SyncLikeAggregatesCommand.php @@ -0,0 +1,57 @@ +handle(); + + $result->toLog(); + $result->toConsole($this); + + return $result->hasFailed() ? 1 : 0; + } + + /** + * Get the validator for options. + * + * @return Validator + */ + protected function validator(): Validator + { + return ValidatorFacade::make($this->options(), []); + } +} diff --git a/app/Console/Commands/Models/SyncViewAggregatesCommand.php b/app/Console/Commands/Models/SyncViewAggregatesCommand.php index 0c8fa59a1..5c64cec0b 100644 --- a/app/Console/Commands/Models/SyncViewAggregatesCommand.php +++ b/app/Console/Commands/Models/SyncViewAggregatesCommand.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\Console\Commands\Models; -use App\Actions\Models\Service\SyncViewAggregatesAction; +use App\Actions\Models\Aggregate\SyncViewAggregatesAction; use App\Console\Commands\BaseCommand; use Illuminate\Contracts\Validation\Validator; use Illuminate\Support\Facades\Validator as ValidatorFacade; diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index b91b6c78f..8c8b7ade1 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Console; +use App\Console\Commands\Models\SyncLikeAggregatesCommand; use App\Console\Commands\Models\SyncViewAggregatesCommand; use App\Console\Commands\Storage\Admin\AdminDumpCommand; use App\Console\Commands\Storage\Admin\AuthDumpCommand; @@ -151,6 +152,12 @@ class Kernel extends ConsoleKernel ->storeOutput() ->everyFiveMinutes(); + $schedule->command(SyncLikeAggregatesCommand::class) + ->withoutOverlapping() + ->runInBackground() + ->storeOutput() + ->daily(); + $schedule->command(SyncViewAggregatesCommand::class) ->withoutOverlapping() ->runInBackground() diff --git a/app/Contracts/Models/HasAggregateLikes.php b/app/Contracts/Models/HasAggregateLikes.php new file mode 100644 index 000000000..fdfda21d4 --- /dev/null +++ b/app/Contracts/Models/HasAggregateLikes.php @@ -0,0 +1,23 @@ +like(); + return $playlist; + } + + if ($video instanceof Video) { + $video->like(); + return $video; + } + + throw new Exception('None models detected to like.'); + } + + /** + * Remove the specified resource. + * + * @param null $_ + * @param array $args + * @return Model + * + * @throws Exception + */ + public function destroy($_, array $args): Model + { + $playlist = Arr::get($args, self::ATTRIBUTE_PLAYLIST); + $video = Arr::get($args, self::ATTRIBUTE_VIDEO); + + if ($playlist instanceof Playlist) { + $playlist->unlike(); + return $playlist; + } + + if ($video instanceof Video) { + $video->unlike(); + return $video; + } + + throw new Exception('None models detected to unlike.'); + } +} diff --git a/app/GraphQL/Policies/User/LikePolicy.php b/app/GraphQL/Policies/User/LikePolicy.php new file mode 100644 index 000000000..1b806c35b --- /dev/null +++ b/app/GraphQL/Policies/User/LikePolicy.php @@ -0,0 +1,29 @@ +can(CrudPermission::DELETE->format(Like::class)); + } +} diff --git a/app/GraphQL/Resolvers/LikesCountResolver.php b/app/GraphQL/Resolvers/LikesCountResolver.php new file mode 100644 index 000000000..c381cba7c --- /dev/null +++ b/app/GraphQL/Resolvers/LikesCountResolver.php @@ -0,0 +1,34 @@ +likeAggregate; + + return (int) $like?->value; + } +} diff --git a/app/GraphQL/Resolvers/ViewsCountResolver.php b/app/GraphQL/Resolvers/ViewsCountResolver.php index e79bdbdfd..09f5d5c78 100644 --- a/app/GraphQL/Resolvers/ViewsCountResolver.php +++ b/app/GraphQL/Resolvers/ViewsCountResolver.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace App\GraphQL\Resolvers; use App\Contracts\Models\HasAggregateViews; -use App\Models\Service\ViewAggregate; +use App\Models\Aggregate\ViewAggregate; use GraphQL\Type\Definition\ResolveInfo; use Nuwave\Lighthouse\Support\Contracts\GraphQLContext; diff --git a/app/GraphQL/Schemas/Auth/user.graphql b/app/GraphQL/Schemas/Auth/user.graphql index 52c481bfb..1fb663b16 100644 --- a/app/GraphQL/Schemas/Auth/user.graphql +++ b/app/GraphQL/Schemas/Auth/user.graphql @@ -25,6 +25,8 @@ type Me { two_factor_confirmed_at: DateTimeTz notifications: [Notification] @morphMany playlists: [Playlist] @hasMany + likedplaylists: [Playlist] @belongsToMany(type: CONNECTION) + likedvideos: [Video] @belongsToMany(type: CONNECTION) "The date that the resource was created" createdAt: DateTimeTz @rename(attribute: "created_at") "The date that the resource was last modified" diff --git a/app/GraphQL/Schemas/List/Playlist/playlisttrack.graphql b/app/GraphQL/Schemas/List/Playlist/playlisttrack.graphql index b5b524110..08c1a282c 100644 --- a/app/GraphQL/Schemas/List/Playlist/playlisttrack.graphql +++ b/app/GraphQL/Schemas/List/Playlist/playlisttrack.graphql @@ -58,7 +58,7 @@ extend type Mutation @guard { playlist: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid") ): PlaylistTrack! @canModel(ability: "create", injectArgs: true) - @validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\Playlist\\CreatePlaylistTrackValidator") + @validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\Playlist\\Track\\CreatePlaylistTrackValidator") @field(resolver: "App\\GraphQL\\Mutations\\List\\Playlist\\PlaylistTrackMutator@store") @@ -71,7 +71,7 @@ extend type Mutation @guard { playlist: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid") ): PlaylistTrack! @canModel(ability: "update", injectArgs: true) - @validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\Playlist\\UpdatePlaylistTrackValidator") + @validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\Playlist\\Track\\UpdatePlaylistTrackValidator") @field(resolver: "App\\GraphQL\\Mutations\\List\\Playlist\\PlaylistTrackMutator@update") diff --git a/app/GraphQL/Schemas/List/playlist.graphql b/app/GraphQL/Schemas/List/playlist.graphql index 150a992ab..f865e16f7 100644 --- a/app/GraphQL/Schemas/List/playlist.graphql +++ b/app/GraphQL/Schemas/List/playlist.graphql @@ -16,6 +16,8 @@ type Playlist { tracksExists: Boolean! @with(relation: "tracks") @field(resolver: "App\\GraphQL\\Resolvers\\ExistsResolver@resolve") "The state of who can see the playlist" visibility: PlaylistVisibility! @localizedEnum + "The number of likes recorded for the resource" + likesCount: Int! @with(relation: "likeAggregate") @field(resolver: "App\\GraphQL\\Resolvers\\LikesCountResolver@resolve") "The number of views recorded for the resource" viewsCount: Int! @with(relation: "viewAggregate") @field(resolver: "App\\GraphQL\\Resolvers\\ViewsCountResolver@resolve") first: PlaylistTrack @belongsTo @@ -66,7 +68,12 @@ extend type Query { updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">") deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<") deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">") - orderBy: _ @orderBy(columnsEnum: "PlaylistColumnsOrderable") + orderBy: _ @orderBy(columnsEnum: "PlaylistColumnsOrderable", + relations: [ + {relation: "likeAggregate", columns: ["value"]}, + {relation: "viewAggregate", columns: ["value"]} + ] + ) ): [Playlist!]! @canModel(ability: "viewAny", injectArgs: true) @builder(method: "App\\GraphQL\\Builders\\List\\PlaylistBuilder@index") @@ -80,7 +87,7 @@ extend type Mutation @guard { visibility: PlaylistVisibility! ): Playlist! @canModel(ability: "create") - @validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\CreatePlaylistValidator") + @validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\Playlist\\CreatePlaylistValidator") @field(resolver: "App\\GraphQL\\Mutations\\List\\PlaylistMutator@store") @@ -91,7 +98,7 @@ extend type Mutation @guard { visibility: PlaylistVisibility ): Playlist! @canModel(ability: "update", injectArgs: true) - @validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\UpdatePlaylistValidator") + @validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\Playlist\\UpdatePlaylistValidator") @field(resolver: "App\\GraphQL\\Mutations\\List\\PlaylistMutator@update") diff --git a/app/GraphQL/Schemas/User/like.graphql b/app/GraphQL/Schemas/User/like.graphql new file mode 100644 index 000000000..6a9374511 --- /dev/null +++ b/app/GraphQL/Schemas/User/like.graphql @@ -0,0 +1,27 @@ +"Represents a like of a user." +type Like { + "The user that liked the resource" + user: User @belongsTo + "The model that was liked" + liked: Liked @morphTo +} + +extend type Mutation @guard { + like( + playlist: String @bind(class: "App\\Models\\List\\Playlist", column: "hashid") + video: Int @bind(class: "App\\Models\\Wiki\\Video", column: "video_id") + ): Liked + @canModel(ability: "create", model: "App\\Models\\User\\Like") + @validator(class: "App\\GraphQL\\Validators\\Mutation\\User\\Like\\CreateLikeValidator") + @field(resolver: "App\\GraphQL\\Mutations\\User\\LikeMutator@store") + + unlike( + playlist: String @bind(class: "App\\Models\\List\\Playlist", column: "hashid") + video: Int @bind(class: "App\\Models\\Wiki\\Video", column: "video_id") + ): Liked + @canModel(ability: "delete", injectArgs: true, model: "App\\Models\\User\\Like") + @validator(class: "App\\GraphQL\\Validators\\Mutation\\User\\Like\\DeleteLikeValidator") + @field(resolver: "App\\GraphQL\\Mutations\\User\\LikeMutator@destroy") +} + +union Liked = Playlist | Video \ No newline at end of file diff --git a/app/GraphQL/Schemas/Wiki/audio.graphql b/app/GraphQL/Schemas/Wiki/audio.graphql index 58d5f5c16..00bc0cddf 100644 --- a/app/GraphQL/Schemas/Wiki/audio.graphql +++ b/app/GraphQL/Schemas/Wiki/audio.graphql @@ -50,7 +50,11 @@ extend type Query { updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">") deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<") deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">") - orderBy: _ @orderBy(columnsEnum: "AudioColumnsOrderable") + orderBy: _ @orderBy(columnsEnum: "AudioColumnsOrderable", + relations: [ + {relation: "viewAggregate", columns: ["value"]} + ] + ) ): [Audio!]! @canModel(ability: "viewAny", injectArgs: true) @softDeletes diff --git a/app/GraphQL/Schemas/Wiki/video.graphql b/app/GraphQL/Schemas/Wiki/video.graphql index 34312225f..277e4a463 100644 --- a/app/GraphQL/Schemas/Wiki/video.graphql +++ b/app/GraphQL/Schemas/Wiki/video.graphql @@ -34,6 +34,8 @@ type Video { tags: String @field(resolver: "App\\GraphQL\\Resolvers\\ImplodeArrayResolver@resolve") "The URL to stream the file from storage" link: String! + "The number of likes recorded for the resource" + likesCount: Int! @with(relation: "likeAggregate") @field(resolver: "App\\GraphQL\\Resolvers\\LikesCountResolver@resolve") "The number of views recorded for the resource" viewsCount: Int! @with(relation: "viewAggregate") @field(resolver: "App\\GraphQL\\Resolvers\\ViewsCountResolver@resolve") animethemeentries: [AnimeThemeEntry] @belongsToMany(type: CONNECTION) @@ -76,6 +78,7 @@ enum VideoColumnsOrderable { extend type Query { "Returns a listing of video resources given fields." videos( + filename: String @eq isLyrics: Boolean @eq isNc: Boolean @eq isSubbed: Boolean @eq @@ -93,7 +96,12 @@ extend type Query { updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">") deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<") deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">") - orderBy: _ @orderBy(columnsEnum: "VideoColumnsOrderable") + orderBy: _ @orderBy(columnsEnum: "VideoColumnsOrderable", + relations: [ + {relation: "likeAggregate", columns: ["value"]}, + {relation: "viewAggregate", columns: ["value"]} + ] + ) ): [Video!]! @canModel(ability: "viewAny", injectArgs: true) @softDeletes diff --git a/app/GraphQL/Validators/Mutation/List/CreatePlaylistValidator.php b/app/GraphQL/Validators/Mutation/List/Playlist/CreatePlaylistValidator.php similarity index 94% rename from app/GraphQL/Validators/Mutation/List/CreatePlaylistValidator.php rename to app/GraphQL/Validators/Mutation/List/Playlist/CreatePlaylistValidator.php index eec6e2602..e4cb2613f 100644 --- a/app/GraphQL/Validators/Mutation/List/CreatePlaylistValidator.php +++ b/app/GraphQL/Validators/Mutation/List/Playlist/CreatePlaylistValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\GraphQL\Validators\Mutation\List; +namespace App\GraphQL\Validators\Mutation\List\Playlist; use App\Enums\Models\List\PlaylistVisibility; use App\Models\List\Playlist; diff --git a/app/GraphQL/Validators/Mutation/List/Playlist/CreatePlaylistTrackValidator.php b/app/GraphQL/Validators/Mutation/List/Playlist/Track/CreatePlaylistTrackValidator.php similarity index 97% rename from app/GraphQL/Validators/Mutation/List/Playlist/CreatePlaylistTrackValidator.php rename to app/GraphQL/Validators/Mutation/List/Playlist/Track/CreatePlaylistTrackValidator.php index e6859acaf..86126a08f 100644 --- a/app/GraphQL/Validators/Mutation/List/Playlist/CreatePlaylistTrackValidator.php +++ b/app/GraphQL/Validators/Mutation/List/Playlist/Track/CreatePlaylistTrackValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\GraphQL\Validators\Mutation\List\Playlist; +namespace App\GraphQL\Validators\Mutation\List\Playlist\Track; use App\Contracts\Models\HasHashids; use App\Models\List\Playlist; diff --git a/app/GraphQL/Validators/Mutation/List/Playlist/UpdatePlaylistTrackValidator.php b/app/GraphQL/Validators/Mutation/List/Playlist/Track/UpdatePlaylistTrackValidator.php similarity index 98% rename from app/GraphQL/Validators/Mutation/List/Playlist/UpdatePlaylistTrackValidator.php rename to app/GraphQL/Validators/Mutation/List/Playlist/Track/UpdatePlaylistTrackValidator.php index d7d8c2513..97fbe3365 100644 --- a/app/GraphQL/Validators/Mutation/List/Playlist/UpdatePlaylistTrackValidator.php +++ b/app/GraphQL/Validators/Mutation/List/Playlist/Track/UpdatePlaylistTrackValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\GraphQL\Validators\Mutation\List\Playlist; +namespace App\GraphQL\Validators\Mutation\List\Playlist\Track; use App\Contracts\Models\HasHashids; use App\Models\List\Playlist; diff --git a/app/GraphQL/Validators/Mutation/List/UpdatePlaylistValidator.php b/app/GraphQL/Validators/Mutation/List/Playlist/UpdatePlaylistValidator.php similarity index 94% rename from app/GraphQL/Validators/Mutation/List/UpdatePlaylistValidator.php rename to app/GraphQL/Validators/Mutation/List/Playlist/UpdatePlaylistValidator.php index 3d79862ce..2963a2e6e 100644 --- a/app/GraphQL/Validators/Mutation/List/UpdatePlaylistValidator.php +++ b/app/GraphQL/Validators/Mutation/List/Playlist/UpdatePlaylistValidator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\GraphQL\Validators\Mutation\List; +namespace App\GraphQL\Validators\Mutation\List\Playlist; use App\Enums\Models\List\PlaylistVisibility; use App\Models\List\Playlist; diff --git a/app/GraphQL/Validators/Mutation/User/Like/CreateLikeValidator.php b/app/GraphQL/Validators/Mutation/User/Like/CreateLikeValidator.php new file mode 100644 index 000000000..95801d5da --- /dev/null +++ b/app/GraphQL/Validators/Mutation/User/Like/CreateLikeValidator.php @@ -0,0 +1,32 @@ +> + */ + public function rules(): array + { + return [ + LikeMutator::ATTRIBUTE_PLAYLIST => [ + Str::of('prohibits:')->append(LikeMutator::ATTRIBUTE_VIDEO)->__toString(), + ], + LikeMutator::ATTRIBUTE_VIDEO => [ + Str::of('prohibits:')->append(LikeMutator::ATTRIBUTE_PLAYLIST)->__toString(), + ], + ]; + } +} diff --git a/app/GraphQL/Validators/Mutation/User/Like/DeleteLikeValidator.php b/app/GraphQL/Validators/Mutation/User/Like/DeleteLikeValidator.php new file mode 100644 index 000000000..29b315087 --- /dev/null +++ b/app/GraphQL/Validators/Mutation/User/Like/DeleteLikeValidator.php @@ -0,0 +1,32 @@ +> + */ + public function rules(): array + { + return [ + LikeMutator::ATTRIBUTE_PLAYLIST => [ + Str::of('prohibits:')->append(LikeMutator::ATTRIBUTE_VIDEO)->__toString(), + ], + LikeMutator::ATTRIBUTE_VIDEO => [ + Str::of('prohibits:')->append(LikeMutator::ATTRIBUTE_PLAYLIST)->__toString(), + ], + ]; + } +} diff --git a/app/Http/Api/Field/List/Playlist/PlaylistViewCountField.php b/app/Http/Api/Field/List/Playlist/PlaylistViewCountField.php index 1ca08adec..e0f31ed95 100644 --- a/app/Http/Api/Field/List/Playlist/PlaylistViewCountField.php +++ b/app/Http/Api/Field/List/Playlist/PlaylistViewCountField.php @@ -12,7 +12,7 @@ use App\Http\Api\Filter\IntFilter; use App\Http\Api\Schema\Schema; use App\Http\Api\Sort\Sort; use App\Models\List\Playlist; -use App\Models\Service\ViewAggregate; +use App\Models\Aggregate\ViewAggregate; use Illuminate\Database\Eloquent\Model; /** diff --git a/app/Http/Api/Field/Wiki/Audio/AudioViewCountField.php b/app/Http/Api/Field/Wiki/Audio/AudioViewCountField.php index 9ad780250..6cb525070 100644 --- a/app/Http/Api/Field/Wiki/Audio/AudioViewCountField.php +++ b/app/Http/Api/Field/Wiki/Audio/AudioViewCountField.php @@ -11,7 +11,7 @@ use App\Http\Api\Filter\Filter; use App\Http\Api\Filter\IntFilter; use App\Http\Api\Schema\Schema; use App\Http\Api\Sort\Sort; -use App\Models\Service\ViewAggregate; +use App\Models\Aggregate\ViewAggregate; use App\Models\Wiki\Audio; use Illuminate\Database\Eloquent\Model; diff --git a/app/Http/Api/Field/Wiki/Video/VideoViewCountField.php b/app/Http/Api/Field/Wiki/Video/VideoViewCountField.php index c46334f96..c2ce9f2ef 100644 --- a/app/Http/Api/Field/Wiki/Video/VideoViewCountField.php +++ b/app/Http/Api/Field/Wiki/Video/VideoViewCountField.php @@ -11,7 +11,7 @@ use App\Http\Api\Filter\Filter; use App\Http\Api\Filter\IntFilter; use App\Http\Api\Schema\Schema; use App\Http\Api\Sort\Sort; -use App\Models\Service\ViewAggregate; +use App\Models\Aggregate\ViewAggregate; use App\Models\Wiki\Video; use Illuminate\Database\Eloquent\Model; diff --git a/app/Models/Aggregate/LikeAggregate.php b/app/Models/Aggregate/LikeAggregate.php new file mode 100644 index 000000000..b5bf15b32 --- /dev/null +++ b/app/Models/Aggregate/LikeAggregate.php @@ -0,0 +1,58 @@ +morphTo(); + } +} diff --git a/app/Models/Service/ViewAggregate.php b/app/Models/Aggregate/ViewAggregate.php similarity index 97% rename from app/Models/Service/ViewAggregate.php rename to app/Models/Aggregate/ViewAggregate.php index 157696729..027818919 100644 --- a/app/Models/Service/ViewAggregate.php +++ b/app/Models/Aggregate/ViewAggregate.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Models\Service; +namespace App\Models\Aggregate; use CyrildeWit\EloquentViewable\Contracts\Viewable; use Illuminate\Database\Eloquent\Model; diff --git a/app/Models/Auth/User.php b/app/Models/Auth/User.php index c45d57b13..6e73041e2 100644 --- a/app/Models/Auth/User.php +++ b/app/Models/Auth/User.php @@ -15,7 +15,9 @@ use App\Models\Admin\ActionLog; use App\Models\User\Report; use App\Models\List\Playlist; use App\Models\List\ExternalProfile; +use App\Models\User\Like; use App\Models\User\Notification; +use App\Models\Wiki\Video; use App\Notifications\UserNotification; use Database\Factories\Auth\UserFactory; use Filament\Facades\Filament; @@ -25,8 +27,10 @@ use Filament\Notifications\DatabaseNotification as FilamentNotification; use Filament\Panel; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphMany; +use Illuminate\Database\Eloquent\Relations\MorphToMany; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; @@ -249,6 +253,44 @@ class User extends Authenticatable implements MustVerifyEmail, Nameable, HasSubt return $this->hasMany(ExternalProfile::class, ExternalProfile::ATTRIBUTE_USER); } + /** + * Get the liked playlists of the user. + * + * @return BelongsToMany + */ + public function likedplaylists(): BelongsToMany + { + return $this->belongsToMany( + Playlist::class, + Like::TABLE, + Like::ATTRIBUTE_USER, + Like::ATTRIBUTE_LIKEABLE_ID, + null, + Playlist::ATTRIBUTE_ID + ) + ->wherePivot(Like::ATTRIBUTE_LIKEABLE_TYPE, Playlist::class) + ->withTimestamps(); + } + + /** + * Get the liked videos of the user. + * + * @return BelongsToMany + */ + public function likedvideos(): BelongsToMany + { + return $this->belongsToMany( + Video::class, + Like::TABLE, + Like::ATTRIBUTE_USER, + Like::ATTRIBUTE_LIKEABLE_ID, + null, + Video::ATTRIBUTE_ID + ) + ->wherePivot(Like::ATTRIBUTE_LIKEABLE_TYPE, Video::class) + ->withTimestamps(); + } + /** * Get the submissions that the user made. * diff --git a/app/Models/List/Playlist.php b/app/Models/List/Playlist.php index 18852923a..8d6cd2e06 100644 --- a/app/Models/List/Playlist.php +++ b/app/Models/List/Playlist.php @@ -4,10 +4,14 @@ declare(strict_types=1); namespace App\Models\List; -use App\Concerns\Models\Service\AggregatesView; +use App\Concerns\Models\Aggregate\AggregatesLike; +use App\Concerns\Models\Aggregate\AggregatesView; +use App\Concerns\Models\InteractsWithLikes; +use App\Contracts\Models\HasAggregateLikes; use App\Contracts\Models\HasAggregateViews; use App\Contracts\Models\HasHashids; use App\Contracts\Models\HasImages; +use App\Contracts\Models\Likeable; use App\Enums\Models\List\PlaylistVisibility; use App\Events\List\Playlist\PlaylistCreated; use App\Events\List\Playlist\PlaylistDeleted; @@ -46,9 +50,11 @@ use Illuminate\Support\Collection; * * @method static PlaylistFactory factory(...$parameters) */ -class Playlist extends BaseModel implements HasHashids, Viewable, HasImages, HasAggregateViews +class Playlist extends BaseModel implements HasHashids, Likeable, Viewable, HasImages, HasAggregateLikes, HasAggregateViews { + use AggregatesLike; use AggregatesView; + use InteractsWithLikes; use Searchable; use InteractsWithViews; diff --git a/app/Models/Service/View.php b/app/Models/Service/View.php index f0423d22f..afc47bea2 100644 --- a/app/Models/Service/View.php +++ b/app/Models/Service/View.php @@ -23,13 +23,13 @@ class View extends BaseView final public const TABLE = 'views'; /** - * Bootstrap the model. + * Perform any actions required after the model boots. * * @return void */ - protected static function boot(): void + protected static function booted(): void { - parent::boot(); + parent::booted(); static::creating(function (View $view) { $view->user_agent = Request::userAgent(); diff --git a/app/Models/User/Like.php b/app/Models/User/Like.php new file mode 100644 index 000000000..6da0e4207 --- /dev/null +++ b/app/Models/User/Like.php @@ -0,0 +1,90 @@ + + */ + protected $fillable = [ + Like::ATTRIBUTE_USER, + Like::ATTRIBUTE_LIKEABLE_TYPE, + Like::ATTRIBUTE_LIKEABLE_ID + ]; + + /** + * Get name. + * + * @return string + */ + public function getName(): string + { + return strval($this->getKey()); + } + + /** + * Gets the user that owns the like. + * + * @return BelongsTo + */ + public function user(): BelongsTo + { + return $this->belongsTo(User::class, Like::ATTRIBUTE_USER); + } + + /** + * Gets the video that owns the like. + * + * @return MorphTo + */ + public function likeable(): MorphTo + { + return $this->morphTo(); + } +} diff --git a/app/Models/Wiki/Audio.php b/app/Models/Wiki/Audio.php index 439efdafa..2b6be092b 100644 --- a/app/Models/Wiki/Audio.php +++ b/app/Models/Wiki/Audio.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace App\Models\Wiki; use App\Concerns\Models\Reportable; -use App\Concerns\Models\Service\AggregatesView; +use App\Concerns\Models\Aggregate\AggregatesView; use App\Contracts\Models\HasAggregateViews; use App\Contracts\Models\Streamable; use App\Events\Wiki\Audio\AudioCreated; diff --git a/app/Models/Wiki/Video.php b/app/Models/Wiki/Video.php index 62d67d05b..a0e0e341c 100644 --- a/app/Models/Wiki/Video.php +++ b/app/Models/Wiki/Video.php @@ -4,9 +4,13 @@ declare(strict_types=1); namespace App\Models\Wiki; +use App\Concerns\Models\Aggregate\AggregatesLike; use App\Concerns\Models\Reportable; -use App\Concerns\Models\Service\AggregatesView; +use App\Concerns\Models\Aggregate\AggregatesView; +use App\Concerns\Models\InteractsWithLikes; +use App\Contracts\Models\HasAggregateLikes; use App\Contracts\Models\HasAggregateViews; +use App\Contracts\Models\Likeable; use App\Contracts\Models\Streamable; use App\Enums\Models\List\PlaylistVisibility; use App\Enums\Models\Wiki\VideoOverlap; @@ -62,9 +66,11 @@ use Illuminate\Support\Collection; * * @method static VideoFactory factory(...$parameters) */ -class Video extends BaseModel implements Streamable, Viewable, HasAggregateViews +class Video extends BaseModel implements Streamable, Likeable, Viewable, HasAggregateLikes, HasAggregateViews { + use AggregatesLike; use AggregatesView; + use InteractsWithLikes; use Reportable; use Searchable; use InteractsWithViews; diff --git a/database/migrations/2025_01_01_070445_create_view_aggregates_table.php b/database/migrations/2025_01_01_070445_create_view_aggregates_table.php index 0da3bbd2e..baf4a06fb 100644 --- a/database/migrations/2025_01_01_070445_create_view_aggregates_table.php +++ b/database/migrations/2025_01_01_070445_create_view_aggregates_table.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use App\Models\Service\ViewAggregate; +use App\Models\Aggregate\ViewAggregate; use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; diff --git a/database/migrations/2025_05_16_013458_create_likes_table.php b/database/migrations/2025_05_16_013458_create_likes_table.php new file mode 100644 index 000000000..b9e96391d --- /dev/null +++ b/database/migrations/2025_05_16_013458_create_likes_table.php @@ -0,0 +1,39 @@ +id(Like::ATTRIBUTE_ID); + $table->unsignedBigInteger(Like::ATTRIBUTE_USER)->nullable(); + $table->foreign(Like::ATTRIBUTE_USER)->references(User::ATTRIBUTE_ID)->on(User::TABLE)->cascadeOnDelete(); + + $table->morphs(Like::ATTRIBUTE_LIKEABLE); + $table->timestamps(6); + + $table->index([Like::ATTRIBUTE_USER, Like::ATTRIBUTE_LIKEABLE_TYPE, Like::ATTRIBUTE_LIKEABLE_ID]); + }); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists(Like::TABLE); + } +}; diff --git a/database/migrations/2025_05_16_100535_create_like_aggregates_table.php b/database/migrations/2025_05_16_100535_create_like_aggregates_table.php new file mode 100644 index 000000000..5983c0d59 --- /dev/null +++ b/database/migrations/2025_05_16_100535_create_like_aggregates_table.php @@ -0,0 +1,34 @@ +morphs(LikeAggregate::ATTRIBUTE_LIKEABLE); + $table->integer(LikeAggregate::ATTRIBUTE_VALUE)->default(0); + $table->primary([LikeAggregate::ATTRIBUTE_LIKEABLE_ID, LikeAggregate::ATTRIBUTE_LIKEABLE_TYPE]); + $table->index([LikeAggregate::ATTRIBUTE_LIKEABLE_ID, LikeAggregate::ATTRIBUTE_LIKEABLE_TYPE]); + }); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists(LikeAggregate::TABLE); + } +}; diff --git a/database/seeders/Auth/Permission/PermissionSeeder.php b/database/seeders/Auth/Permission/PermissionSeeder.php index 694d5b6b3..71ea2e137 100644 --- a/database/seeders/Auth/Permission/PermissionSeeder.php +++ b/database/seeders/Auth/Permission/PermissionSeeder.php @@ -21,6 +21,7 @@ use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; +use App\Models\User\Like; use App\Models\User\Notification; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; @@ -78,6 +79,7 @@ class PermissionSeeder extends Seeder $this->registerResource(PlaylistTrack::class, $extendedCrudPermissions); // User Resources + $this->registerResource(Like::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::DELETE]); $this->registerResource(Notification::class, [CrudPermission::VIEW, CrudPermission::UPDATE]); $this->registerResource(Report::class, CrudPermission::cases()); diff --git a/database/seeders/Auth/Role/AdminSeeder.php b/database/seeders/Auth/Role/AdminSeeder.php index a293f28a9..5a719bcd5 100644 --- a/database/seeders/Auth/Role/AdminSeeder.php +++ b/database/seeders/Auth/Role/AdminSeeder.php @@ -22,6 +22,7 @@ use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; +use App\Models\User\Like; use App\Models\User\Notification; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; @@ -85,6 +86,7 @@ class AdminSeeder extends RoleSeeder $this->configureResource($role, PlaylistTrack::class, $extendedCrudPermissions); // User Resources + $this->configureResource($role, Like::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::DELETE]); $this->configureResource($role, Notification::class, [CrudPermission::VIEW, CrudPermission::UPDATE]); $this->configureResource($role, Report::class, CrudPermission::cases()); diff --git a/database/seeders/Auth/Role/ContentModeratorRoleSeeder.php b/database/seeders/Auth/Role/ContentModeratorRoleSeeder.php index 76cd63d70..5ce4f3972 100644 --- a/database/seeders/Auth/Role/ContentModeratorRoleSeeder.php +++ b/database/seeders/Auth/Role/ContentModeratorRoleSeeder.php @@ -15,6 +15,7 @@ use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; +use App\Models\User\Like; use App\Models\User\Notification; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; @@ -67,6 +68,7 @@ class ContentModeratorRoleSeeder extends RoleSeeder $this->configureResource($role, PlaylistTrack::class, $extendedCrudPermissions); // User Resources + $this->configureResource($role, Like::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::DELETE]); $this->configureResource($role, Notification::class, [CrudPermission::VIEW, CrudPermission::UPDATE]); $extendedCrudPermissions = array_merge( diff --git a/database/seeders/Auth/Role/ContributorRoleSeeder.php b/database/seeders/Auth/Role/ContributorRoleSeeder.php index 9b4d41475..962324dfc 100644 --- a/database/seeders/Auth/Role/ContributorRoleSeeder.php +++ b/database/seeders/Auth/Role/ContributorRoleSeeder.php @@ -16,6 +16,7 @@ use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; +use App\Models\User\Like; use App\Models\User\Notification; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; @@ -68,6 +69,7 @@ class ContributorRoleSeeder extends RoleSeeder $this->configureResource($role, PlaylistTrack::class, $extendedCrudPermissions); // User Resources + $this->configureResource($role, Like::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::DELETE]); $this->configureResource($role, Notification::class, [CrudPermission::VIEW, CrudPermission::UPDATE]); $this->configureResource($role, Report::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::UPDATE]); diff --git a/database/seeders/Auth/Role/DeveloperRoleSeeder.php b/database/seeders/Auth/Role/DeveloperRoleSeeder.php index b7ffc9563..5002fcc26 100644 --- a/database/seeders/Auth/Role/DeveloperRoleSeeder.php +++ b/database/seeders/Auth/Role/DeveloperRoleSeeder.php @@ -15,6 +15,7 @@ use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; +use App\Models\User\Like; use App\Models\User\Notification; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; @@ -67,6 +68,7 @@ class DeveloperRoleSeeder extends RoleSeeder $this->configureResource($role, PlaylistTrack::class, $extendedCrudPermissions); // User Resources + $this->configureResource($role, Like::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::DELETE]); $this->configureResource($role, Notification::class, [CrudPermission::VIEW, CrudPermission::UPDATE]); // Wiki Resources diff --git a/database/seeders/Auth/Role/PanelViewerRoleSeeder.php b/database/seeders/Auth/Role/PanelViewerRoleSeeder.php index 6757787c7..83960d0c6 100644 --- a/database/seeders/Auth/Role/PanelViewerRoleSeeder.php +++ b/database/seeders/Auth/Role/PanelViewerRoleSeeder.php @@ -16,6 +16,7 @@ use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; +use App\Models\User\Like; use App\Models\User\Notification; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; @@ -68,6 +69,7 @@ class PanelViewerRoleSeeder extends RoleSeeder $this->configureResource($role, PlaylistTrack::class, $extendedCrudPermissions); // User Resources + $this->configureResource($role, Like::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::DELETE]); $this->configureResource($role, Notification::class, [CrudPermission::VIEW, CrudPermission::UPDATE]); $this->configureResource($role, Report::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::UPDATE]); diff --git a/database/seeders/Auth/Role/PatronRoleSeeder.php b/database/seeders/Auth/Role/PatronRoleSeeder.php index 24896fb9e..37c325100 100644 --- a/database/seeders/Auth/Role/PatronRoleSeeder.php +++ b/database/seeders/Auth/Role/PatronRoleSeeder.php @@ -15,6 +15,7 @@ use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; +use App\Models\User\Like; use App\Models\User\Notification; use App\Models\Wiki\Anime; use App\Models\Wiki\Anime\AnimeSynonym; @@ -67,6 +68,7 @@ class PatronRoleSeeder extends RoleSeeder $this->configureResource($role, PlaylistTrack::class, $extendedCrudPermissions); // User Resources + $this->configureResource($role, Like::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::DELETE]); $this->configureResource($role, Notification::class, [CrudPermission::VIEW, CrudPermission::UPDATE]); // Wiki Resources diff --git a/database/seeders/Auth/Role/VerifiedRoleSeeder.php b/database/seeders/Auth/Role/VerifiedRoleSeeder.php index 57c2871e7..3c6614523 100644 --- a/database/seeders/Auth/Role/VerifiedRoleSeeder.php +++ b/database/seeders/Auth/Role/VerifiedRoleSeeder.php @@ -12,6 +12,7 @@ use App\Models\List\External\ExternalEntry; use App\Models\List\ExternalProfile; use App\Models\List\Playlist; use App\Models\List\Playlist\PlaylistTrack; +use App\Models\User\Like; /** * Class VerifiedRoleSeeder. @@ -37,6 +38,9 @@ class VerifiedRoleSeeder extends RoleSeeder ExtendedCrudPermission::cases(), ); + // User Resources + $this->configureResource($role, Like::class, [CrudPermission::VIEW, CrudPermission::CREATE, CrudPermission::DELETE]); + // List Resources $this->configureResource($role, ExternalEntry::class, [CrudPermission::VIEW]); $this->configureResource($role, ExternalProfile::class, $extendedCrudPermissions);