FIX: Deleting a for_topic bookmark caused JS error (#14781)

When deleting a for_topic bookmark, we were calling
bookmark.attachedTo() for the bookmarks:changed event,
but the bookmark was not always a Bookmark model instance,
so sometimes that call would error. Now we make sure that
the bookmarks in the topic.bookmarks JS array are all
bookmark model instances, and added a test to cover this
deleting for_topic bookmark case as well.
This commit is contained in:
Martin Brennan 2021-11-01 13:31:17 +10:00 committed by GitHub
parent a03c48b720
commit dcf3733c13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 15 deletions

View File

@ -755,11 +755,12 @@ export default Controller.extend(bufferedProperty("model"), {
(bookmark) => bookmark.post_id === post.id && !bookmark.for_topic (bookmark) => bookmark.post_id === post.id && !bookmark.for_topic
); );
return this._modifyPostBookmark( return this._modifyPostBookmark(
bookmarkForPost || { bookmarkForPost ||
post_id: post.id, Bookmark.create({
topic_id: post.topic_id, post_id: post.id,
for_topic: false, topic_id: post.topic_id,
}, for_topic: false,
}),
post post
); );
} else { } else {
@ -1228,7 +1229,6 @@ export default Controller.extend(bufferedProperty("model"), {
}, },
_modifyTopicBookmark(bookmark) { _modifyTopicBookmark(bookmark) {
bookmark = Bookmark.create(bookmark);
return openBookmarkModal(bookmark, { return openBookmarkModal(bookmark, {
onAfterSave: (savedData) => { onAfterSave: (savedData) => {
this._syncBookmarks(savedData); this._syncBookmarks(savedData);
@ -1251,7 +1251,6 @@ export default Controller.extend(bufferedProperty("model"), {
}, },
_modifyPostBookmark(bookmark, post) { _modifyPostBookmark(bookmark, post) {
bookmark = Bookmark.create(bookmark);
return openBookmarkModal(bookmark, { return openBookmarkModal(bookmark, {
onCloseWithoutSaving: () => { onCloseWithoutSaving: () => {
post.appEvents.trigger("post-stream:refresh", { post.appEvents.trigger("post-stream:refresh", {
@ -1279,7 +1278,7 @@ export default Controller.extend(bufferedProperty("model"), {
const bookmark = this.model.bookmarks.findBy("id", data.id); const bookmark = this.model.bookmarks.findBy("id", data.id);
if (!bookmark) { if (!bookmark) {
this.model.bookmarks.pushObject(data); this.model.bookmarks.pushObject(Bookmark.create(data));
} else { } else {
bookmark.reminder_at = data.reminder_at; bookmark.reminder_at = data.reminder_at;
bookmark.name = data.name; bookmark.name = data.name;
@ -1309,11 +1308,13 @@ export default Controller.extend(bufferedProperty("model"), {
if (this.model.bookmarkCount === 0) { if (this.model.bookmarkCount === 0) {
const firstPost = await this.model.firstPost(); const firstPost = await this.model.firstPost();
return this._modifyTopicBookmark({ return this._modifyTopicBookmark(
post_id: firstPost.id, Bookmark.create({
topic_id: this.model.id, post_id: firstPost.id,
for_topic: true, topic_id: this.model.id,
}); for_topic: true,
})
);
} }
}, },

View File

@ -2,6 +2,7 @@ import { alias, and, equal, notEmpty, or } from "@ember/object/computed";
import { fmt, propertyEqual } from "discourse/lib/computed"; import { fmt, propertyEqual } from "discourse/lib/computed";
import ActionSummary from "discourse/models/action-summary"; import ActionSummary from "discourse/models/action-summary";
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import Bookmark from "discourse/models/bookmark";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
import I18n from "I18n"; import I18n from "I18n";
import PreloadStore from "discourse/lib/preload-store"; import PreloadStore from "discourse/lib/preload-store";
@ -447,7 +448,7 @@ const Topic = RestModel.extend({
.then(() => { .then(() => {
this.setProperties({ this.setProperties({
deleted_at: new Date(), deleted_at: new Date(),
deleted_by: deleted_by, deleted_by,
"details.can_delete": false, "details.can_delete": false,
"details.can_recover": true, "details.can_recover": true,
}); });
@ -488,6 +489,11 @@ const Topic = RestModel.extend({
} }
} }
keys.forEach((key) => this.set(key, json[key])); keys.forEach((key) => this.set(key, json[key]));
if (this.bookmarks.length) {
this.bookmarks = this.bookmarks.map((bm) => Bookmark.create(bm));
}
return this; return this;
}, },
@ -619,7 +625,7 @@ const Topic = RestModel.extend({
return ajax(`/t/${this.id}/tags`, { return ajax(`/t/${this.id}/tags`, {
type: "PUT", type: "PUT",
data: { tags: tags }, data: { tags },
}); });
}, },
}); });

View File

@ -428,6 +428,41 @@ acceptance("Bookmarking", function (needs) {
); );
}); });
test("Deleting a topic_level bookmark with a reminder", async function (assert) {
await visit("/t/internationalization-localization/280");
await click("#topic-footer-button-bookmark");
await click("#save-bookmark");
assert.equal(
query("#topic-footer-button-bookmark").innerText,
I18n.t("bookmarked.edit_bookmark"),
"A topic level bookmark button has a label 'Edit Bookmark'"
);
await click("#topic-footer-button-bookmark");
await fillIn("input#bookmark-name", "Test name");
await click("#tap_tile_tomorrow");
await click("#topic-footer-button-bookmark");
await click("#delete-bookmark");
assert.ok(exists(".bootbox.modal"), "it asks for delete confirmation");
assert.ok(
queryAll(".bootbox.modal")
.text()
.includes(I18n.t("bookmarks.confirm_delete")),
"it shows delete confirmation message"
);
await click(".bootbox.modal .btn-primary");
assert.equal(
query("#topic-footer-button-bookmark").innerText,
I18n.t("bookmarked.title"),
"A topic level bookmark button no longer says 'Edit Bookmark' after deletion"
);
});
test("The topic level bookmark button opens the edit modal if only one post in the post stream is bookmarked", async function (assert) { test("The topic level bookmark button opens the edit modal if only one post in the post stream is bookmarked", async function (assert) {
await visit("/t/internationalization-localization/280"); await visit("/t/internationalization-localization/280");
await openBookmarkModal(2); await openBookmarkModal(2);