Skip to content
This repository was archived by the owner on Mar 14, 2025. It is now read-only.

Commit e3c9007

Browse files
authored
✨ Added (very simple) friendships feature (#80)
1 parent 626b249 commit e3c9007

14 files changed

+383
-11
lines changed

app/Friendship.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace App;
4+
5+
use Illuminate\Database\Eloquent\Factories\HasFactory;
6+
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
8+
9+
class Friendship extends Model {
10+
use HasFactory;
11+
12+
protected $fillable = ['user_id', 'friend_id'];
13+
14+
public function user(): BelongsTo {
15+
return $this->belongsTo(User::class, 'user_id', 'id');
16+
}
17+
18+
public function friend(): BelongsTo {
19+
return $this->belongsTo(User::class, 'friend_id', 'id');
20+
}
21+
}

app/FriendshipRequest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace App;
4+
5+
use Illuminate\Database\Eloquent\Factories\HasFactory;
6+
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
8+
9+
class FriendshipRequest extends Model {
10+
11+
use HasFactory;
12+
13+
protected $fillable = ['requester_id', 'user_id'];
14+
15+
public function requester(): BelongsTo {
16+
return $this->belongsTo(User::class, 'requester_id', 'id');
17+
}
18+
19+
public function user(): BelongsTo {
20+
return $this->belongsTo(User::class, 'user_id', 'id');
21+
}
22+
23+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use Illuminate\Contracts\Support\Renderable;
6+
use Illuminate\Http\RedirectResponse;
7+
use Illuminate\Validation\Rule;
8+
use Illuminate\Http\Request;
9+
use App\Friendship;
10+
use App\FriendshipRequest;
11+
use App\User;
12+
13+
class FriendshipController extends Controller {
14+
15+
public function renderFriendshipPage(): Renderable {
16+
17+
if(!auth()->user()->visible) {
18+
return view('social.friendship.not-visible');
19+
}
20+
21+
return view('social.friendship.overview');
22+
}
23+
24+
public function activateModule(): RedirectResponse {
25+
auth()->user()->update(['visible' => true]);
26+
return back();
27+
}
28+
29+
public function cancelFriendship(Request $request): RedirectResponse {
30+
$validated = $request->validate([
31+
'friend_id' => ['required', Rule::in(auth()->user()->friends->pluck('id'))]
32+
]);
33+
34+
Friendship::where('user_id', auth()->user()->id)->where('friend_id', $validated['friend_id'])->delete();
35+
Friendship::where('friend_id', auth()->user()->id)->where('user_id', $validated['friend_id'])->delete();
36+
37+
return back();
38+
}
39+
40+
public function requestFriendship(Request $request): RedirectResponse {
41+
$validated = $request->validate([
42+
'username' => [
43+
'required',
44+
'exists:users,username',
45+
Rule::notIn([auth()->user()->username]),
46+
Rule::notIn(auth()->user()->friends->pluck('username'))
47+
]
48+
]);
49+
50+
$requester = auth()->user();
51+
$user = User::where('username', $validated['username'])->firstOrFail();
52+
53+
if(!$user->visible) {
54+
return back()->with('alert-danger', 'Der angegebene Benutzer hat die Freundschaftsfunktion nicht aktiviert.');
55+
}
56+
57+
$otherRequest = FriendshipRequest::where('requester_id', $user->id)->where('user_id', $requester->id)->first();
58+
59+
if($otherRequest != null) {
60+
$otherRequest->delete();
61+
Friendship::create(['user_id' => $requester->id, 'friend_id' => $user->id]);
62+
Friendship::create(['user_id' => $user->id, 'friend_id' => $requester->id]);
63+
return back()->with('alert-success', 'Da der User dir auch eine Anfrage geschickt hat wurde die Freundschaft bestätigt.');
64+
}
65+
66+
FriendshipRequest::create([
67+
'requester_id' => $requester->id,
68+
'user_id' => $user->id
69+
]);
70+
71+
72+
return back()->with('alert-success', 'Die Anfrage wurde gespeichert. Um diese zu bestätigen muss der User deinen Usernamen ebenfalls anfragen.');
73+
}
74+
}

app/User.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
use Illuminate\Database\Eloquent\Relations\HasOne;
88
use Illuminate\Foundation\Auth\User as Authenticatable;
99
use Illuminate\Notifications\Notifiable;
10+
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
1011

1112
class User extends Authenticatable {
1213

1314
use Notifiable, HasFactory;
1415

15-
protected $fillable = ['username', 'email', 'password', 'last_login', 'privacy_confirmed_at'];
16+
protected $fillable = ['username', 'email', 'password', 'visible', 'last_login', 'privacy_confirmed_at'];
1617
protected $hidden = ['password', 'remember_token'];
1718
protected $dates = ['privacy_confirmed_at', 'last_login', 'email_verified_at'];
19+
protected $casts = ['visible' => 'boolean'];
1820

1921
public function socialProfile(): HasOne {
2022
if($this->hasOne(SocialLoginProfile::class)->count() == 0)
@@ -42,6 +44,10 @@ public function spotifySessions(): HasMany {
4244
return $this->hasMany(SpotifySession::class, 'user_id', 'id');
4345
}
4446

47+
public function friends(): BelongsToMany {
48+
return $this->belongsToMany(User::class, 'friendships', 'user_id', 'friend_id');
49+
}
50+
4551
public function reweReceipts(): HasMany {
4652
return $this->hasMany(ReweBon::class, 'user_id', 'id')->orderBy('timestamp_bon');
4753
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Database\Factories;
4+
5+
use App\Friendship;
6+
use Illuminate\Database\Eloquent\Factories\Factory;
7+
use App\User;
8+
use JetBrains\PhpStorm\ArrayShape;
9+
10+
class FriendshipFactory extends Factory {
11+
12+
protected $model = Friendship::class;
13+
14+
#[ArrayShape([
15+
'user_id' => "\Illuminate\Database\Eloquent\Factories\Factory",
16+
'friend_id' => "\Illuminate\Database\Eloquent\Factories\Factory"
17+
])]
18+
public function definition(): array {
19+
return [
20+
'user_id' => User::factory(),
21+
'friend_id' => User::factory()
22+
];
23+
}
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Database\Factories;
4+
5+
use App\FriendshipRequest;
6+
use Illuminate\Database\Eloquent\Factories\Factory;
7+
8+
class FriendshipRequestFactory extends Factory
9+
{
10+
/**
11+
* The name of the factory's corresponding model.
12+
*
13+
* @var string
14+
*/
15+
protected $model = FriendshipRequest::class;
16+
17+
/**
18+
* Define the model's default state.
19+
*
20+
* @return array
21+
*/
22+
public function definition()
23+
{
24+
return [
25+
//
26+
];
27+
}
28+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreateFriendshipsTable extends Migration {
8+
9+
public function up(): void {
10+
Schema::create('friendships', function(Blueprint $table) {
11+
$table->id();
12+
13+
$table->unsignedBigInteger('user_id');
14+
$table->unsignedBigInteger('friend_id');
15+
16+
$table->timestamps();
17+
18+
$table->unique(['user_id', 'friend_id']);
19+
20+
$table->foreign('user_id')
21+
->references('id')
22+
->on('users')
23+
->cascadeOnDelete();
24+
$table->foreign('friend_id')
25+
->references('id')
26+
->on('users')
27+
->cascadeOnDelete();
28+
});
29+
}
30+
31+
public function down(): void {
32+
Schema::dropIfExists('friendships');
33+
}
34+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class AddVisibleColumnToUsers extends Migration {
8+
9+
public function up(): void {
10+
Schema::table('users', function(Blueprint $table) {
11+
$table->boolean('visible')
12+
->comment('user is visible to others')
13+
->default(0)
14+
->after('password');
15+
});
16+
}
17+
18+
public function down(): void {
19+
Schema::table('users', function(Blueprint $table) {
20+
$table->dropColumn('visible');
21+
});
22+
}
23+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreateFriendshipRequestsTable extends Migration {
8+
9+
public function up(): void {
10+
Schema::create('friendship_requests', function(Blueprint $table) {
11+
$table->id();
12+
13+
$table->unsignedBigInteger('requester_id');
14+
$table->unsignedBigInteger('user_id');
15+
16+
$table->timestamps();
17+
18+
$table->unique(['requester_id', 'user_id']);
19+
20+
$table->foreign('requester_id')
21+
->references('id')
22+
->on('users')
23+
->cascadeOnDelete();
24+
$table->foreign('user_id')
25+
->references('id')
26+
->on('users')
27+
->cascadeOnDelete();
28+
});
29+
}
30+
31+
public function down(): void {
32+
Schema::dropIfExists('friendship_requests');
33+
}
34+
}

database/seeders/DatabaseSeeder.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@
66
use App\SpotifyTrack;
77
use App\User;
88
use Illuminate\Database\Seeder;
9+
use App\Friendship;
910

1011
class DatabaseSeeder extends Seeder {
11-
/**
12-
* Seed the application's database.
13-
*
14-
* @return void
15-
*/
16-
public function run() {
17-
User::factory()->create(['username' => 'john.doe']);
12+
13+
public function run(): void {
14+
$user = User::factory()->create(['username' => 'john.doe']);
15+
16+
foreach(User::factory(rand(3, 9))->create() as $friend) {
17+
Friendship::create(['user_id' => $user->id, 'friend_id' => $friend->id]);
18+
Friendship::create(['user_id' => $friend->id, 'friend_id' => $user->id]);
19+
}
1820

1921
$this->call(SocialLoginProfileSeeder::class);
2022

@@ -31,7 +33,7 @@ public function run() {
3133
$this->call(SpotifyArtistSeeder::class);
3234
SpotifyAlbum::factory(rand(5, 100))->create();
3335
$this->call(SpotifyAlbumArtistSeeder::class);
34-
SpotifyTrack::factory(rand(100, 1000))->create();
36+
SpotifyTrack::factory(rand(100, 100))->create();
3537
$this->call(SpotifyTrackArtistSeeder::class);
3638
$this->call(SpotifyDeviceSeeder::class);
3739
$this->call(SpotifyPlayActivitySeeder::class);

0 commit comments

Comments
 (0)