DEV: Asyncify `Composer.createPost()` (#18026)

I convert these Composer (and Topic) functions one by one because stuff do be breaking 😄

Moved the special pretender handler code from the global one to the tests that actually require it.
This commit is contained in:
Jarek Radosz 2022-10-07 17:25:15 +02:00 committed by GitHub
parent 08476f17ff
commit d2d4749127
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 95 deletions

View File

@ -22,7 +22,7 @@ import { inject as service } from "@ember/service";
import deprecated from "discourse-common/lib/deprecated";
import { isEmpty } from "@ember/utils";
import { propertyNotEqual } from "discourse/lib/computed";
import { throwAjaxError } from "discourse/lib/ajax-error";
import { extractError, throwAjaxError } from "discourse/lib/ajax-error";
import { prioritizeNameFallback } from "discourse/lib/settings";
let _customizations = [];
@ -1023,7 +1023,7 @@ const Composer = RestModel.extend({
return dest;
},
createPost(opts) {
async createPost(opts) {
if (CREATE_TOPIC === this.action || PRIVATE_MESSAGE === this.action) {
this.set("topic", null);
}
@ -1032,7 +1032,6 @@ const Composer = RestModel.extend({
const topic = this.topic;
const user = this.user;
const postStream = this.get("topic.postStream");
let addedToStream = false;
const postTypes = this.site.post_types;
const postType = this.whisper ? postTypes.whisper : postTypes.regular;
@ -1073,12 +1072,10 @@ const Composer = RestModel.extend({
// If we're in a topic, we can append the post instantly.
if (postStream) {
// If it's in reply to another post, increase the reply count
if (post) {
post.setProperties({
reply_count: (post.reply_count || 0) + 1,
replies: [],
});
}
post?.setProperties({
reply_count: (post.reply_count || 0) + 1,
replies: [],
});
// We do not stage posts in mobile view, we do not have the "cooked"
// Furthermore calculating cooked is very complicated, especially since
@ -1092,80 +1089,72 @@ const Composer = RestModel.extend({
}
}
const composer = this;
composer.setProperties({
this.setProperties({
composeState: SAVING,
stagedPost: state === "staged" && createdPost,
});
return createdPost
.save()
.then((result) => {
let saving = true;
if (result.responseJson.action === "enqueued") {
if (postStream) {
postStream.undoPost(createdPost);
}
return result;
}
// We sometimes want to hide the `reply_to_user` if the post contains a quote
if (
result.responseJson &&
result.responseJson.post &&
!result.responseJson.post.reply_to_user
) {
createdPost.set("reply_to_user", null);
}
if (topic) {
// It's no longer a new post
topic.set("draft_sequence", result.target.draft_sequence);
postStream.commitPost(createdPost);
addedToStream = true;
} else {
// We created a new topic, let's show it.
composer.set("composeState", CLOSED);
saving = false;
// Update topic_count for the category
const category = composer.site.categories.find(
(x) => x.id === (parseInt(createdPost.category, 10) || 1)
);
if (category) {
category.incrementProperty("topic_count");
}
}
composer.clearState();
composer.set("createdPost", createdPost);
if (composer.replyingToTopic) {
this.appEvents.trigger("post:created", createdPost);
} else {
this.appEvents.trigger("topic:created", createdPost, composer);
}
if (addedToStream) {
composer.set("composeState", CLOSED);
} else if (saving) {
composer.set("composeState", SAVING);
}
try {
const result = await createdPost.save();
let saving = true;
if (result.responseJson.action === "enqueued") {
postStream?.undoPost(createdPost);
return result;
})
.catch(
throwAjaxError(() => {
if (postStream) {
postStream.undoPost(createdPost);
}
if (post) {
post.set("reply_count", post.reply_count - 1);
}
}
next(() => composer.set("composeState", OPEN));
})
);
// We sometimes want to hide the `reply_to_user` if the post contains a quote
if (result.responseJson.post && !result.responseJson.post.reply_to_user) {
createdPost.set("reply_to_user", null);
}
let addedToStream = false;
if (topic) {
// It's no longer a new post
topic.set("draft_sequence", result.target.draft_sequence);
postStream.commitPost(createdPost);
addedToStream = true;
} else {
// We created a new topic, let's show it.
this.set("composeState", CLOSED);
saving = false;
// Update topic_count for the category
const postCategoryId = parseInt(createdPost.category, 10) || 1;
const category = this.site.categories.find(
(x) => x.id === postCategoryId
);
category?.incrementProperty("topic_count");
}
this.clearState();
this.set("createdPost", createdPost);
if (this.replyingToTopic) {
this.appEvents.trigger("post:created", createdPost);
} else {
this.appEvents.trigger("topic:created", createdPost, this);
}
if (addedToStream) {
this.set("composeState", CLOSED);
} else if (saving) {
this.set("composeState", SAVING);
}
return result;
} catch (error) {
if (postStream) {
postStream.undoPost(createdPost);
post?.set("reply_count", post.reply_count - 1);
}
next(() => this.set("composeState", OPEN));
throw extractError(error);
}
},
getCookedHtml() {

View File

@ -227,12 +227,17 @@ acceptance("Composer", function (needs) {
});
test("Create a topic with server side errors", async function (assert) {
pretender.post("/posts", function () {
return response(422, { errors: ["That title has already been taken"] });
});
await visit("/");
await click("#create-topic");
await fillIn("#reply-title", "this title triggers an error");
await fillIn(".d-editor-input", "this is the *content* of a post");
await click("#reply-control button.create");
assert.ok(exists(".dialog-body"), "it pops up an error message");
await click(".dialog-footer .btn-primary");
assert.ok(!exists(".dialog-body"), "it dismisses the error");
assert.ok(exists(".d-editor-input"), "the composer input is visible");
@ -255,6 +260,17 @@ acceptance("Composer", function (needs) {
});
test("Create an enqueued Topic", async function (assert) {
pretender.post("/posts", function () {
return response(200, {
success: true,
action: "enqueued",
pending_post: {
id: 1234,
raw: "enqueue this content please",
},
});
});
await visit("/");
await click("#create-topic");
await fillIn("#reply-title", "Internationalization Localization");
@ -380,7 +396,7 @@ acceptance("Composer", function (needs) {
await click(".modal-footer button.keep-editing");
assert.ok(invisible(".discard-draft-modal.modal"));
assert.ok(invisible(".discard-draft-modal.modal"), "hides modal");
await click("#topic-footer-buttons .btn.create");
assert.ok(
exists(".discard-draft-modal.modal"),
@ -397,8 +413,18 @@ acceptance("Composer", function (needs) {
});
test("Create an enqueued Reply", async function (assert) {
await visit("/t/internationalization-localization/280");
pretender.post("/posts", function () {
return response(200, {
success: true,
action: "enqueued",
pending_post: {
id: 1234,
raw: "enqueue this content please",
},
});
});
await visit("/t/internationalization-localization/280");
assert.ok(!exists(".pending-posts .reviewable-item"));
await click("#topic-footer-buttons .btn.create");
@ -415,12 +441,10 @@ acceptance("Composer", function (needs) {
"enqueue this content please",
"it doesn't insert the post"
);
assert.ok(visible(".d-modal"), "it pops up a modal");
await click(".modal-footer button");
assert.ok(invisible(".d-modal"), "the modal can be dismissed");
assert.ok(exists(".pending-posts .reviewable-item"));
});

View File

@ -612,21 +612,6 @@ export function applyDefaultHandlers(pretender) {
pretender.post("/posts", function (request) {
const data = parsePostData(request.requestBody);
if (data.title === "this title triggers an error") {
return response(422, { errors: ["That title has already been taken"] });
}
if (data.raw === "enqueue this content please") {
return response(200, {
success: true,
action: "enqueued",
pending_post: {
id: 1234,
raw: data.raw,
},
});
}
if (data.raw === "custom message") {
return response(200, {
success: true,