DEV: upgrade reject reason reviewable modal to glimmer component (#24073)
* DEV: add system test for rejecting user from review page * DEV: upgrade reject-reason-reviewable modal to glimmer & DModal
This commit is contained in:
parent
d5e8bd790b
commit
44c84413fb
|
@ -0,0 +1,30 @@
|
||||||
|
<DModal
|
||||||
|
@bodyClass="reject-reason-reviewable-modal__explain-reviewable"
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
@title={{i18n "review.reject_reason.title"}}
|
||||||
|
class="reject-reason-reviewable-modal"
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
<Textarea @value={{this.rejectReason}} />
|
||||||
|
<div class="control-group">
|
||||||
|
<label>
|
||||||
|
<Input
|
||||||
|
@type="checkbox"
|
||||||
|
class="reject-reason-reviewable-modal__send_email--inline"
|
||||||
|
@checked={{this.sendEmail}}
|
||||||
|
/>
|
||||||
|
{{i18n "review.reject_reason.send_email"}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</:body>
|
||||||
|
|
||||||
|
<:footer>
|
||||||
|
<DButton
|
||||||
|
@icon="trash-alt"
|
||||||
|
@action={{this.perform}}
|
||||||
|
@label="admin.user.delete"
|
||||||
|
class="btn-danger"
|
||||||
|
/>
|
||||||
|
<DButton @action={{@closeModal}} @label="cancel" class="cancel" />
|
||||||
|
</:footer>
|
||||||
|
</DModal>
|
|
@ -0,0 +1,17 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
|
||||||
|
export default class RejectReasonReviewableModal extends Component {
|
||||||
|
rejectReason;
|
||||||
|
sendEmail = false;
|
||||||
|
|
||||||
|
@action
|
||||||
|
async perform() {
|
||||||
|
this.args.model.reviewable.setProperties({
|
||||||
|
rejectReason: this.rejectReason,
|
||||||
|
sendEmail: this.sendEmail,
|
||||||
|
});
|
||||||
|
this.args.closeModal();
|
||||||
|
await this.args.model.performConfirmed(this.args.model.action);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,11 @@ import { action, set } from "@ember/object";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import { classify, dasherize } from "@ember/string";
|
import { classify, dasherize } from "@ember/string";
|
||||||
import ExplainReviewableModal from "discourse/components/modal/explain-reviewable";
|
import ExplainReviewableModal from "discourse/components/modal/explain-reviewable";
|
||||||
|
import RejectReasonReviewableModal from "discourse/components/modal/reject-reason-reviewable";
|
||||||
import ReviseAndRejectPostReviewable from "discourse/components/modal/revise-and-reject-post-reviewable";
|
import ReviseAndRejectPostReviewable from "discourse/components/modal/revise-and-reject-post-reviewable";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import optionalService from "discourse/lib/optional-service";
|
import optionalService from "discourse/lib/optional-service";
|
||||||
import showModal from "discourse/lib/show-modal";
|
|
||||||
import Category from "discourse/models/category";
|
import Category from "discourse/models/category";
|
||||||
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
@ -299,22 +299,15 @@ export default Component.extend({
|
||||||
const requireRejectReason = performableAction.get(
|
const requireRejectReason = performableAction.get(
|
||||||
"require_reject_reason"
|
"require_reject_reason"
|
||||||
);
|
);
|
||||||
const actionModalClass =
|
const actionModalClass = requireRejectReason
|
||||||
actionModalClassMap[performableAction.server_action];
|
? RejectReasonReviewableModal
|
||||||
|
: actionModalClassMap[performableAction.server_action];
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
this.dialog.confirm({
|
this.dialog.confirm({
|
||||||
message,
|
message,
|
||||||
didConfirm: () => this._performConfirmed(performableAction),
|
didConfirm: () => this._performConfirmed(performableAction),
|
||||||
});
|
});
|
||||||
} else if (requireRejectReason) {
|
|
||||||
showModal("reject-reason-reviewable", {
|
|
||||||
title: "review.reject_reason.title",
|
|
||||||
model: this.reviewable,
|
|
||||||
}).setProperties({
|
|
||||||
performConfirmed: this._performConfirmed,
|
|
||||||
action: performableAction,
|
|
||||||
});
|
|
||||||
} else if (actionModalClass) {
|
} else if (actionModalClass) {
|
||||||
this.modal.show(actionModalClass, {
|
this.modal.show(actionModalClass, {
|
||||||
model: {
|
model: {
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
import Controller from "@ember/controller";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
|
||||||
|
|
||||||
export default Controller.extend(ModalFunctionality, {
|
|
||||||
rejectReason: null,
|
|
||||||
sendEmail: false,
|
|
||||||
|
|
||||||
onShow() {
|
|
||||||
this.setProperties({ rejectReason: null, sendEmail: false });
|
|
||||||
},
|
|
||||||
|
|
||||||
@action
|
|
||||||
perform() {
|
|
||||||
this.model.setProperties({
|
|
||||||
rejectReason: this.rejectReason,
|
|
||||||
sendEmail: this.sendEmail,
|
|
||||||
});
|
|
||||||
this.send("closeModal");
|
|
||||||
this.performConfirmed(this.action);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,23 +0,0 @@
|
||||||
<DModalBody @class="explain-reviewable">
|
|
||||||
<Textarea @value={{this.rejectReason}} />
|
|
||||||
<div class="control-group">
|
|
||||||
<label>
|
|
||||||
<Input @type="checkbox" class="inline" @checked={{this.sendEmail}} />
|
|
||||||
{{i18n "review.reject_reason.send_email"}}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</DModalBody>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<DButton
|
|
||||||
@icon="trash-alt"
|
|
||||||
@action={{this.perform}}
|
|
||||||
@label="admin.user.delete"
|
|
||||||
class="btn-danger"
|
|
||||||
/>
|
|
||||||
<DButton
|
|
||||||
@action={{route-action "closeModal"}}
|
|
||||||
@label="cancel"
|
|
||||||
class="cancel"
|
|
||||||
/>
|
|
||||||
</div>
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module PageObjects
|
||||||
|
module Modals
|
||||||
|
class RejectReasonReviewable < PageObjects::Modals::Base
|
||||||
|
def modal
|
||||||
|
find(".reject-reason-reviewable-modal")
|
||||||
|
end
|
||||||
|
|
||||||
|
def select_send_rejection_email_checkbox
|
||||||
|
modal.find(".reject-reason-reviewable-modal__send_email--inline").check
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_in_rejection_reason(reason)
|
||||||
|
modal.find(".reject-reason-reviewable-modal__explain-reviewable textarea").fill_in(
|
||||||
|
with: reason,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_user
|
||||||
|
modal.find(".modal-footer .btn.btn-danger").click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -64,6 +64,13 @@ module PageObjects
|
||||||
within(reviewable_by_id(reviewable.id)) { page.has_css?(".status .rejected") }
|
within(reviewable_by_id(reviewable.id)) { page.has_css?(".status .rejected") }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_reviewable_with_rejection_reason?(reviewable, rejection_reason)
|
||||||
|
reviewable_by_id(reviewable.id).has_css?(
|
||||||
|
".reviewable-user-details.reject-reason .value",
|
||||||
|
text: rejection_reason,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def has_error_dialog_visible?
|
def has_error_dialog_visible?
|
||||||
page.has_css?(".dialog-container .dialog-content")
|
page.has_css?(".dialog-container .dialog-content")
|
||||||
end
|
end
|
||||||
|
|
|
@ -56,6 +56,39 @@ describe "Reviewables", type: :system do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "when there is a reviewable user" do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
let(:rejection_reason_modal) { PageObjects::Modals::RejectReasonReviewable.new }
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.must_approve_users = true
|
||||||
|
Jobs.run_immediately!
|
||||||
|
user.update!(approved: false)
|
||||||
|
user.activate
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Rejecting user sends rejection email and updates reviewable with rejection reason" do
|
||||||
|
rejection_reason = "user is spamming"
|
||||||
|
reviewable = ReviewableUser.find_by_target_id(user.id)
|
||||||
|
# cache it for later assertion instead of querying UserHistory
|
||||||
|
user_email = user.email
|
||||||
|
|
||||||
|
review_page.visit_reviewable(reviewable)
|
||||||
|
review_page.select_bundled_action(reviewable, "user-delete_user")
|
||||||
|
rejection_reason_modal.fill_in_rejection_reason(rejection_reason)
|
||||||
|
rejection_reason_modal.select_send_rejection_email_checkbox
|
||||||
|
rejection_reason_modal.delete_user
|
||||||
|
|
||||||
|
expect(review_page).to have_reviewable_with_rejected_status(reviewable)
|
||||||
|
expect(review_page).to have_reviewable_with_rejection_reason(reviewable, rejection_reason)
|
||||||
|
|
||||||
|
mail = ActionMailer::Base.deliveries.first
|
||||||
|
expect(mail.to).to eq([user_email])
|
||||||
|
expect(mail.subject).to match(/You've been rejected on Discourse/)
|
||||||
|
expect(mail.body.raw_source).to include rejection_reason
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "when performing a review action from the show route" do
|
context "when performing a review action from the show route" do
|
||||||
context "with a ReviewableQueuedPost" do
|
context "with a ReviewableQueuedPost" do
|
||||||
fab!(:queued_post_reviewable) { Fabricate(:reviewable_queued_post) }
|
fab!(:queued_post_reviewable) { Fabricate(:reviewable_queued_post) }
|
||||||
|
|
Loading…
Reference in New Issue