mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: explain why invites are disabled to staff users (#10810)
Co-authored-by: Robin Ward <robin.ward@gmail.com>
This commit is contained in:
parent
97f34d7b71
commit
9b45391cf9
@ -145,5 +145,9 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</section>
|
</section>
|
||||||
{{/load-more}}
|
{{/load-more}}
|
||||||
|
{{else}}
|
||||||
|
<div class="alert alert-error invite-error">
|
||||||
|
{{model.error}}
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/d-section}}
|
{{/d-section}}
|
||||||
|
@ -782,3 +782,9 @@
|
|||||||
.timezone-input {
|
.timezone-input {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-invites-page {
|
||||||
|
.invite-error {
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@ class UsersController < ApplicationController
|
|||||||
:update_second_factor, :create_second_factor_backup, :select_avatar,
|
:update_second_factor, :create_second_factor_backup, :select_avatar,
|
||||||
:notification_level, :revoke_auth_token, :register_second_factor_security_key,
|
:notification_level, :revoke_auth_token, :register_second_factor_security_key,
|
||||||
:create_second_factor_security_key, :feature_topic, :clear_featured_topic,
|
:create_second_factor_security_key, :feature_topic, :clear_featured_topic,
|
||||||
:bookmarks, :invited
|
:bookmarks, :invited, :invite_links
|
||||||
]
|
]
|
||||||
|
|
||||||
skip_before_action :check_xhr, only: [
|
skip_before_action :check_xhr, only: [
|
||||||
@ -369,57 +369,87 @@ class UsersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def invited
|
def invited
|
||||||
guardian.ensure_can_invite_to_forum!
|
if guardian.can_invite_to_forum?
|
||||||
|
offset = params[:offset].to_i || 0
|
||||||
|
filter_by = params[:filter] || "redeemed"
|
||||||
|
inviter = fetch_user_from_params(include_inactive: current_user.staff? || SiteSetting.show_inactive_accounts)
|
||||||
|
|
||||||
offset = params[:offset].to_i || 0
|
invites = if guardian.can_see_invite_details?(inviter) && filter_by == "pending"
|
||||||
filter_by = params[:filter] || "redeemed"
|
Invite.find_pending_invites_from(inviter, offset)
|
||||||
inviter = fetch_user_from_params(include_inactive: current_user.staff? || SiteSetting.show_inactive_accounts)
|
elsif filter_by == "redeemed"
|
||||||
|
Invite.find_redeemed_invites_from(inviter, offset)
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
invites = if guardian.can_see_invite_details?(inviter) && filter_by == "pending"
|
show_emails = guardian.can_see_invite_emails?(inviter)
|
||||||
Invite.find_pending_invites_from(inviter, offset)
|
if params[:search].present? && invites.present?
|
||||||
elsif filter_by == "redeemed"
|
filter_sql = '(LOWER(users.username) LIKE :filter)'
|
||||||
Invite.find_redeemed_invites_from(inviter, offset)
|
filter_sql = '(LOWER(invites.email) LIKE :filter) or (LOWER(users.username) LIKE :filter)' if show_emails
|
||||||
|
invites = invites.where(filter_sql, filter: "%#{params[:search].downcase}%")
|
||||||
|
end
|
||||||
|
|
||||||
|
render json: MultiJson.dump(InvitedSerializer.new(
|
||||||
|
OpenStruct.new(invite_list: invites.to_a, show_emails: show_emails, inviter: inviter, type: filter_by),
|
||||||
|
scope: guardian,
|
||||||
|
root: false
|
||||||
|
))
|
||||||
else
|
else
|
||||||
[]
|
if current_user&.staff?
|
||||||
end
|
message = if SiteSetting.enable_sso
|
||||||
|
I18n.t("invite.disabled_errors.sso_enabled")
|
||||||
|
elsif !SiteSetting.enable_local_logins
|
||||||
|
I18n.t("invite.disabled_errors.local_logins_disabled")
|
||||||
|
end
|
||||||
|
|
||||||
show_emails = guardian.can_see_invite_emails?(inviter)
|
render_invite_error(message)
|
||||||
if params[:search].present? && invites.present?
|
else
|
||||||
filter_sql = '(LOWER(users.username) LIKE :filter)'
|
render_json_error(I18n.t("invite.disabled_errors.invalid_access"))
|
||||||
filter_sql = '(LOWER(invites.email) LIKE :filter) or (LOWER(users.username) LIKE :filter)' if show_emails
|
end
|
||||||
invites = invites.where(filter_sql, filter: "%#{params[:search].downcase}%")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: MultiJson.dump(InvitedSerializer.new(
|
|
||||||
OpenStruct.new(invite_list: invites.to_a, show_emails: show_emails, inviter: inviter, type: filter_by),
|
|
||||||
scope: guardian,
|
|
||||||
root: false
|
|
||||||
))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def invite_links
|
def invite_links
|
||||||
guardian.ensure_can_invite_to_forum!
|
if guardian.can_invite_to_forum?
|
||||||
|
inviter = fetch_user_from_params(include_inactive: current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts))
|
||||||
|
guardian.ensure_can_see_invite_details!(inviter)
|
||||||
|
|
||||||
inviter = fetch_user_from_params(include_inactive: current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts))
|
offset = params[:offset].to_i || 0
|
||||||
guardian.ensure_can_see_invite_details!(inviter)
|
invites = Invite.find_links_invites_from(inviter, offset)
|
||||||
|
|
||||||
offset = params[:offset].to_i || 0
|
render json: MultiJson.dump(invites: serialize_data(invites.to_a, InviteLinkSerializer), can_see_invite_details: guardian.can_see_invite_details?(inviter))
|
||||||
invites = Invite.find_links_invites_from(inviter, offset)
|
else
|
||||||
|
if current_user&.staff?
|
||||||
|
message = if SiteSetting.enable_sso
|
||||||
|
I18n.t("invite.disabled_errors.sso_enabled")
|
||||||
|
elsif !SiteSetting.enable_local_logins
|
||||||
|
I18n.t("invite.disabled_errors.local_logins_disabled")
|
||||||
|
end
|
||||||
|
|
||||||
render json: MultiJson.dump(invites: serialize_data(invites.to_a, InviteLinkSerializer), can_see_invite_details: guardian.can_see_invite_details?(inviter))
|
render_invite_error(message)
|
||||||
|
else
|
||||||
|
render_json_error(I18n.t("invite.disabled_errors.invalid_access"))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def invited_count
|
def invited_count
|
||||||
guardian.ensure_can_invite_to_forum!
|
if guardian.can_invite_to_forum?
|
||||||
|
inviter = fetch_user_from_params(include_inactive: current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts))
|
||||||
|
|
||||||
inviter = fetch_user_from_params(include_inactive: current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts))
|
pending_count = Invite.find_pending_invites_count(inviter)
|
||||||
|
redeemed_count = Invite.find_redeemed_invites_count(inviter)
|
||||||
|
links_count = Invite.find_links_invites_count(inviter)
|
||||||
|
|
||||||
pending_count = Invite.find_pending_invites_count(inviter)
|
render json: { counts: { pending: pending_count, redeemed: redeemed_count, links: links_count,
|
||||||
redeemed_count = Invite.find_redeemed_invites_count(inviter)
|
total: (pending_count.to_i + redeemed_count.to_i) } }
|
||||||
links_count = Invite.find_links_invites_count(inviter)
|
else
|
||||||
|
if current_user&.staff?
|
||||||
render json: { counts: { pending: pending_count, redeemed: redeemed_count, links: links_count,
|
render json: { counts: 0 }
|
||||||
total: (pending_count.to_i + redeemed_count.to_i) } }
|
else
|
||||||
|
render_json_error(I18n.t("invite.disabled_errors.invalid_access"))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_local_username
|
def is_local_username
|
||||||
@ -1639,4 +1669,12 @@ class UsersController < ApplicationController
|
|||||||
def summary_cache_key(user)
|
def summary_cache_key(user)
|
||||||
"user_summary:#{user.id}:#{current_user ? current_user.id : 0}"
|
"user_summary:#{user.id}:#{current_user ? current_user.id : 0}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_invite_error(message)
|
||||||
|
render json: {
|
||||||
|
invites: [],
|
||||||
|
can_see_invite_details: false,
|
||||||
|
error: message
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -218,6 +218,10 @@ en:
|
|||||||
user_exists: "There's no need to invite <b>%{email}</b>, they <a href='%{base_path}/u/%{username}/summary'>already have an account!</a>"
|
user_exists: "There's no need to invite <b>%{email}</b>, they <a href='%{base_path}/u/%{username}/summary'>already have an account!</a>"
|
||||||
confirm_email: "<p>You’re almost done! We sent an activation mail to your email address. Please follow the instructions in the mail to activate your account.</p><p>If it doesn’t arrive, check your spam folder.</p>"
|
confirm_email: "<p>You’re almost done! We sent an activation mail to your email address. Please follow the instructions in the mail to activate your account.</p><p>If it doesn’t arrive, check your spam folder.</p>"
|
||||||
cant_invite_to_group: "You are not allowed to invite users to specified group(s). Make sure you are owner of the group(s) you are trying to invite to."
|
cant_invite_to_group: "You are not allowed to invite users to specified group(s). Make sure you are owner of the group(s) you are trying to invite to."
|
||||||
|
disabled_errors:
|
||||||
|
sso_enabled: "Invites are disabled because SSO is enabled."
|
||||||
|
local_logins_disabled: "Invites are disabled because the 'enable local logins' setting is disabled."
|
||||||
|
invalid_access: "You are not permitted to view the requested resource."
|
||||||
|
|
||||||
bulk_invite:
|
bulk_invite:
|
||||||
file_should_be_csv: "The uploaded file should be of csv format."
|
file_should_be_csv: "The uploaded file should be of csv format."
|
||||||
|
@ -1556,7 +1556,7 @@ describe UsersController do
|
|||||||
it "fails for anonymous users" do
|
it "fails for anonymous users" do
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
get "/u/#{user.username}/invited_count.json"
|
get "/u/#{user.username}/invited_count.json"
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(422)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "works for users who can see invites" do
|
it "works for users who can see invites" do
|
||||||
@ -1713,7 +1713,7 @@ describe UsersController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
get "/u/#{inviter.username}/invited/pending.json"
|
get "/u/#{inviter.username}/invited/pending.json"
|
||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(422)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1760,6 +1760,21 @@ describe UsersController do
|
|||||||
expect(response.status).to eq(403)
|
expect(response.status).to eq(403)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when local logins are disabled' do
|
||||||
|
it 'explains why invites are disabled to staff users' do
|
||||||
|
SiteSetting.enable_local_logins = false
|
||||||
|
inviter = sign_in(Fabricate(:admin))
|
||||||
|
Fabricate(:invite, invited_by: inviter, email: nil, max_redemptions_allowed: 5, expires_at: 1.month.from_now, emailed_status: Invite.emailed_status_types[:not_required])
|
||||||
|
|
||||||
|
get "/u/#{inviter.username}/invite_links.json"
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
expect(response.parsed_body['error']).to include(I18n.t(
|
||||||
|
'invite.disabled_errors.local_logins_disabled'
|
||||||
|
))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user