Skip to content

Commit 630fd51

Browse files
authored
Merge pull request ppy#12054 from nanaya/team-leader-change
Allow changing team leader
2 parents ce7dc30 + ba3a416 commit 630fd51

File tree

6 files changed

+115
-23
lines changed

6 files changed

+115
-23
lines changed

app/Http/Controllers/Teams/MembersController.php

+22
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use App\Http\Controllers\Controller;
1111
use App\Models\Team;
1212
use App\Models\TeamMember;
13+
use App\Models\User;
1314
use Symfony\Component\HttpFoundation\Response;
1415

1516
class MembersController extends Controller
@@ -48,4 +49,25 @@ public function index(string $teamId): Response
4849

4950
return ext_view('teams.members.index', compact('team'));
5051
}
52+
53+
public function setLeader(string $teamId, string $userId): Response
54+
{
55+
$newLeader = User::default()->findOrFail($userId);
56+
$team = Team::findOrFail($teamId);
57+
$teamMember = TeamMember::where([
58+
'team_id' => $team->getKey(),
59+
'user_id' => $newLeader->getKey(),
60+
])->firstOrFail();
61+
62+
priv_check('TeamUpdate', $team)->ensureCan();
63+
64+
$team->update(['leader_id' => $newLeader->getKey()]);
65+
66+
\Session::flash('popup', osu_trans(
67+
'teams.members.set_leader.success',
68+
['user' => $newLeader->username],
69+
));
70+
71+
return ujs_redirect(route('teams.show', $team));
72+
}
5173
}

resources/css/bem/team-members-manage.less

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
font-size: @font-size--title-small;
99
display: grid;
1010
gap: 2px 10px;
11-
grid-template-columns: 1fr auto auto auto;
11+
grid-template-columns: 1fr auto auto auto auto;
12+
13+
&--applications {
14+
grid-template-columns: 1fr auto auto auto;
15+
}
1216

1317
&__avatar {
1418
.default-border-radius();

resources/lang/en/teams.php

+11-2
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,22 @@
9494
'title' => 'Manage Members',
9595

9696
'applications' => [
97+
'accept_confirm' => 'Add user :user to team?',
98+
'created_at' => 'Requested At',
9799
'empty' => 'No join requests at the moment.',
98100
'empty_slots' => 'Available slots',
99101
'empty_slots_overflow' => ':count_delimited user overflow|:count_delimited users overflow',
102+
'reject_confirm' => 'Deny join request from user :user?',
100103
'title' => 'Join Requests',
101-
'created_at' => 'Requested At',
102104
],
103105

104106
'table' => [
105-
'status' => 'Status',
106107
'joined_at' => 'Join Date',
107108
'remove' => 'Remove',
109+
'remove_confirm' => 'Remove user :user from team?',
110+
'set_leader' => 'Transfer team leadership',
111+
'set_leader_confirm' => 'Transfer team leadership to user :user?',
112+
'status' => 'Status',
108113
'title' => 'Current Members',
109114
],
110115

@@ -113,6 +118,10 @@
113118
'status_1' => 'Active',
114119
],
115120
],
121+
122+
'set_leader' => [
123+
'success' => 'User :user is now the team leader.',
124+
],
116125
],
117126

118127
'part' => [

resources/views/teams/members/index.blade.php

+45-20
Original file line numberDiff line numberDiff line change
@@ -57,24 +57,43 @@ class="avatar avatar--full avatar--guest"
5757
<span>
5858
{!! timeago($member->created_at) !!}
5959
</span>
60-
<span>
61-
<form
62-
action="{{ route('teams.members.destroy', compact('member', 'team')) }}"
63-
class="u-contents"
64-
data-confirm="{{ osu_trans('common.confirmation') }}"
65-
data-reload-on-success="1"
66-
data-remote="1"
67-
method="POST"
60+
<form
61+
action="{{ route('teams.members.set-leader', compact('member', 'team')) }}"
62+
class="u-contents"
63+
data-turbo-confirm="{{ osu_trans(
64+
'teams.members.index.table.set_leader_confirm',
65+
['user' => $user->username],
66+
) }}"
67+
method="POST"
68+
>
69+
<button
70+
class="btn-osu-big btn-osu-big--rounded-small"
71+
{{ $member->user_id === $team->leader_id ? 'disabled' : '' }}
72+
title="{{ osu_trans('teams.members.index.table.set_leader') }}"
6873
>
69-
<input type="hidden" name="_method" value="DELETE" />
70-
<button
71-
class="btn-osu-big btn-osu-big--rounded-small"
72-
{{ $member->user_id === $team->leader_id ? 'disabled' : '' }}
73-
>
74-
{{ osu_trans('teams.members.index.table.remove') }}
75-
</button>
76-
</form>
77-
</span>
74+
<span class="fas fa-fw fa-user-cog"></span>
75+
</button>
76+
</form>
77+
<form
78+
action="{{ route('teams.members.destroy', compact('member', 'team')) }}"
79+
class="u-contents"
80+
data-confirm="{{ osu_trans(
81+
'teams.members.index.table.remove_confirm',
82+
['user' => $user->username],
83+
) }}"
84+
data-reload-on-success="1"
85+
data-remote="1"
86+
method="POST"
87+
>
88+
<input type="hidden" name="_method" value="DELETE" />
89+
<button
90+
class="btn-osu-big btn-osu-big--rounded-small"
91+
{{ $member->user_id === $team->leader_id ? 'disabled' : '' }}
92+
title="{{ osu_trans('teams.members.index.table.remove') }}"
93+
>
94+
<span class="fas fa-fw fa-times"></span>
95+
</button>
96+
</form>
7897
@endforeach
7998
</ul>
8099
</div>
@@ -96,7 +115,7 @@ class="btn-osu-big btn-osu-big--rounded-small"
96115
@if ($team->applications->isEmpty())
97116
{{ osu_trans('teams.members.index.applications.empty') }}
98117
@else
99-
<ul class="team-members-manage">
118+
<ul class="team-members-manage team-members-manage--applications">
100119
<li class="team-members-manage__item team-members-manage__item--header">
101120
<span></span>
102121
<span>{{ osu_trans('teams.members.index.applications.created_at') }}</span>
@@ -131,7 +150,10 @@ class="avatar avatar--full avatar--guest"
131150
<form
132151
action="{{ route('teams.applications.accept', compact('application', 'team')) }}"
133152
class="u-contents"
134-
data-confirm="{{ osu_trans('common.confirmation') }}"
153+
data-confirm="{{ osu_trans(
154+
'teams.members.index.applications.accept_confirm',
155+
['user' => $user->username],
156+
) }}"
135157
data-reload-on-success="1"
136158
data-remote="1"
137159
method="POST"
@@ -145,7 +167,10 @@ class="u-contents"
145167
<form
146168
action="{{ route('teams.applications.reject', compact('application', 'team')) }}"
147169
class="u-contents"
148-
data-confirm="{{ osu_trans('common.confirmation') }}"
170+
data-confirm="{{ osu_trans(
171+
'teams.members.index.applications.reject_confirm',
172+
['user' => $user->username],
173+
) }}"
149174
data-reload-on-success="1"
150175
data-remote="1"
151176
method="POST"

routes/web.php

+1
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@
302302
Route::get('leaderboard/{ruleset?}', 'TeamsController@leaderboard')->name('leaderboard');
303303
Route::post('part', 'TeamsController@part')->name('part');
304304
Route::resource('members', 'Teams\MembersController', ['only' => ['destroy', 'index']]);
305+
Route::post('members/{member}/set-leader', 'Teams\MembersController@setLeader')->name('members.set-leader');
305306
});
306307
Route::resource('teams', 'TeamsController', ['only' => ['create', 'destroy', 'edit', 'store', 'update']]);
307308
Route::get('teams/{team}/{ruleset?}', 'TeamsController@show')->name('teams.show');

tests/Controllers/Teams/MembersControllerTest.php

+31
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,35 @@ public function testDestroy()
2626
->delete(route('teams.members.destroy', ['team' => $team->getKey(), 'member' => $userId]))
2727
->assertStatus(204);
2828
}
29+
30+
public function testSetLeader(): void
31+
{
32+
$team = Team::factory()->create();
33+
$initialLeader = $team->leader;
34+
$user = User::factory()->create();
35+
$application = $team->applications()->create(['user_id' => $user->getKey()]);
36+
$team->addMember($application);
37+
38+
$this
39+
->actingAsVerified($user)
40+
->get(route('teams.members.index', ['team' => $team->getKey()]))
41+
->assertStatus(403);
42+
43+
$this
44+
->actingAsVerified($initialLeader)
45+
->post(route('teams.members.set-leader', ['team' => $team->getKey(), 'member' => $user->getKey()]))
46+
->assertRedirect();
47+
48+
$this->assertSame($user->getKey(), $team->fresh()->leader_id);
49+
50+
$this
51+
->actingAsVerified($initialLeader)
52+
->get(route('teams.members.index', ['team' => $team->getKey()]))
53+
->assertStatus(403);
54+
55+
$this
56+
->actingAsVerified($user)
57+
->get(route('teams.members.index', ['team' => $team->getKey()]))
58+
->assertStatus(200);
59+
}
2960
}

0 commit comments

Comments
 (0)