mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
FIX: Hide delete button to invite as user are unable to delete anyway (#21884)
Moderators are not allowed to delete invites that don't belong to them
This commit is contained in:
parent
6642958706
commit
d2ef490e9a
|
@ -184,24 +184,26 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="invite-actions">
|
{{#if invite.can_delete_invite}}
|
||||||
<DButton
|
<td class="invite-actions">
|
||||||
@class="btn-default"
|
<DButton
|
||||||
@icon="pencil-alt"
|
@class="btn-default"
|
||||||
@action={{action "editInvite" invite}}
|
@icon="pencil-alt"
|
||||||
@title="user.invited.edit"
|
@action={{action "editInvite" invite}}
|
||||||
/>
|
@title="user.invited.edit"
|
||||||
<DButton
|
/>
|
||||||
@icon="trash-alt"
|
<DButton
|
||||||
@class="cancel"
|
@icon="trash-alt"
|
||||||
@action={{action "destroyInvite" invite}}
|
@class="cancel"
|
||||||
@title={{if
|
@action={{action "destroyInvite" invite}}
|
||||||
invite.destroyed
|
@title={{if
|
||||||
"user.invited.removed"
|
invite.destroyed
|
||||||
"user.invited.remove"
|
"user.invited.removed"
|
||||||
}}
|
"user.invited.remove"
|
||||||
/>
|
}}
|
||||||
</td>
|
/>
|
||||||
|
</td>
|
||||||
|
{{/if}}
|
||||||
</tr>
|
</tr>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { click, fillIn, visit } from "@ember/test-helpers";
|
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||||
import {
|
import {
|
||||||
acceptance,
|
acceptance,
|
||||||
count,
|
|
||||||
exists,
|
exists,
|
||||||
fakeTime,
|
fakeTime,
|
||||||
loggedInUser,
|
loggedInUser,
|
||||||
|
@ -57,15 +56,15 @@ acceptance("Invites - Create & Edit Invite Modal", function (needs) {
|
||||||
await visit("/u/eviltrout/invited/pending");
|
await visit("/u/eviltrout/invited/pending");
|
||||||
await click(".user-invite-buttons .btn:first-child");
|
await click(".user-invite-buttons .btn:first-child");
|
||||||
|
|
||||||
assert.ok(!exists("tbody tr"), "does not show invite before saving");
|
assert
|
||||||
|
.dom("table.user-invite-list tbody tr")
|
||||||
|
.exists({ count: 2 }, "is seeded with two rows");
|
||||||
|
|
||||||
await click(".btn-primary");
|
await click(".btn-primary");
|
||||||
|
|
||||||
assert.strictEqual(
|
assert
|
||||||
count("tbody tr"),
|
.dom("table.user-invite-list tbody tr")
|
||||||
1,
|
.exists({ count: 3 }, "gets added to the list");
|
||||||
"adds invite to list after saving"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("copying saves invite", async function (assert) {
|
test("copying saves invite", async function (assert) {
|
||||||
|
|
|
@ -224,7 +224,40 @@ export function applyDefaultHandlers(pretender) {
|
||||||
|
|
||||||
pretender.get("/u/eviltrout/invited.json", () => {
|
pretender.get("/u/eviltrout/invited.json", () => {
|
||||||
return response({
|
return response({
|
||||||
invites: [],
|
invites: [
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
invite_key: "hMFT8G1oKP",
|
||||||
|
link: "http://localhost:3000/invites/hMFT8G1oKP",
|
||||||
|
email: "steak@cat.com",
|
||||||
|
domain: null,
|
||||||
|
emailed: false,
|
||||||
|
can_delete_invite: true,
|
||||||
|
custom_message: null,
|
||||||
|
created_at: "2023-06-01T04:47:13.195Z",
|
||||||
|
updated_at: "2023-06-01T04:47:13.195Z",
|
||||||
|
expires_at: "2023-08-30T04:47:00.000Z",
|
||||||
|
expired: false,
|
||||||
|
topics: [],
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
invite_key: "hMFT8G1WHA",
|
||||||
|
link: "http://localhost:3000/invites/hMFT8G1WHA",
|
||||||
|
email: "tomtom@cat.com",
|
||||||
|
domain: null,
|
||||||
|
emailed: false,
|
||||||
|
can_delete_invite: false,
|
||||||
|
custom_message: null,
|
||||||
|
created_at: "2023-06-01T04:47:13.195Z",
|
||||||
|
updated_at: "2023-06-01T04:47:13.195Z",
|
||||||
|
expires_at: "2023-08-30T04:47:00.000Z",
|
||||||
|
expired: false,
|
||||||
|
topics: [],
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
can_see_invite_details: true,
|
can_see_invite_details: true,
|
||||||
counts: {
|
counts: {
|
||||||
pending: 0,
|
pending: 0,
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { visit } from "@ember/test-helpers";
|
||||||
|
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import { test } from "qunit";
|
||||||
|
|
||||||
|
acceptance("User invites", function (needs) {
|
||||||
|
needs.user();
|
||||||
|
|
||||||
|
test("hides delete button based on can_delete_invite", async function (assert) {
|
||||||
|
await visit("/u/eviltrout/invited");
|
||||||
|
|
||||||
|
assert.dom("table.user-invite-list tbody tr").exists({ count: 2 });
|
||||||
|
assert
|
||||||
|
.dom("table.user-invite-list tbody tr:nth-child(1) button.cancel")
|
||||||
|
.exists();
|
||||||
|
assert
|
||||||
|
.dom("table.user-invite-list tbody tr:nth-child(2) button.cancel")
|
||||||
|
.doesNotExist();
|
||||||
|
});
|
||||||
|
});
|
|
@ -7,6 +7,7 @@ class InviteSerializer < ApplicationSerializer
|
||||||
:email,
|
:email,
|
||||||
:domain,
|
:domain,
|
||||||
:emailed,
|
:emailed,
|
||||||
|
:can_delete_invite,
|
||||||
:max_redemptions_allowed,
|
:max_redemptions_allowed,
|
||||||
:redemption_count,
|
:redemption_count,
|
||||||
:custom_message,
|
:custom_message,
|
||||||
|
@ -30,6 +31,10 @@ class InviteSerializer < ApplicationSerializer
|
||||||
object.emailed_status != Invite.emailed_status_types[:not_required]
|
object.emailed_status != Invite.emailed_status_types[:not_required]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_delete_invite
|
||||||
|
scope.is_admin? || object.invited_by_id == scope.current_user.id
|
||||||
|
end
|
||||||
|
|
||||||
def include_custom_message?
|
def include_custom_message?
|
||||||
email.present?
|
email.present?
|
||||||
end
|
end
|
||||||
|
|
37
spec/serializers/invite_serializer_spec.rb
Normal file
37
spec/serializers/invite_serializer_spec.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe InviteSerializer do
|
||||||
|
describe "#can_delete_invite" do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
fab!(:admin) { Fabricate(:admin) }
|
||||||
|
fab!(:moderator) { Fabricate(:moderator) }
|
||||||
|
fab!(:invite_from_user) { Fabricate(:invite, invited_by: user) }
|
||||||
|
fab!(:invite_from_moderator) { Fabricate(:invite, invited_by: moderator) }
|
||||||
|
|
||||||
|
it "returns true for admin" do
|
||||||
|
serializer = InviteSerializer.new(invite_from_user, scope: Guardian.new(admin), root: false)
|
||||||
|
|
||||||
|
expect(serializer.as_json[:can_delete_invite]).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false for moderator" do
|
||||||
|
serializer =
|
||||||
|
InviteSerializer.new(invite_from_user, scope: Guardian.new(moderator), root: false)
|
||||||
|
|
||||||
|
expect(serializer.as_json[:can_delete_invite]).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true for inviter" do
|
||||||
|
serializer = InviteSerializer.new(invite_from_user, scope: Guardian.new(user), root: false)
|
||||||
|
|
||||||
|
expect(serializer.as_json[:can_delete_invite]).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false for plain user" do
|
||||||
|
serializer =
|
||||||
|
InviteSerializer.new(invite_from_moderator, scope: Guardian.new(user), root: false)
|
||||||
|
|
||||||
|
expect(serializer.as_json[:can_delete_invite]).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user