Skip to content

Commit acf121f

Browse files
committed
add: playlist suggestions
Allow other users to suggest torrents to add to other users' playlists.
1 parent ad1b66e commit acf121f

15 files changed

+713
-31
lines changed

app/Http/Controllers/PlaylistController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public function show(Request $request, Playlist $playlist): \Illuminate\Contract
121121
$this->scopeMeta($torrents);
122122

123123
return view('playlist.show', [
124-
'playlist' => $playlist->load('user.group'),
124+
'playlist' => $playlist->load(['user.group', 'suggestions' => ['user.group', 'torrent']]),
125125
'meta' => match (true) {
126126
$randomTorrent?->category?->tv_meta => TmdbTv::find($randomTorrent->tmdb_tv_id),
127127
$randomTorrent?->category?->movie_meta => TmdbMovie::find($randomTorrent->tmdb_movie_id),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* NOTICE OF LICENSE.
7+
*
8+
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
9+
* The details is bundled with this project in the file LICENSE.txt.
10+
*
11+
* @project UNIT3D Community Edition
12+
*
13+
* @author Roardom <roardom@protonmail.com>
14+
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
15+
*/
16+
17+
namespace App\Http\Controllers;
18+
19+
use App\Enums\ModerationStatus;
20+
use App\Http\Requests\StorePlaylistSuggestionRequest;
21+
use App\Http\Requests\UpdatePlaylistSuggestionRequest;
22+
use App\Models\Playlist;
23+
use App\Models\PlaylistSuggestion;
24+
use App\Models\PlaylistTorrent;
25+
use App\Notifications\PlaylistSuggestionCreated;
26+
use App\Notifications\PlaylistSuggestionRejected;
27+
use Illuminate\Support\Facades\Validator;
28+
use Illuminate\Validation\Rule;
29+
30+
class PlaylistSuggestionController extends Controller
31+
{
32+
/**
33+
* Store a new playlist.
34+
*/
35+
public function store(StorePlaylistSuggestionRequest $request, Playlist $playlist): \Illuminate\Http\RedirectResponse
36+
{
37+
Validator::make([
38+
'torrent_id' => basename($request->torrent_url)
39+
], [
40+
'torrent_id' => Rule::exists('torrents', 'id'),
41+
], [
42+
'torrent_id.exists' => 'The torrent ID/URL ":input" entered was not found on site.'
43+
])->validate();
44+
45+
$playlistSuggestion = PlaylistSuggestion::create([
46+
'playlist_id' => $playlist->id,
47+
'torrent_id' => basename($request->torrent_url),
48+
'user_id' => $request->user()->id,
49+
'message' => $request->message,
50+
]);
51+
52+
$playlist->user->notify(new PlaylistSuggestionCreated($playlistSuggestion));
53+
54+
return to_route('playlists.show', ['playlist' => $playlist])
55+
->with('success', trans('playlist.suggestion-review'));
56+
}
57+
58+
/**
59+
* Update a playlist suggestion.
60+
*/
61+
public function update(UpdatePlaylistSuggestionRequest $request, Playlist $playlist, PlaylistSuggestion $playlistSuggestion): \Illuminate\Http\RedirectResponse
62+
{
63+
abort_unless($request->user()->id == $playlist->user_id || $request->user()->group->is_modo, 403);
64+
65+
switch (ModerationStatus::from($request->integer('status'))) {
66+
case ModerationStatus::APPROVED:
67+
$playlistTorrent = PlaylistTorrent::create([
68+
'playlist_id' => $playlistSuggestion->playlist_id,
69+
'torrent_id' => $playlistSuggestion->torrent_id,
70+
]);
71+
72+
$playlistTorrent->torrent()->searchable();
73+
$playlistSuggestion->delete();
74+
75+
return to_route('playlists.show', ['playlist' => $playlist])
76+
->withFragment('#playlist_suggestions')
77+
->with('success', trans('playlist.suggestion-approved'));
78+
case ModerationStatus::REJECTED:
79+
$playlistSuggestion->user->notify(new PlaylistSuggestionRejected($playlistSuggestion, $request->rejection_message));
80+
$playlistSuggestion->delete();
81+
82+
return to_route('playlists.show', ['playlist' => $playlist])
83+
->withFragment('#playlist_suggestions')
84+
->with('success', trans('playlist.suggestion-rejected'));
85+
86+
default:
87+
return to_route('playlists.show', ['playlist' => $playlist]);
88+
}
89+
}
90+
}

app/Http/Livewire/NotificationSearch.php

+12
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ class NotificationSearch extends Component
4242
#[Url(history: true)]
4343
public bool $followers = false;
4444

45+
#[Url(history: true)]
46+
public bool $playlist_suggestions = false;
47+
48+
#[Url(history: true)]
49+
public bool $playlist_suggestion_rejections = false;
50+
4551
#[Url(history: true)]
4652
public bool $posts = false;
4753

@@ -118,6 +124,12 @@ final public function notifications(): \Illuminate\Pagination\LengthAwarePaginat
118124
->when($this->followers, function ($query): void {
119125
$query->orWhere('type', '=', \App\Notifications\NewFollow::class);
120126
})
127+
->when($this->playlist_suggestions, function ($query): void {
128+
$query->orWhere('type', '=', \App\Notifications\PlaylistSuggestionCreated::class);
129+
})
130+
->when($this->playlist_suggestion_rejections, function ($query): void {
131+
$query->orWhere('type', '=', \App\Notifications\PlaylistSuggestionRejected::class);
132+
})
121133
->when($this->posts, function ($query): void {
122134
$query->orWhere('type', '=', \App\Notifications\NewPost::class);
123135
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* NOTICE OF LICENSE.
7+
*
8+
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
9+
* The details is bundled with this project in the file LICENSE.txt.
10+
*
11+
* @project UNIT3D Community Edition
12+
*
13+
* @author Roardom <roardom@protonmail.com>
14+
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
15+
*/
16+
17+
namespace App\Http\Requests;
18+
19+
use Illuminate\Foundation\Http\FormRequest;
20+
use Illuminate\Http\Request;
21+
22+
class StorePlaylistSuggestionRequest extends FormRequest
23+
{
24+
/**
25+
* Get the validation rules that apply to the request.
26+
*
27+
* @return array<string, array<string>>
28+
*/
29+
public function rules(Request $request): array
30+
{
31+
return [
32+
'torrent_url' => [
33+
'required',
34+
'max:65535',
35+
],
36+
'message' => [
37+
'sometimes',
38+
'max:65535',
39+
],
40+
];
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* NOTICE OF LICENSE.
7+
*
8+
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
9+
* The details is bundled with this project in the file LICENSE.txt.
10+
*
11+
* @project UNIT3D Community Edition
12+
*
13+
* @author Roardom <roardom@protonmail.com>
14+
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
15+
*/
16+
17+
namespace App\Http\Requests;
18+
19+
use App\Enums\ModerationStatus;
20+
use Illuminate\Foundation\Http\FormRequest;
21+
use Illuminate\Http\Request;
22+
use Illuminate\Validation\Rule;
23+
24+
class UpdatePlaylistSuggestionRequest extends FormRequest
25+
{
26+
/**
27+
* Get the validation rules that apply to the request.
28+
*
29+
* @return array<string, array<string>>
30+
*/
31+
public function rules(Request $request): array
32+
{
33+
return [
34+
'status' => [
35+
'required',
36+
Rule::enum(ModerationStatus::class)->only([ModerationStatus::APPROVED, ModerationStatus::REJECTED]),
37+
],
38+
'rejection_message' => [
39+
'required_if:status,'.ModerationStatus::REJECTED->value,
40+
'max:65535',
41+
],
42+
];
43+
}
44+
}

app/Models/Playlist.php

+10
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ public function torrents(): \Illuminate\Database\Eloquent\Relations\BelongsToMan
6868
return $this->belongsToMany(Torrent::class, 'playlist_torrents')->using(PlaylistTorrent::class)->withPivot('id')->withTimestamps();
6969
}
7070

71+
/**
72+
* Has Many Torrents.
73+
*
74+
* @return \Illuminate\Database\Eloquent\Relations\HasMany<PlaylistSuggestion, $this>
75+
*/
76+
public function suggestions(): \Illuminate\Database\Eloquent\Relations\HasMany
77+
{
78+
return $this->hasMany(PlaylistSuggestion::class);
79+
}
80+
7181
/**
7282
* @return \Illuminate\Database\Eloquent\Relations\MorphMany<Comment, $this>
7383
*/

app/Models/PlaylistSuggestion.php

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* NOTICE OF LICENSE.
7+
*
8+
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
9+
* The details is bundled with this project in the file LICENSE.txt.
10+
*
11+
* @project UNIT3D Community Edition
12+
*
13+
* @author HDVinnie <hdinnovations@protonmail.com>
14+
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
15+
*/
16+
17+
namespace App\Models;
18+
19+
use App\Traits\Auditable;
20+
use Illuminate\Database\Eloquent\Model;
21+
22+
/**
23+
* App\Models\PlaylistSuggestion.
24+
*
25+
* @property int $id
26+
* @property int $playlist_id
27+
* @property int $torrent_id
28+
* @property int $user_id
29+
* @property string $description
30+
* @property \Illuminate\Support\Carbon|null $created_at
31+
* @property \Illuminate\Support\Carbon|null $updated_at
32+
*/
33+
class PlaylistSuggestion extends Model
34+
{
35+
use Auditable;
36+
37+
/**
38+
* The attributes that aren't mass assignable.
39+
*
40+
* @var string[]
41+
*/
42+
protected $guarded = [];
43+
44+
/**
45+
* Belongs to a torrent.
46+
*
47+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<Torrent, $this>
48+
*/
49+
public function torrent(): \Illuminate\Database\Eloquent\Relations\BelongsTo
50+
{
51+
return $this->belongsTo(Torrent::class);
52+
}
53+
54+
/**
55+
* Belongs to a User.
56+
*
57+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<User, $this>
58+
*/
59+
public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
60+
{
61+
return $this->belongsTo(User::class);
62+
}
63+
64+
/**
65+
* Belongs to a playlist.
66+
*
67+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<Playlist, $this>
68+
*/
69+
public function playlist(): \Illuminate\Database\Eloquent\Relations\BelongsTo
70+
{
71+
return $this->belongsTo(Playlist::class);
72+
}
73+
}

app/Models/User.php

+10
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,16 @@ public function playlists(): \Illuminate\Database\Eloquent\Relations\HasMany
454454
return $this->hasMany(Playlist::class);
455455
}
456456

457+
/**
458+
* Has Many Playlist Suggestions.
459+
*
460+
* @return \Illuminate\Database\Eloquent\Relations\HasMany<PlaylistSuggestion, $this>
461+
*/
462+
public function playlistSuggestions(): \Illuminate\Database\Eloquent\Relations\HasMany
463+
{
464+
return $this->hasMany(PlaylistSuggestion::class);
465+
}
466+
457467
/**
458468
* Has Many Sent PM's.
459469
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* NOTICE OF LICENSE.
7+
*
8+
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
9+
* The details is bundled with this project in the file LICENSE.txt.
10+
*
11+
* @project UNIT3D Community Edition
12+
*
13+
* @author Roardom <roardom@protonmail.com>
14+
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
15+
*/
16+
17+
namespace App\Notifications;
18+
19+
use App\Models\PlaylistSuggestion;
20+
use Illuminate\Bus\Queueable;
21+
use Illuminate\Contracts\Queue\ShouldQueue;
22+
use Illuminate\Notifications\Notification;
23+
24+
class PlaylistSuggestionCreated extends Notification implements ShouldQueue
25+
{
26+
use Queueable;
27+
28+
/**
29+
* PlaylistSuggestionCreated Constructor.
30+
*/
31+
public function __construct(public PlaylistSuggestion $playlistSuggestion)
32+
{
33+
}
34+
35+
/**
36+
* Get the notification's delivery channels.
37+
*
38+
* @return array<int, string>
39+
*/
40+
public function via(object $notifiable): array
41+
{
42+
return ['database'];
43+
}
44+
45+
/**
46+
* Get the array representation of the notification.
47+
*
48+
* @return array<string, mixed>
49+
*/
50+
public function toArray(object $notifiable): array
51+
{
52+
return [
53+
'title' => 'New Playlist Suggestion',
54+
'body' => 'A user has suggested a torrent for your playlist: '.$this->playlistSuggestion->playlist->name,
55+
'url' => '/playlists/'.$this->playlistSuggestion->playlist_id.'#playlist_suggestions',
56+
];
57+
}
58+
}

0 commit comments

Comments
 (0)