Skip to content

Commit c2f3a8d

Browse files
committed
Improve team admin permissions
We missed a few permission checks, like anybody was able to see the team list, and any team member was able to add new team members instead of just admins. The commit also adds basic rspecs to make sure the feature work.
1 parent 1729f30 commit c2f3a8d

File tree

4 files changed

+142
-2
lines changed

4 files changed

+142
-2
lines changed

app/controllers/team_members_controller.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class TeamMembersController < ApplicationController
66

77
def create
88
authorize_invite!
9+
return if performed?
910
username = params[:username].to_s.strip
1011
user = User.find_by(username: username)
1112
return redirect_to @team, alert: "User not found" unless user
@@ -24,6 +25,7 @@ def destroy
2425
redirect_to teams_path, notice: "You left the team"
2526
else
2627
authorize_admin!
28+
return if performed?
2729
if @team.last_admin?(membership)
2830
redirect_to @team, alert: "Cannot remove the last admin"
2931
else
@@ -40,12 +42,14 @@ def set_team
4042
end
4143

4244
def authorize_invite!
43-
return if @team.admin?(current_user) || @team.member?(current_user)
44-
redirect_to @team, alert: "Only team members can add users"
45+
return if @team.admin?(current_user)
46+
redirect_to @team, alert: "Admins only"
47+
return
4548
end
4649

4750
def authorize_admin!
4851
return if @team.admin?(current_user)
4952
redirect_to @team, alert: "Admins only"
53+
return
5054
end
5155
end

app/controllers/teams_controller.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
class TeamsController < ApplicationController
44
before_action :require_authentication, except: [:show, :index]
55
before_action :set_team, only: [:show, :destroy]
6+
before_action :require_team_member!, only: [:show]
67
before_action :require_team_admin!, only: [:destroy]
78

89
def index
@@ -47,4 +48,13 @@ def require_team_admin!
4748
redirect_to @team, alert: "Admins only" and return
4849
end
4950
end
51+
52+
def require_team_member!
53+
unless user_signed_in?
54+
redirect_to new_session_path, alert: "Please sign in"
55+
return
56+
end
57+
58+
render_404 unless @team.member?(current_user)
59+
end
5060
end

spec/requests/team_members_spec.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
require "rails_helper"
2+
3+
RSpec.describe "TeamMembers", type: :request do
4+
def sign_in(email:, password: "secret")
5+
post session_path, params: { email: email, password: password }
6+
expect(response).to redirect_to(root_path)
7+
end
8+
9+
def attach_verified_alias(user, email:, primary: true)
10+
al = create(:alias, user: user, email: email)
11+
if primary && user.person&.default_alias_id.nil?
12+
user.person.update!(default_alias_id: al.id)
13+
end
14+
Alias.by_email(email).update_all(verified_at: Time.current)
15+
al
16+
end
17+
18+
let!(:team) { create(:team) }
19+
let!(:admin) { create(:user, password: "secret", password_confirmation: "secret") }
20+
let!(:member) { create(:user, password: "secret", password_confirmation: "secret") }
21+
let!(:invitee) { create(:user, username: "invitee") }
22+
23+
before do
24+
create(:team_member, team: team, user: admin, role: "admin")
25+
create(:team_member, team: team, user: member, role: "member")
26+
end
27+
28+
describe "POST /teams/:team_id/team_members" do
29+
it "blocks non-admins from adding members" do
30+
attach_verified_alias(member, email: "member@example.com")
31+
sign_in(email: "member@example.com")
32+
33+
expect {
34+
post team_team_members_path(team), params: { username: "invitee" }
35+
}.not_to change(TeamMember, :count)
36+
expect(response).to redirect_to(team_path(team))
37+
end
38+
39+
it "allows admins to add members" do
40+
attach_verified_alias(admin, email: "admin@example.com")
41+
sign_in(email: "admin@example.com")
42+
43+
expect {
44+
post team_team_members_path(team), params: { username: "invitee" }
45+
}.to change(TeamMember, :count).by(1)
46+
expect(response).to redirect_to(team_path(team))
47+
end
48+
end
49+
end

spec/requests/teams_spec.rb

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
require "rails_helper"
2+
3+
RSpec.describe "Teams", type: :request do
4+
def sign_in(email:, password: "secret")
5+
post session_path, params: { email: email, password: password }
6+
expect(response).to redirect_to(root_path)
7+
end
8+
9+
def attach_verified_alias(user, email:, primary: true)
10+
al = create(:alias, user: user, email: email)
11+
if primary && user.person&.default_alias_id.nil?
12+
user.person.update!(default_alias_id: al.id)
13+
end
14+
Alias.by_email(email).update_all(verified_at: Time.current)
15+
al
16+
end
17+
18+
describe "GET /teams/:id" do
19+
let!(:team) { create(:team) }
20+
let!(:member) { create(:user, password: "secret", password_confirmation: "secret") }
21+
let!(:non_member) { create(:user, password: "secret", password_confirmation: "secret") }
22+
23+
before do
24+
create(:team_member, team: team, user: member)
25+
end
26+
27+
it "redirects guests to sign in" do
28+
get team_path(team)
29+
expect(response).to redirect_to(new_session_path)
30+
end
31+
32+
it "returns 404 for signed-in non-members" do
33+
attach_verified_alias(non_member, email: "non-member@example.com")
34+
sign_in(email: "non-member@example.com")
35+
36+
get team_path(team)
37+
expect(response).to have_http_status(:not_found)
38+
end
39+
40+
it "allows signed-in team members" do
41+
attach_verified_alias(member, email: "member@example.com")
42+
sign_in(email: "member@example.com")
43+
44+
get team_path(team)
45+
expect(response).to have_http_status(:success)
46+
end
47+
end
48+
49+
describe "DELETE /teams/:id" do
50+
let!(:team) { create(:team) }
51+
let!(:admin) { create(:user, password: "secret", password_confirmation: "secret") }
52+
let!(:member) { create(:user, password: "secret", password_confirmation: "secret") }
53+
54+
before do
55+
create(:team_member, team: team, user: admin, role: "admin")
56+
create(:team_member, team: team, user: member, role: "member")
57+
end
58+
59+
it "blocks non-admins from deleting teams" do
60+
attach_verified_alias(member, email: "member@example.com")
61+
sign_in(email: "member@example.com")
62+
63+
delete team_path(team)
64+
expect(response).to redirect_to(team_path(team))
65+
expect(Team.exists?(team.id)).to be(true)
66+
end
67+
68+
it "allows admins to delete teams" do
69+
attach_verified_alias(admin, email: "admin@example.com")
70+
sign_in(email: "admin@example.com")
71+
72+
expect {
73+
delete team_path(team)
74+
}.to change(Team, :count).by(-1)
75+
end
76+
end
77+
end

0 commit comments

Comments
 (0)