FEATURE: Add last visit indication to topic view page. (#13471)
This PR also removes grey old unread bubble from the topic badges by dropping `TopicUser#highest_seen_post_number`.
This commit is contained in:
parent
0f688f45bd
commit
37b8ce79c9
|
@ -49,7 +49,9 @@ export default MountWidget.extend({
|
|||
"selectedPostsCount",
|
||||
"searchService",
|
||||
"showReadIndicator",
|
||||
"streamFilters"
|
||||
"streamFilters",
|
||||
"lastReadPostNumber",
|
||||
"highestPostNumber"
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
@ -142,8 +142,8 @@ export default Component.extend({
|
|||
classes.push("unseen-topic");
|
||||
}
|
||||
|
||||
if (topic.get("displayNewPosts")) {
|
||||
classes.push("new-posts");
|
||||
if (topic.unread_posts) {
|
||||
classes.push("unread-posts");
|
||||
}
|
||||
|
||||
["liked", "archived", "bookmarked", "pinned", "closed"].forEach((name) => {
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { or } from "@ember/object/computed";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "span",
|
||||
classNameBindings: [":topic-post-badges"],
|
||||
rerenderTriggers: ["url", "unread", "newPosts", "unseen"],
|
||||
rerenderTriggers: ["url", "unread", "newPosts", "unreadPosts", "unseen"],
|
||||
newDotText: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.set(
|
||||
"newDotText",
|
||||
this.currentUser && this.currentUser.trust_level > 0
|
||||
|
@ -15,4 +18,6 @@ export default Component.extend({
|
|||
: I18n.t("filters.new.lower_title")
|
||||
);
|
||||
},
|
||||
|
||||
displayUnreadPosts: or("newPosts", "unreadPosts"),
|
||||
});
|
||||
|
|
|
@ -68,6 +68,8 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||
filter: null,
|
||||
quoteState: null,
|
||||
currentPostId: null,
|
||||
userLastReadPostNumber: null,
|
||||
highestPostNumber: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
|
|
@ -352,15 +352,14 @@ const TopicTrackingState = EmberObject.extend({
|
|||
isSeen !== state.is_seen
|
||||
) {
|
||||
const postsCount = topic.get("posts_count");
|
||||
let newPosts = postsCount - state.highest_post_number,
|
||||
unread = postsCount - state.last_read_post_number;
|
||||
let unread;
|
||||
|
||||
if (newPosts < 0) {
|
||||
newPosts = 0;
|
||||
}
|
||||
if (!state.last_read_post_number) {
|
||||
if (state.last_read_post_number) {
|
||||
unread = postsCount - state.last_read_post_number;
|
||||
} else {
|
||||
unread = 0;
|
||||
}
|
||||
|
||||
if (unread < 0) {
|
||||
unread = 0;
|
||||
}
|
||||
|
@ -368,8 +367,7 @@ const TopicTrackingState = EmberObject.extend({
|
|||
topic.setProperties({
|
||||
highest_post_number: state.highest_post_number,
|
||||
last_read_post_number: state.last_read_post_number,
|
||||
new_posts: newPosts,
|
||||
unread: unread,
|
||||
unread_posts: unread,
|
||||
is_seen: state.is_seen,
|
||||
unseen: !state.last_read_post_number && isUnseen(state),
|
||||
});
|
||||
|
@ -654,14 +652,13 @@ const TopicTrackingState = EmberObject.extend({
|
|||
newState.topic_id = topic.id;
|
||||
newState.notification_level = topic.notification_level;
|
||||
|
||||
// see ListableTopicSerializer for unread/unseen/new_posts and other
|
||||
// see ListableTopicSerializer for unread_posts/unseen and other
|
||||
// topic property logic
|
||||
if (topic.unseen) {
|
||||
newState.last_read_post_number = null;
|
||||
} else if (topic.unread || topic.new_posts) {
|
||||
} else if (topic.unread_posts) {
|
||||
newState.last_read_post_number =
|
||||
topic.highest_post_number -
|
||||
((topic.unread || 0) + (topic.new_posts || 0));
|
||||
topic.highest_post_number - (topic.unread_posts || 0);
|
||||
} else {
|
||||
// remove the topic if it is no longer unread/new (it has been seen)
|
||||
// and if there are too many topics in memory
|
||||
|
|
|
@ -7,7 +7,6 @@ import I18n from "I18n";
|
|||
import PreloadStore from "discourse/lib/preload-store";
|
||||
import { Promise } from "rsvp";
|
||||
import RestModel from "discourse/models/rest";
|
||||
import Session from "discourse/models/session";
|
||||
import Site from "discourse/models/site";
|
||||
import User from "discourse/models/user";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
@ -21,6 +20,7 @@ import { longDate } from "discourse/lib/formatter";
|
|||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { resolveShareUrl } from "discourse/helpers/share-url";
|
||||
import DiscourseURL, { userPath } from "discourse/lib/url";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
export function loadTopicView(topic, args) {
|
||||
const data = deepMerge({}, args);
|
||||
|
@ -239,10 +239,16 @@ const Topic = RestModel.extend({
|
|||
return url;
|
||||
},
|
||||
|
||||
@discourseComputed("new_posts", "unread")
|
||||
totalUnread(newPosts, unread) {
|
||||
const count = (unread || 0) + (newPosts || 0);
|
||||
return count > 0 ? count : null;
|
||||
@discourseComputed("unread_posts", "new_posts")
|
||||
totalUnread(unreadPosts, newPosts) {
|
||||
deprecated("The totalUnread property of the topic model is deprecated");
|
||||
return unreadPosts || newPosts;
|
||||
},
|
||||
|
||||
@discourseComputed("unread_posts", "new_posts")
|
||||
displayNewPosts(unreadPosts, newPosts) {
|
||||
deprecated("The displayNewPosts property of the topic model is deprecated");
|
||||
return unreadPosts || newPosts;
|
||||
},
|
||||
|
||||
@discourseComputed("last_read_post_number", "url")
|
||||
|
@ -284,25 +290,6 @@ const Topic = RestModel.extend({
|
|||
return userPath(username);
|
||||
},
|
||||
|
||||
// The amount of new posts to display. It might be different than what the server
|
||||
// tells us if we are still asynchronously flushing our "recently read" data.
|
||||
// So take what the browser has seen into consideration.
|
||||
@discourseComputed("new_posts", "id")
|
||||
displayNewPosts(newPosts, id) {
|
||||
const highestSeen = Session.currentProp("highestSeenByTopic")[id];
|
||||
if (highestSeen) {
|
||||
const delta = highestSeen - this.last_read_post_number;
|
||||
if (delta > 0) {
|
||||
let result = newPosts - delta;
|
||||
if (result < 0) {
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return newPosts;
|
||||
},
|
||||
|
||||
@discourseComputed("views")
|
||||
viewsHeat(v) {
|
||||
if (v >= this.siteSettings.topic_views_heat_high) {
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { and, or } from "@ember/object/computed";
|
||||
import { and } from "@ember/object/computed";
|
||||
import EmberObject from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default EmberObject.extend({
|
||||
postCountsPresent: or("topic.unread", "topic.displayNewPosts"),
|
||||
showBadges: and("postBadgesEnabled", "postCountsPresent"),
|
||||
showBadges: and("postBadgesEnabled", "topic.unread_posts"),
|
||||
|
||||
@discourseComputed
|
||||
newDotText() {
|
||||
|
|
|
@ -69,6 +69,8 @@ export default DiscourseRoute.extend({
|
|||
"model.currentPost": closest,
|
||||
enteredIndex: topic.postStream.progressIndexOfPost(closestPost),
|
||||
enteredAt: Date.now().toString(),
|
||||
userLastReadPostNumber: topic.last_read_post_number,
|
||||
highestPostNumber: topic.highest_post_number,
|
||||
});
|
||||
|
||||
this.appEvents.trigger("page:topic-loaded", topic);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{raw "topic-status" topic=topic}}
|
||||
<a href={{topic.lastUnreadUrl}} class="title">{{html-safe topic.fancyTitle}}</a>
|
||||
{{topic-post-badges newPosts=topic.totalUnread unseen=topic.unseen url=topic.lastUnreadUrl}}
|
||||
{{topic-post-badges unreadPosts=topic.unread_posts unseen=topic.unseen url=topic.lastUnreadUrl}}
|
||||
|
||||
<a href={{topic.lastPostUrl}} class="last-posted-at">{{format-age topic.last_posted_at}}</a>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
{{#if topic.featured_link}}
|
||||
{{topic-featured-link topic}}
|
||||
{{/if}}
|
||||
{{topic-post-badges newPosts=topic.totalUnread unseen=topic.unseen url=topic.lastUnreadUrl}}
|
||||
{{topic-post-badges unreadPosts=topic.unread_posts unseen=topic.unseen url=topic.lastUnreadUrl}}
|
||||
</div>
|
||||
<div class="bottom-row">
|
||||
{{category-link topic.category}}{{discourse-tags topic mode="list"}}{{! intentionally inline to avoid whitespace}}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{{#if unread }}
|
||||
<a href={{url}} title={{i18n "topic.unread_posts" count=unread}} class="badge badge-notification unread">{{unread}}</a>
|
||||
{{/if}}
|
||||
{{#if newPosts}}
|
||||
<a href={{url}} title={{i18n "topic.total_unread_posts" count=newPosts}} class="badge badge-notification new-posts">{{newPosts}}</a>
|
||||
{{#if displayUnreadPosts}}
|
||||
<a href={{url}} title={{i18n "topic.unread_posts" count=displayUnreadPosts}} class="badge badge-notification unread-posts">{{displayUnreadPosts}}</a>
|
||||
{{/if}}
|
||||
{{#if unseen}}
|
||||
<a href={{url}} title={{i18n "topic.new"}} class="badge badge-notification new-topic">{{newDotText}}</a>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{#if view.showBadges}}
|
||||
{{raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
|
||||
{{raw "topic-post-badges" unreadPosts=topic.unread_posts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
|
||||
{{else}}
|
||||
{{raw "list/posts-count-column" topic=topic tagName="div"}}
|
||||
{{/if}}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
topicId=topic.id
|
||||
unreadClass=unreadClass~}}
|
||||
{{~#if showTopicPostBadges}}
|
||||
{{~raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
|
||||
{{~raw "topic-post-badges" unreadPosts=topic.unread_posts unseen=topic.unseen url=topic.lastUnreadUrl newDotText=newDotText}}
|
||||
{{~/if}}
|
||||
</span>
|
||||
<div class="link-bottom-line">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<span class='topic-post-badges'>
|
||||
{{~#if unread ~}}
|
||||
<a href='{{url}}' class='badge badge-notification unread' title='{{i18n "topic.unread_posts" count=unread}}'>{{unread}}</a>
|
||||
{{~/if}}
|
||||
{{~#if newPosts ~}}
|
||||
<a href='{{url}}' class='badge badge-notification new-posts' title='{{i18n "topic.total_unread_posts" count=newPosts}}'>{{newPosts}}</a>
|
||||
<a href='{{url}}' class='badge badge-notification unread-posts' title='{{i18n "topic.unread_posts" count=newPosts}}'>{{newPosts}}</a>
|
||||
{{~/if}}
|
||||
{{~#if unreadPosts ~}}
|
||||
<a href='{{url}}' class='badge badge-notification unread-posts' title='{{i18n "topic.unread_posts" count=unreadPosts}}'>{{unreadPosts}}</a>
|
||||
{{~/if}}
|
||||
{{~#if unseen ~}}
|
||||
<a href='{{url}}' class='badge badge-notification new-topic' title='{{i18n "topic.new"}}'>{{newDotText}}</a>
|
||||
|
|
|
@ -208,6 +208,8 @@
|
|||
gaps=model.postStream.gaps
|
||||
showReadIndicator=model.show_read_indicator
|
||||
streamFilters=model.postStream.streamFilters
|
||||
lastReadPostNumber=userLastReadPostNumber
|
||||
highestPostNumber=highestPostNumber
|
||||
showFlags=(action "showPostFlags")
|
||||
editPost=(action "editPost")
|
||||
showHistory=(route-action "showHistory")
|
||||
|
|
|
@ -186,17 +186,19 @@ export default createWidget("post-stream", {
|
|||
tagName: "div.post-stream",
|
||||
|
||||
html(attrs) {
|
||||
const posts = attrs.posts || [],
|
||||
postArray = posts.toArray(),
|
||||
result = [],
|
||||
before = attrs.gaps && attrs.gaps.before ? attrs.gaps.before : {},
|
||||
after = attrs.gaps && attrs.gaps.after ? attrs.gaps.after : {},
|
||||
mobileView = this.site.mobileView;
|
||||
const posts = attrs.posts || [];
|
||||
const postArray = posts.toArray();
|
||||
const postArrayLength = postArray.length;
|
||||
const maxPostNumber = postArray[postArrayLength - 1].post_number;
|
||||
const result = [];
|
||||
const before = attrs.gaps && attrs.gaps.before ? attrs.gaps.before : {};
|
||||
const after = attrs.gaps && attrs.gaps.after ? attrs.gaps.after : {};
|
||||
const mobileView = this.site.mobileView;
|
||||
|
||||
let prevPost;
|
||||
let prevDate;
|
||||
|
||||
for (let i = 0; i < postArray.length; i++) {
|
||||
for (let i = 0; i < postArrayLength; i++) {
|
||||
const post = postArray[i];
|
||||
|
||||
if (post instanceof Placeholder) {
|
||||
|
@ -276,6 +278,18 @@ export default createWidget("post-stream", {
|
|||
);
|
||||
}
|
||||
|
||||
if (
|
||||
i !== postArrayLength - 1 &&
|
||||
maxPostNumber <= attrs.highestPostNumber &&
|
||||
attrs.lastReadPostNumber === post.post_number
|
||||
) {
|
||||
result.push(
|
||||
this.attach("topic-post-visited-line", {
|
||||
post_number: post.post_number,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
prevPost = post;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import I18n from "I18n";
|
||||
import { createWidget } from "discourse/widgets/widget";
|
||||
import { h } from "virtual-dom";
|
||||
|
||||
export default createWidget("topic-post-visited-line", {
|
||||
tagName: "div.topic-post-visited-line",
|
||||
|
||||
buildClasses(attrs) {
|
||||
return [`post-${attrs.post_number}`];
|
||||
},
|
||||
|
||||
html() {
|
||||
return h(
|
||||
"span.topic-post-visited-message",
|
||||
I18n.t("topics.new_messages_marker")
|
||||
);
|
||||
},
|
||||
});
|
|
@ -53,8 +53,7 @@ acceptance("Tags", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 1,
|
||||
unread_posts: 1,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
|
|
@ -553,3 +553,23 @@ acceptance("Topic pinning/unpinning as a group moderator", function (needs) {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Topic last visit line", function (needs) {
|
||||
needs.user({ moderator: false, admin: false, trust_level: 1 });
|
||||
|
||||
test("visit topic", async function (assert) {
|
||||
await visit("/t/-/280");
|
||||
|
||||
assert.ok(
|
||||
exists(".topic-post-visited-line.post-10"),
|
||||
"shows the last visited line on the right post"
|
||||
);
|
||||
|
||||
await visit("/t/-/9");
|
||||
|
||||
assert.ok(
|
||||
!exists(".topic-post-visited-line"),
|
||||
"does not show last visited line if post is the last post"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4033,8 +4033,7 @@ export default {
|
|||
bumped_at: "2019-11-12T05:19:52.848Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -4076,8 +4075,7 @@ export default {
|
|||
bumped_at: "2019-11-12T05:19:32.516Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -6398,8 +6396,7 @@ export default {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 5,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
|
|
@ -38,8 +38,7 @@ export default {
|
|||
bumped_at: "2019-07-26T01:29:24.177Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 2,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
|
|
@ -3018,8 +3018,7 @@ export default {
|
|||
bumped_at: "2015-04-08T16:05:09.842Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 3,
|
||||
unread: 0,
|
||||
new_posts: 1,
|
||||
unread_posts: 1,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -3062,8 +3061,7 @@ export default {
|
|||
bumped_at: "2015-04-08T15:40:30.037Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 2,
|
||||
unread: 0,
|
||||
new_posts: 2,
|
||||
unread_posts: 2,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -3143,8 +3141,7 @@ export default {
|
|||
bumped_at: "2015-04-07T09:21:21.570Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 8,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -3187,8 +3184,7 @@ export default {
|
|||
bumped_at: "2015-02-22T13:46:26.845Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 65,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -3266,8 +3262,7 @@ export default {
|
|||
bumped_at: "2015-03-21T00:33:52.243Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -4087,8 +4082,7 @@ export default {
|
|||
bumped_at: "2015-08-13T10:14:34.799Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 5,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -4117,8 +4111,7 @@ export default {
|
|||
bumped_at: "2015-08-13T01:58:35.206Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 3,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -4175,8 +4168,7 @@ export default {
|
|||
bumped_at: "2015-08-13T10:14:34.799Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 5,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -4413,8 +4405,7 @@ export default {
|
|||
bumped_at: "2017-01-27T03:52:02.119Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -4690,8 +4681,7 @@ export default {
|
|||
bumped_at: "2015-08-13T10:14:34.799Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 5,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -4720,8 +4710,7 @@ export default {
|
|||
bumped_at: "2015-08-13T01:58:35.206Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 3,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -4982,8 +4971,7 @@ export default {
|
|||
bumped_at: "2015-08-13T10:14:34.799Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 5,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -5012,8 +5000,7 @@ export default {
|
|||
bumped_at: "2015-08-13T01:58:35.206Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 3,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
|
|
@ -247,8 +247,7 @@ discourseModule("Unit | Model | topic-tracking-state", function (hooks) {
|
|||
{
|
||||
highest_post_number: null,
|
||||
id: 111,
|
||||
unread: 10,
|
||||
new_posts: 10,
|
||||
unread_posts: 10,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -271,8 +270,7 @@ discourseModule("Unit | Model | topic-tracking-state", function (hooks) {
|
|||
Topic.create({
|
||||
highest_post_number: null,
|
||||
id: 111,
|
||||
unread: 10,
|
||||
new_posts: 10,
|
||||
unread_posts: 10,
|
||||
unseen: true,
|
||||
prevent_sync: false,
|
||||
}),
|
||||
|
@ -303,8 +301,7 @@ discourseModule("Unit | Model | topic-tracking-state", function (hooks) {
|
|||
id: 111,
|
||||
unseen: false,
|
||||
seen: true,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
prevent_sync: false,
|
||||
}),
|
||||
],
|
||||
|
@ -338,8 +335,7 @@ discourseModule("Unit | Model | topic-tracking-state", function (hooks) {
|
|||
id: 111,
|
||||
unseen: true,
|
||||
seen: false,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
highest_post_number: 20,
|
||||
category_id: 1,
|
||||
tags: ["pending"],
|
||||
|
@ -348,8 +344,7 @@ discourseModule("Unit | Model | topic-tracking-state", function (hooks) {
|
|||
id: 222,
|
||||
unseen: false,
|
||||
seen: true,
|
||||
unread: 3,
|
||||
new_posts: 0,
|
||||
unread_posts: 3,
|
||||
highest_post_number: 20,
|
||||
}),
|
||||
],
|
||||
|
|
|
@ -396,7 +396,7 @@ div.education {
|
|||
border-top: 3px solid var(--primary-low);
|
||||
border-bottom: 1px solid var(--primary-low);
|
||||
|
||||
.badge-notification.new-posts {
|
||||
.badge-notification.unread-posts {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1030,6 +1030,21 @@ a.mention-group {
|
|||
}
|
||||
}
|
||||
|
||||
.topic-post-visited-line {
|
||||
border-bottom: 1px solid var(--danger-medium);
|
||||
line-height: 0.1em;
|
||||
text-align: center;
|
||||
margin: 1rem 0px;
|
||||
|
||||
.topic-post-visited-message {
|
||||
position: relative; // Chrome needs this, otherwise the line is above the text
|
||||
background-color: var(--secondary);
|
||||
color: var(--danger-medium);
|
||||
font-size: $font-down-1;
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
// Select posts
|
||||
|
||||
.topic-post {
|
||||
|
|
|
@ -178,9 +178,8 @@
|
|||
color: var(--secondary);
|
||||
}
|
||||
|
||||
// New posts
|
||||
// Unread posts
|
||||
|
||||
&.new-posts,
|
||||
&.unread-posts {
|
||||
background-color: var(--tertiary-med-or-tertiary);
|
||||
color: var(--secondary);
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
.badge-wrapper {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
.badge-notification.new-posts {
|
||||
.badge-notification.unread-posts {
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@
|
|||
.topic-statuses {
|
||||
margin-right: 0.15em;
|
||||
}
|
||||
.topic-post-badges .badge.new-posts,
|
||||
.topic-post-badges .badge.unread-posts,
|
||||
.title {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
|
|
@ -577,6 +577,20 @@ blockquote {
|
|||
}
|
||||
}
|
||||
|
||||
.topic-post-visited-line {
|
||||
width: calc(
|
||||
#{$topic-body-width} + #{$topic-avatar-width} +
|
||||
(#{$topic-body-width-padding} * 2)
|
||||
);
|
||||
|
||||
+ .topic-post {
|
||||
.topic-avatar,
|
||||
.topic-body {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// variables are used to calculate the width of .gap
|
||||
.topic-body {
|
||||
width: calc(#{$topic-body-width} + (#{$topic-body-width-padding} * 2));
|
||||
|
|
|
@ -156,7 +156,6 @@ ol.category-breadcrumb {
|
|||
}
|
||||
|
||||
.category-topic-link td.num .badge-notification {
|
||||
&.new-posts,
|
||||
&.unread-posts {
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.topic-post-visited-line {
|
||||
+ .topic-post article {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.topic-post article {
|
||||
border-top: 1px solid var(--primary-low);
|
||||
padding: 15px 0 8px 0;
|
||||
|
|
|
@ -136,7 +136,6 @@ html {
|
|||
background: var(--primary-medium);
|
||||
}
|
||||
|
||||
.badge-notification.new-posts,
|
||||
.badge-notification.unread-posts {
|
||||
background: var(--tertiary);
|
||||
}
|
||||
|
|
|
@ -352,7 +352,7 @@ class PostMover
|
|||
}
|
||||
|
||||
DB.exec(<<~SQL, params)
|
||||
INSERT INTO topic_users(user_id, topic_id, posted, last_read_post_number, highest_seen_post_number,
|
||||
INSERT INTO topic_users(user_id, topic_id, posted, last_read_post_number,
|
||||
last_emailed_post_number, first_visited_at, last_visited_at, notification_level,
|
||||
notifications_changed_at, notifications_reason_id)
|
||||
SELECT tu.user_id,
|
||||
|
@ -370,12 +370,6 @@ class PostMover
|
|||
WHERE lr.old_topic_id = tu.topic_id
|
||||
AND lr.old_post_number <= tu.last_read_post_number
|
||||
) AS last_read_post_number,
|
||||
(
|
||||
SELECT MAX(hs.new_post_number)
|
||||
FROM moved_posts hs
|
||||
WHERE hs.old_topic_id = tu.topic_id
|
||||
AND hs.old_post_number <= tu.highest_seen_post_number
|
||||
) AS highest_seen_post_number,
|
||||
(
|
||||
SELECT MAX(le.new_post_number)
|
||||
FROM moved_posts le
|
||||
|
@ -392,7 +386,6 @@ class PostMover
|
|||
WHERE tu.topic_id = :old_topic_id
|
||||
AND GREATEST(
|
||||
tu.last_read_post_number,
|
||||
tu.highest_seen_post_number,
|
||||
tu.last_emailed_post_number
|
||||
) >= (SELECT MIN(old_post_number) FROM moved_posts)
|
||||
ON CONFLICT (topic_id, user_id) DO UPDATE
|
||||
|
@ -409,18 +402,6 @@ class PostMover
|
|||
GREATEST(topic_users.last_read_post_number,
|
||||
excluded.last_read_post_number)
|
||||
ELSE topic_users.last_read_post_number END,
|
||||
highest_seen_post_number = CASE
|
||||
WHEN topic_users.highest_seen_post_number = :old_highest_staff_post_number OR (
|
||||
:old_highest_post_number < :old_highest_staff_post_number
|
||||
AND topic_users.highest_seen_post_number = :old_highest_post_number
|
||||
AND NOT EXISTS(SELECT 1
|
||||
FROM users u
|
||||
WHERE u.id = topic_users.user_id
|
||||
AND (admin OR moderator))
|
||||
) THEN
|
||||
GREATEST(topic_users.highest_seen_post_number,
|
||||
excluded.highest_seen_post_number)
|
||||
ELSE topic_users.highest_seen_post_number END,
|
||||
last_emailed_post_number = CASE
|
||||
WHEN topic_users.last_emailed_post_number = :old_highest_staff_post_number OR (
|
||||
:old_highest_post_number < :old_highest_staff_post_number
|
||||
|
|
|
@ -71,7 +71,6 @@ class PostTiming < ActiveRecord::Base
|
|||
end
|
||||
|
||||
TopicUser.where(user_id: user.id, topic_id: topic.id).update_all(
|
||||
highest_seen_post_number: last_read,
|
||||
last_read_post_number: last_read
|
||||
)
|
||||
|
||||
|
|
|
@ -810,11 +810,7 @@ class Topic < ActiveRecord::Base
|
|||
SET last_read_post_number = CASE
|
||||
WHEN last_read_post_number > :highest THEN :highest
|
||||
ELSE last_read_post_number
|
||||
END,
|
||||
highest_seen_post_number = CASE
|
||||
WHEN highest_seen_post_number > :highest THEN :highest
|
||||
ELSE highest_seen_post_number
|
||||
END
|
||||
END
|
||||
WHERE topic_id = :topic_id
|
||||
SQL
|
||||
end
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class TopicUser < ActiveRecord::Base
|
||||
self.ignored_columns = [
|
||||
:highest_seen_post_number # Remove after 01 Jan 2022
|
||||
]
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :topic
|
||||
|
||||
|
@ -114,6 +118,11 @@ class TopicUser < ActiveRecord::Base
|
|||
# since there's more likely to be an existing record than not. If the update returns 0 rows affected
|
||||
# it then creates the row instead.
|
||||
def change(user_id, topic_id, attrs)
|
||||
# For plugin compatibility, remove after 01 Jan 2022
|
||||
if attrs[:highest_seen_post_number]
|
||||
attrs.delete(:highest_seen_post_number)
|
||||
end
|
||||
|
||||
# Sometimes people pass objs instead of the ids. We can handle that.
|
||||
topic_id = topic_id.id if topic_id.is_a?(::Topic)
|
||||
user_id = user_id.id if user_id.is_a?(::User)
|
||||
|
@ -131,6 +140,7 @@ class TopicUser < ActiveRecord::Base
|
|||
|
||||
attrs_sql = attrs_array.map { |t| "#{t[0]} = ?" }.join(", ")
|
||||
vals = attrs_array.map { |t| t[1] }
|
||||
|
||||
rows = TopicUser.where(topic_id: topic_id, user_id: user_id).update_all([attrs_sql, *vals])
|
||||
|
||||
if rows == 0
|
||||
|
@ -252,7 +262,6 @@ class TopicUser < ActiveRecord::Base
|
|||
UPDATE_TOPIC_USER_SQL = "UPDATE topic_users
|
||||
SET
|
||||
last_read_post_number = GREATEST(:post_number, tu.last_read_post_number),
|
||||
highest_seen_post_number = t.highest_post_number,
|
||||
total_msecs_viewed = LEAST(tu.total_msecs_viewed + :msecs,86400000),
|
||||
notification_level =
|
||||
case when tu.notifications_reason_id is null and (tu.total_msecs_viewed + :msecs) >
|
||||
|
@ -278,8 +287,8 @@ class TopicUser < ActiveRecord::Base
|
|||
|
||||
UPDATE_TOPIC_USER_SQL_STAFF = UPDATE_TOPIC_USER_SQL.gsub("highest_post_number", "highest_staff_post_number")
|
||||
|
||||
INSERT_TOPIC_USER_SQL = "INSERT INTO topic_users (user_id, topic_id, last_read_post_number, highest_seen_post_number, last_visited_at, first_visited_at, notification_level)
|
||||
SELECT :user_id, :topic_id, :post_number, ft.highest_post_number, :now, :now, :new_status
|
||||
INSERT_TOPIC_USER_SQL = "INSERT INTO topic_users (user_id, topic_id, last_read_post_number, last_visited_at, first_visited_at, notification_level)
|
||||
SELECT :user_id, :topic_id, :post_number, :now, :now, :new_status
|
||||
FROM topics AS ft
|
||||
JOIN users u on u.id = :user_id
|
||||
WHERE ft.id = :topic_id
|
||||
|
@ -303,11 +312,6 @@ class TopicUser < ActiveRecord::Base
|
|||
threshold: SiteSetting.default_other_auto_track_topics_after_msecs
|
||||
}
|
||||
|
||||
# In case anyone sees "highest_seen_post_number" and gets confused, like I do.
|
||||
# highest_seen_post_number represents the highest_post_number of the topic when
|
||||
# the user visited it. It may be out of alignment with last_read, meaning
|
||||
# ... user visited the topic but did not read the posts
|
||||
#
|
||||
# 86400000 = 1 day
|
||||
rows =
|
||||
if user.staff?
|
||||
|
@ -424,12 +428,11 @@ class TopicUser < ActiveRecord::Base
|
|||
builder.exec(action_type_id: PostActionType.types[action_type])
|
||||
end
|
||||
|
||||
# cap number of unread topics at count, bumping up highest_seen / last_read if needed
|
||||
# cap number of unread topics at count, bumping up last_read if needed
|
||||
def self.cap_unread!(user_id, count)
|
||||
sql = <<SQL
|
||||
UPDATE topic_users tu
|
||||
SET last_read_post_number = max_number,
|
||||
highest_seen_post_number = max_number
|
||||
SET last_read_post_number = max_number
|
||||
FROM (
|
||||
SELECT MAX(post_number) max_number, p.topic_id FROM posts p
|
||||
WHERE deleted_at IS NULL
|
||||
|
@ -456,8 +459,7 @@ SQL
|
|||
builder = DB.build <<~SQL
|
||||
UPDATE topic_users t
|
||||
SET
|
||||
last_read_post_number = LEAST(GREATEST(last_read, last_read_post_number), max_post_number),
|
||||
highest_seen_post_number = LEAST(max_post_number,GREATEST(t.highest_seen_post_number, last_read))
|
||||
last_read_post_number = LEAST(GREATEST(last_read, last_read_post_number), max_post_number)
|
||||
FROM (
|
||||
SELECT topic_id, user_id, MAX(post_number) last_read
|
||||
FROM post_timings
|
||||
|
@ -474,8 +476,7 @@ SQL
|
|||
X.topic_id = t.topic_id AND
|
||||
X.user_id = t.user_id AND
|
||||
(
|
||||
last_read_post_number <> LEAST(GREATEST(last_read, last_read_post_number), max_post_number) OR
|
||||
highest_seen_post_number <> LEAST(max_post_number,GREATEST(t.highest_seen_post_number, last_read))
|
||||
last_read_post_number <> LEAST(GREATEST(last_read, last_read_post_number), max_post_number)
|
||||
)
|
||||
SQL
|
||||
|
||||
|
@ -496,7 +497,6 @@ end
|
|||
# topic_id :integer not null
|
||||
# posted :boolean default(FALSE), not null
|
||||
# last_read_post_number :integer
|
||||
# highest_seen_post_number :integer
|
||||
# last_visited_at :datetime
|
||||
# first_visited_at :datetime
|
||||
# notification_level :integer default(1), not null
|
||||
|
|
|
@ -14,6 +14,7 @@ class ListableTopicSerializer < BasicTopicSerializer
|
|||
:last_read_post_number,
|
||||
:unread,
|
||||
:new_posts,
|
||||
:unread_posts,
|
||||
:pinned,
|
||||
:unpinned,
|
||||
:excerpt,
|
||||
|
@ -115,16 +116,25 @@ class ListableTopicSerializer < BasicTopicSerializer
|
|||
|
||||
alias :include_last_read_post_number? :has_user_data
|
||||
|
||||
# TODO: For backwards compatibility with themes,
|
||||
# Remove once Discourse 2.8 is released
|
||||
def unread
|
||||
unread_helper.unread_posts
|
||||
0
|
||||
end
|
||||
alias :include_unread? :has_user_data
|
||||
|
||||
# TODO: For backwards compatibility with themes,
|
||||
# Remove once Discourse 2.8 is released
|
||||
def new_posts
|
||||
unread_helper.new_posts
|
||||
unread_helper.unread_posts
|
||||
end
|
||||
alias :include_new_posts? :has_user_data
|
||||
|
||||
def unread_posts
|
||||
unread_helper.unread_posts
|
||||
end
|
||||
alias :include_unread_posts? :has_user_data
|
||||
|
||||
def include_excerpt?
|
||||
pinned || SiteSetting.always_include_topic_excerpts || theme_modifier_helper.serialize_topic_excerpts
|
||||
end
|
||||
|
|
|
@ -752,7 +752,12 @@ class PostAlerter
|
|||
|
||||
DiscourseEvent.trigger(:before_create_notifications_for_users, notify, post)
|
||||
|
||||
already_seen_user_ids = Set.new TopicUser.where(topic_id: post.topic.id).where("highest_seen_post_number >= ?", post.post_number).pluck(:user_id)
|
||||
already_seen_user_ids = Set.new(
|
||||
TopicUser
|
||||
.where(topic_id: post.topic.id)
|
||||
.where("last_read_post_number >= ?", post.post_number)
|
||||
.pluck(:user_id)
|
||||
)
|
||||
|
||||
each_user_in_batches(notify) do |user|
|
||||
notification_type = !new_record && already_seen_user_ids.include?(user.id) ? Notification.types[:edited] : Notification.types[:posted]
|
||||
|
|
|
@ -2397,7 +2397,7 @@ en:
|
|||
top: "There are no top topics."
|
||||
educate:
|
||||
new: '<p>Your new topics will appear here. By default, topics are considered new and will show a <span class="badge new-topic badge-notification" style="vertical-align:middle;line-height:inherit;"></span> indicator if they were created in the last 2 days.</p><p>Visit your <a href="%{userPrefsUrl}">preferences</a> to change this.</p>'
|
||||
unread: '<p>Your unread topics appear here.</p><p>By default, topics are considered unread and will show unread counts <span class="badge new-posts badge-notification">1</span> if you:</p><ul><li>Created the topic</li><li>Replied to the topic</li><li>Read the topic for more than 4 minutes</li></ul><p>Or if you have explicitly set the topic to Tracked or Watched via the 🔔 in each topic.</p><p>Visit your <a href="%{userPrefsUrl}">preferences</a> to change this.</p>'
|
||||
unread: '<p>Your unread topics appear here.</p><p>By default, topics are considered unread and will show unread counts <span class="badge unread-posts badge-notification">1</span> if you:</p><ul><li>Created the topic</li><li>Replied to the topic</li><li>Read the topic for more than 4 minutes</li></ul><p>Or if you have explicitly set the topic to Tracked or Watched via the 🔔 in each topic.</p><p>Visit your <a href="%{userPrefsUrl}">preferences</a> to change this.</p>'
|
||||
bottom:
|
||||
latest: "There are no more latest topics."
|
||||
posted: "There are no more posted topics."
|
||||
|
@ -2457,15 +2457,9 @@ en:
|
|||
not_found:
|
||||
title: "Topic not found"
|
||||
description: "Sorry, we couldn't find that topic. Perhaps it was removed by a moderator?"
|
||||
total_unread_posts:
|
||||
unread_posts:
|
||||
one: "you have %{count} unread post in this topic"
|
||||
other: "you have %{count} unread posts in this topic"
|
||||
unread_posts:
|
||||
one: "you have %{count} unread old post in this topic"
|
||||
other: "you have %{count} unread old posts in this topic"
|
||||
new_posts:
|
||||
one: "there is %{count} new post in this topic since you last read it"
|
||||
other: "there are %{count} new posts in this topic since you last read it"
|
||||
likes:
|
||||
one: "there is %{count} like in this topic"
|
||||
other: "there are %{count} likes in this topic"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'migration/column_dropper'
|
||||
|
||||
class RemoveHighestSeenPostNumberFromTopicUsers < ActiveRecord::Migration[6.1]
|
||||
DROPPED_COLUMNS = {
|
||||
topic_users: %i{highest_seen_post_number}
|
||||
}
|
||||
|
||||
def up
|
||||
DROPPED_COLUMNS.each do |table, columns|
|
||||
Migration::ColumnDropper.execute_drop(table, columns)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
raise ActiveRecord::IrreversibleMigration
|
||||
end
|
||||
end
|
|
@ -646,7 +646,6 @@ class PostCreator
|
|||
@topic.id,
|
||||
posted: true,
|
||||
last_read_post_number: @post.post_number,
|
||||
highest_seen_post_number: @post.post_number,
|
||||
last_posted_at: Time.zone.now)
|
||||
|
||||
# assume it took us 5 seconds of reading time to make a post
|
||||
|
|
|
@ -57,8 +57,8 @@ def insert_topic_users
|
|||
log "Inserting topic users..."
|
||||
|
||||
DB.exec <<-SQL
|
||||
INSERT INTO topic_users (user_id, topic_id, posted, last_read_post_number, highest_seen_post_number, first_visited_at, last_visited_at, total_msecs_viewed)
|
||||
SELECT user_id, topic_id, 't' , MAX(post_number), MAX(post_number), MIN(created_at), MAX(created_at), COUNT(id) * #{MS_SPEND_CREATING_POST}
|
||||
INSERT INTO topic_users (user_id, topic_id, posted, last_read_post_number, first_visited_at, last_visited_at, total_msecs_viewed)
|
||||
SELECT user_id, topic_id, 't' , MAX(post_number), MIN(created_at), MAX(created_at), COUNT(id) * #{MS_SPEND_CREATING_POST}
|
||||
FROM posts
|
||||
WHERE user_id > 0
|
||||
GROUP BY user_id, topic_id
|
||||
|
|
|
@ -346,7 +346,6 @@ task 'posts:reorder_posts', [:topic_id] => [:environment] do |_, args|
|
|||
["post_timings", "post_number"],
|
||||
["posts", "reply_to_post_number"],
|
||||
["topic_users", "last_read_post_number"],
|
||||
["topic_users", "highest_seen_post_number"],
|
||||
["topic_users", "last_emailed_post_number"],
|
||||
].each do |table, column|
|
||||
builder = DB.build <<~SQL
|
||||
|
|
|
@ -72,7 +72,7 @@ class TopicsBulkAction
|
|||
highest_number_source_column = @user.staff? ? 'highest_staff_post_number' : 'highest_post_number'
|
||||
sql = <<~SQL
|
||||
UPDATE topic_users tu
|
||||
SET highest_seen_post_number = t.#{highest_number_source_column} , last_read_post_number = t.#{highest_number_source_column}
|
||||
SET last_read_post_number = t.#{highest_number_source_column}
|
||||
FROM topics t
|
||||
WHERE t.id = tu.topic_id AND tu.user_id = :user_id AND t.id IN (:topic_ids)
|
||||
SQL
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
class Unread
|
||||
|
||||
# This module helps us calculate unread and new post counts
|
||||
# This module helps us calculate unread post counts
|
||||
|
||||
def initialize(topic, topic_user, guardian)
|
||||
@guardian = guardian
|
||||
|
@ -11,29 +11,27 @@ class Unread
|
|||
end
|
||||
|
||||
def unread_posts
|
||||
return 0 if do_not_notify?(@topic_user.notification_level)
|
||||
result = ((@topic_user.highest_seen_post_number || 0) - (@topic_user.last_read_post_number || 0))
|
||||
result = 0 if result < 0
|
||||
result
|
||||
end
|
||||
|
||||
def new_posts
|
||||
return 0 if @topic_user.highest_seen_post_number.blank?
|
||||
return 0 if @topic_user.last_read_post_number.blank?
|
||||
return 0 if do_not_notify?(@topic_user.notification_level)
|
||||
|
||||
highest_post_number = @guardian.is_staff? ? @topic.highest_staff_post_number : @topic.highest_post_number
|
||||
|
||||
return 0 if (@topic_user.last_read_post_number || 0) > highest_post_number
|
||||
return 0 if @topic_user.last_read_post_number > highest_post_number
|
||||
|
||||
new_posts = (highest_post_number - @topic_user.highest_seen_post_number)
|
||||
new_posts = 0 if new_posts < 0
|
||||
new_posts
|
||||
unread = (highest_post_number - @topic_user.last_read_post_number)
|
||||
unread = 0 if unread < 0
|
||||
unread
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
DO_NOT_NOTIFY_LEVELS = [
|
||||
TopicUser.notification_levels[:muted],
|
||||
TopicUser.notification_levels[:regular]
|
||||
]
|
||||
|
||||
def do_not_notify?(notification_level)
|
||||
[TopicUser.notification_levels[:muted], TopicUser.notification_levels[:regular]].include?(notification_level)
|
||||
DO_NOT_NOTIFY_LEVELS.include?(notification_level)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -192,7 +192,7 @@ after_initialize do
|
|||
return if topic_id.blank? || data[:track] != DiscourseNarrativeBot::NewUserNarrative.to_s
|
||||
|
||||
topic_user = topic_users.find_by(topic_id: topic_id)
|
||||
return if topic_user.present? && (topic_user.last_read_post_number.present? || topic_user.highest_seen_post_number.present?)
|
||||
return if topic_user.present? && topic_user.last_read_post_number.present?
|
||||
|
||||
topic = Topic.find_by(id: topic_id)
|
||||
return if topic.blank?
|
||||
|
|
|
@ -150,8 +150,7 @@ acceptance("Poll in a post reply history", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 3,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -205,8 +204,7 @@ acceptance("Poll in a post reply history", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 12,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
|
|
@ -230,8 +230,7 @@ acceptance("Poll quote", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: true,
|
||||
visible: true,
|
||||
|
@ -275,8 +274,7 @@ acceptance("Poll quote", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
|
|
@ -239,8 +239,7 @@ acceptance("Poll results", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 9,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: true,
|
||||
visible: true,
|
||||
|
@ -295,8 +294,7 @@ acceptance("Poll results", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -343,8 +341,7 @@ acceptance("Poll results", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 1,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
@ -389,8 +386,7 @@ acceptance("Poll results", function (needs) {
|
|||
archetype: "regular",
|
||||
unseen: false,
|
||||
last_read_post_number: 12,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
unread_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
|
|
|
@ -762,8 +762,8 @@ class ImportScripts::Base
|
|||
puts "", "Updating topic users"
|
||||
|
||||
DB.exec <<~SQL
|
||||
INSERT INTO topic_users (user_id, topic_id, posted, last_read_post_number, highest_seen_post_number, first_visited_at, last_visited_at, total_msecs_viewed)
|
||||
SELECT user_id, topic_id, 't' , MAX(post_number), MAX(post_number), MIN(created_at), MAX(created_at), COUNT(id) * 5000
|
||||
INSERT INTO topic_users (user_id, topic_id, posted, last_read_post_number, first_visited_at, last_visited_at, total_msecs_viewed)
|
||||
SELECT user_id, topic_id, 't' , MAX(post_number), MIN(created_at), MAX(created_at), COUNT(id) * 5000
|
||||
FROM posts
|
||||
WHERE user_id > 0
|
||||
GROUP BY user_id, topic_id
|
||||
|
|
|
@ -598,8 +598,7 @@ class ImportScripts::Telligent < ImportScripts::Base
|
|||
# Mark all imported messages as read
|
||||
DB.exec(<<~SQL)
|
||||
UPDATE topic_users tu
|
||||
SET last_read_post_number = t.highest_post_number,
|
||||
highest_seen_post_number = t.highest_post_number
|
||||
SET last_read_post_number = t.highest_post_number
|
||||
FROM topics t
|
||||
JOIN topic_custom_fields tcf ON t.id = tcf.topic_id
|
||||
WHERE tu.topic_id = t.id
|
||||
|
|
|
@ -652,10 +652,6 @@ describe PostDestroyer do
|
|||
it "sets the second user's last_read_post_number back to 1" do
|
||||
expect(topic_user.last_read_post_number).to eq(1)
|
||||
end
|
||||
|
||||
it "sets the second user's last_read_post_number back to 1" do
|
||||
expect(topic_user.highest_seen_post_number).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -82,7 +82,6 @@ describe TopicsBulkAction do
|
|||
tu = TopicUser.find_by(user_id: post1.user_id, topic_id: post1.topic_id)
|
||||
|
||||
expect(tu.last_read_post_number).to eq(3)
|
||||
expect(tu.highest_seen_post_number).to eq(3)
|
||||
end
|
||||
|
||||
context "when the user is staff" do
|
||||
|
@ -106,7 +105,6 @@ describe TopicsBulkAction do
|
|||
tu = TopicUser.find_by(user_id: user.id, topic_id: post1.topic_id)
|
||||
|
||||
expect(tu.last_read_post_number).to eq(4)
|
||||
expect(tu.highest_seen_post_number).to eq(4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,62 +27,45 @@ describe Unread do
|
|||
|
||||
describe 'staff counts' do
|
||||
it 'should correctly return based on staff post number' do
|
||||
|
||||
user.admin = true
|
||||
|
||||
topic_user.last_read_post_number = 13
|
||||
topic_user.highest_seen_post_number = 13
|
||||
|
||||
expect(unread.unread_posts).to eq(0)
|
||||
expect(unread.new_posts).to eq(2)
|
||||
expect(unread.unread_posts).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unread_posts' do
|
||||
it 'should have 0 unread posts if the user has seen all posts' do
|
||||
it 'should have 0 unread posts if the user has read all posts' do
|
||||
topic_user.last_read_post_number = 13
|
||||
topic_user.highest_seen_post_number = 13
|
||||
expect(unread.unread_posts).to eq(0)
|
||||
end
|
||||
|
||||
it 'should have 6 unread posts if the user has seen all but 6 posts' do
|
||||
topic_user.last_read_post_number = 5
|
||||
topic_user.highest_seen_post_number = 11
|
||||
expect(unread.unread_posts).to eq(6)
|
||||
it 'returns the right unread posts for a user' do
|
||||
topic_user.last_read_post_number = 10
|
||||
expect(unread.unread_posts).to eq(3)
|
||||
end
|
||||
|
||||
it 'should have 0 unread posts if the user has seen more posts than exist (deleted)' do
|
||||
topic_user.last_read_post_number = 100
|
||||
topic_user.highest_seen_post_number = 13
|
||||
it 'returns the right unread posts for a staff user' do
|
||||
user.admin = true
|
||||
topic_user.last_read_post_number = 10
|
||||
expect(unread.unread_posts).to eq(5)
|
||||
end
|
||||
|
||||
it 'should have 0 unread posts if the user has read more posts than exist (deleted)' do
|
||||
topic_user.last_read_post_number = 14
|
||||
expect(unread.unread_posts).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'new_posts' do
|
||||
it 'should have 0 new posts if the user has read all posts' do
|
||||
topic_user.last_read_post_number = 13
|
||||
expect(unread.new_posts).to eq(0)
|
||||
end
|
||||
|
||||
it 'returns 0 when the topic is the same length as when you last saw it' do
|
||||
topic_user.highest_seen_post_number = 13
|
||||
expect(unread.new_posts).to eq(0)
|
||||
end
|
||||
|
||||
it 'has 3 new posts if the user has read 10 posts' do
|
||||
topic_user.highest_seen_post_number = 10
|
||||
expect(unread.new_posts).to eq(3)
|
||||
end
|
||||
|
||||
it 'has 0 new posts if the user has read 10 posts but is not tracking' do
|
||||
topic_user.highest_seen_post_number = 10
|
||||
it 'has 0 unread posts if the user has read 10 posts but is not tracking' do
|
||||
topic_user.last_read_post_number = 10
|
||||
topic_user.notification_level = TopicUser.notification_levels[:regular]
|
||||
expect(unread.new_posts).to eq(0)
|
||||
expect(unread.unread_posts).to eq(0)
|
||||
end
|
||||
|
||||
it 'has 0 new posts if the user read more posts than exist (deleted)' do
|
||||
topic_user.highest_seen_post_number = 16
|
||||
expect(unread.new_posts).to eq(0)
|
||||
it 'has 0 unread psots if the user has not seen the topic' do
|
||||
topic_user.last_read_post_number = nil
|
||||
expect(unread.unread_posts).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -425,7 +425,6 @@ describe PostMover do
|
|||
bookmarked: true,
|
||||
notification_level: TopicUser.notification_levels[:watching],
|
||||
last_read_post_number: 4,
|
||||
highest_seen_post_number: 4,
|
||||
last_emailed_post_number: 3
|
||||
)
|
||||
tu2 = Fabricate(
|
||||
|
@ -435,7 +434,6 @@ describe PostMover do
|
|||
bookmarked: true,
|
||||
notification_level: TopicUser.notification_levels[:watching],
|
||||
last_read_post_number: 4,
|
||||
highest_seen_post_number: 4,
|
||||
last_emailed_post_number: 3
|
||||
)
|
||||
|
||||
|
@ -470,21 +468,18 @@ describe PostMover do
|
|||
create_topic_user(
|
||||
user1,
|
||||
last_read_post_number: 4,
|
||||
highest_seen_post_number: 4,
|
||||
last_emailed_post_number: 3,
|
||||
notification_level: :tracking
|
||||
)
|
||||
create_topic_user(
|
||||
user2,
|
||||
last_read_post_number: 2,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 2,
|
||||
notification_level: :tracking
|
||||
)
|
||||
create_topic_user(
|
||||
user3,
|
||||
last_read_post_number: 1,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 4,
|
||||
notification_level: :watching
|
||||
)
|
||||
|
@ -496,28 +491,24 @@ describe PostMover do
|
|||
expect(TopicUser.find_by(topic: topic, user: user))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 4,
|
||||
highest_seen_post_number: 4,
|
||||
last_emailed_post_number: nil,
|
||||
notification_level: TopicUser.notification_levels[:tracking]
|
||||
)
|
||||
expect(TopicUser.find_by(topic: topic, user: user1))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 4,
|
||||
highest_seen_post_number: 4,
|
||||
last_emailed_post_number: 3,
|
||||
notification_level: TopicUser.notification_levels[:tracking]
|
||||
)
|
||||
expect(TopicUser.find_by(topic: topic, user: user2))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 2,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 2,
|
||||
notification_level: TopicUser.notification_levels[:tracking]
|
||||
)
|
||||
expect(TopicUser.find_by(topic: topic, user: user3))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 1,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 4,
|
||||
notification_level: TopicUser.notification_levels[:watching]
|
||||
)
|
||||
|
@ -526,7 +517,6 @@ describe PostMover do
|
|||
expect(TopicUser.find_by(topic: new_topic, user: user))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 1,
|
||||
highest_seen_post_number: 1,
|
||||
last_emailed_post_number: nil,
|
||||
notification_level: TopicUser.notification_levels[:watching],
|
||||
posted: true
|
||||
|
@ -534,7 +524,6 @@ describe PostMover do
|
|||
expect(TopicUser.find_by(topic: new_topic, user: user1))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 2,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 2,
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
posted: false
|
||||
|
@ -542,7 +531,6 @@ describe PostMover do
|
|||
expect(TopicUser.find_by(topic: new_topic, user: user2))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 2,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 2,
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
posted: true
|
||||
|
@ -550,7 +538,6 @@ describe PostMover do
|
|||
expect(TopicUser.find_by(topic: new_topic, user: user3))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 1,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 2,
|
||||
notification_level: TopicUser.notification_levels[:watching],
|
||||
posted: false
|
||||
|
@ -810,52 +797,44 @@ describe PostMover do
|
|||
create_topic_user(
|
||||
user1, topic,
|
||||
last_read_post_number: 3,
|
||||
highest_seen_post_number: 3,
|
||||
last_emailed_post_number: 3
|
||||
)
|
||||
create_topic_user(
|
||||
user1, destination_topic,
|
||||
last_read_post_number: 1,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 1
|
||||
)
|
||||
|
||||
create_topic_user(
|
||||
user2, topic,
|
||||
last_read_post_number: 3,
|
||||
highest_seen_post_number: 3,
|
||||
last_emailed_post_number: 3
|
||||
)
|
||||
create_topic_user(
|
||||
user2, destination_topic,
|
||||
last_read_post_number: 2,
|
||||
highest_seen_post_number: 1,
|
||||
last_emailed_post_number: 2
|
||||
)
|
||||
|
||||
create_topic_user(
|
||||
admin1, topic,
|
||||
last_read_post_number: 3,
|
||||
highest_seen_post_number: 3,
|
||||
last_emailed_post_number: 3
|
||||
)
|
||||
create_topic_user(
|
||||
admin1, destination_topic,
|
||||
last_read_post_number: 2,
|
||||
highest_seen_post_number: 3,
|
||||
last_emailed_post_number: 1
|
||||
)
|
||||
|
||||
create_topic_user(
|
||||
admin2, topic,
|
||||
last_read_post_number: 3,
|
||||
highest_seen_post_number: 3,
|
||||
last_emailed_post_number: 3
|
||||
)
|
||||
create_topic_user(
|
||||
admin2, destination_topic,
|
||||
last_read_post_number: 3,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 3
|
||||
)
|
||||
|
||||
|
@ -864,28 +843,24 @@ describe PostMover do
|
|||
expect(TopicUser.find_by(topic: moved_to_topic, user: user1))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 1,
|
||||
highest_seen_post_number: 5,
|
||||
last_emailed_post_number: 1
|
||||
)
|
||||
|
||||
expect(TopicUser.find_by(topic: moved_to_topic, user: user2))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 5,
|
||||
highest_seen_post_number: 1,
|
||||
last_emailed_post_number: 5
|
||||
)
|
||||
|
||||
expect(TopicUser.find_by(topic: moved_to_topic, user: admin1))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 2,
|
||||
highest_seen_post_number: 5,
|
||||
last_emailed_post_number: 1
|
||||
)
|
||||
|
||||
expect(TopicUser.find_by(topic: moved_to_topic, user: admin2))
|
||||
.to have_attributes(
|
||||
last_read_post_number: 5,
|
||||
highest_seen_post_number: 2,
|
||||
last_emailed_post_number: 5
|
||||
)
|
||||
end
|
||||
|
@ -895,14 +870,14 @@ describe PostMover do
|
|||
|
||||
original_topic_user1 = create_topic_user(
|
||||
user1, topic,
|
||||
highest_seen_post_number: 5,
|
||||
last_read_post_number: 5,
|
||||
first_visited_at: 5.hours.ago,
|
||||
last_visited_at: 30.minutes.ago,
|
||||
notification_level: :tracking
|
||||
).reload
|
||||
destination_topic_user1 = create_topic_user(
|
||||
user1, destination_topic,
|
||||
highest_seen_post_number: 5,
|
||||
last_read_post_number: 5,
|
||||
first_visited_at: 7.hours.ago,
|
||||
last_visited_at: 2.hours.ago,
|
||||
notification_level: :watching
|
||||
|
@ -910,14 +885,14 @@ describe PostMover do
|
|||
|
||||
original_topic_user2 = create_topic_user(
|
||||
user2, topic,
|
||||
highest_seen_post_number: 5,
|
||||
last_read_post_number: 5,
|
||||
first_visited_at: 3.hours.ago,
|
||||
last_visited_at: 1.hour.ago,
|
||||
notification_level: :watching
|
||||
).reload
|
||||
destination_topic_user2 = create_topic_user(
|
||||
user2, destination_topic,
|
||||
highest_seen_post_number: 5,
|
||||
last_read_post_number: 5,
|
||||
first_visited_at: 2.hours.ago,
|
||||
last_visited_at: 1.hour.ago,
|
||||
notification_level: :tracking
|
||||
|
|
|
@ -20,12 +20,11 @@ describe PostTiming do
|
|||
PostTiming.create!(topic_id: topic_id, user_id: user_id, post_number: post_number, msecs: 0)
|
||||
end
|
||||
|
||||
def topic_user(user_id, last_read_post_number, highest_seen_post_number)
|
||||
def topic_user(user_id, last_read_post_number)
|
||||
TopicUser.create!(
|
||||
topic_id: topic_id,
|
||||
user_id: user_id,
|
||||
last_read_post_number: last_read_post_number,
|
||||
highest_seen_post_number: highest_seen_post_number
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -37,9 +36,9 @@ describe PostTiming do
|
|||
timing(3, 2)
|
||||
timing(3, 3)
|
||||
|
||||
_tu_one = topic_user(1, 1, 1)
|
||||
_tu_two = topic_user(2, 2, 2)
|
||||
_tu_three = topic_user(3, 3, 3)
|
||||
_tu_one = topic_user(1, 1)
|
||||
_tu_two = topic_user(2, 2)
|
||||
_tu_three = topic_user(3, 3)
|
||||
|
||||
PostTiming.pretend_read(topic_id, 2, 3)
|
||||
|
||||
|
@ -49,15 +48,12 @@ describe PostTiming do
|
|||
|
||||
tu = TopicUser.find_by(topic_id: topic_id, user_id: 1)
|
||||
expect(tu.last_read_post_number).to eq(1)
|
||||
expect(tu.highest_seen_post_number).to eq(1)
|
||||
|
||||
tu = TopicUser.find_by(topic_id: topic_id, user_id: 2)
|
||||
expect(tu.last_read_post_number).to eq(3)
|
||||
expect(tu.highest_seen_post_number).to eq(3)
|
||||
|
||||
tu = TopicUser.find_by(topic_id: topic_id, user_id: 3)
|
||||
expect(tu.last_read_post_number).to eq(3)
|
||||
expect(tu.highest_seen_post_number).to eq(3)
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1615,7 +1615,12 @@ describe Topic do
|
|||
end
|
||||
|
||||
it 'should generate the modified notification for the topic if already seen' do
|
||||
TopicUser.create!(topic_id: topic.id, highest_seen_post_number: topic.posts.first.post_number, user_id: user.id)
|
||||
TopicUser.create!(
|
||||
topic_id: topic.id,
|
||||
last_read_post_number: topic.posts.first.post_number,
|
||||
user_id: user.id
|
||||
)
|
||||
|
||||
expect do
|
||||
topic.change_category_to_id(new_category.id)
|
||||
end.to change { Notification.count }.by(2)
|
||||
|
|
|
@ -597,7 +597,6 @@ describe TopicTrackingState do
|
|||
tracking = {
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
last_read_post_number: 1,
|
||||
highest_seen_post_number: 1
|
||||
}
|
||||
|
||||
TopicUser.change(user.id, post1.topic_id, tracking)
|
||||
|
|
|
@ -434,7 +434,7 @@ describe TopicUser do
|
|||
p2 = Fabricate(:post, user: p1.user, topic: p1.topic, post_number: 2)
|
||||
p1.topic.notifier.watch_topic!(p1.user_id)
|
||||
|
||||
DB.exec("UPDATE topic_users set highest_seen_post_number=1, last_read_post_number=0
|
||||
DB.exec("UPDATE topic_users set last_read_post_number=0
|
||||
WHERE topic_id = :topic_id AND user_id = :user_id", topic_id: p1.topic_id, user_id: p1.user_id)
|
||||
|
||||
[p1, p2].each do |p|
|
||||
|
@ -445,7 +445,6 @@ describe TopicUser do
|
|||
|
||||
tu = TopicUser.find_by(user_id: p1.user_id, topic_id: p1.topic_id)
|
||||
expect(tu.last_read_post_number).to eq(p2.post_number)
|
||||
expect(tu.highest_seen_post_number).to eq(2)
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -64,8 +64,7 @@ describe 'private messages' do
|
|||
archetype: { type: :string },
|
||||
unseen: { type: :boolean },
|
||||
last_read_post_number: { type: :integer },
|
||||
unread: { type: :integer },
|
||||
new_posts: { type: :integer },
|
||||
unread_posts: { type: :integer },
|
||||
pinned: { type: :boolean },
|
||||
unpinned: { type: :string, nullable: true },
|
||||
visible: { type: :boolean },
|
||||
|
@ -174,8 +173,7 @@ describe 'private messages' do
|
|||
archetype: { type: :string },
|
||||
unseen: { type: :boolean },
|
||||
last_read_post_number: { type: :integer },
|
||||
unread: { type: :integer },
|
||||
new_posts: { type: :integer },
|
||||
unread_posts: { type: :integer },
|
||||
pinned: { type: :boolean },
|
||||
unpinned: { type: :string, nullable: true },
|
||||
visible: { type: :boolean },
|
||||
|
|
|
@ -277,8 +277,7 @@ describe 'tags' do
|
|||
archetype: { type: :string },
|
||||
unseen: { type: :boolean },
|
||||
last_read_post_number: { type: :integer },
|
||||
unread: { type: :integer },
|
||||
new_posts: { type: :integer },
|
||||
unread_posts: { type: :integer },
|
||||
pinned: { type: :boolean },
|
||||
unpinned: { type: :string, nullable: true },
|
||||
visible: { type: :boolean },
|
||||
|
|
|
@ -225,8 +225,7 @@ describe 'topics' do
|
|||
archetype: { type: :string },
|
||||
unseen: { type: :boolean },
|
||||
last_read_post_number: { type: :integer },
|
||||
unread: { type: :integer },
|
||||
new_posts: { type: :integer },
|
||||
unread_posts: { type: :integer },
|
||||
pinned: { type: :boolean },
|
||||
unpinned: { type: :boolean },
|
||||
visible: { type: :boolean },
|
||||
|
@ -603,8 +602,7 @@ describe 'topics' do
|
|||
archetype: { type: :string },
|
||||
unseen: { type: :boolean },
|
||||
last_read_post_number: { type: :integer },
|
||||
unread: { type: :integer },
|
||||
new_posts: { type: :integer },
|
||||
unread_posts: { type: :integer },
|
||||
pinned: { type: :boolean },
|
||||
unpinned: { type: :string, nullable: true },
|
||||
visible: { type: :boolean },
|
||||
|
@ -704,8 +702,7 @@ describe 'topics' do
|
|||
archetype: { type: :string },
|
||||
unseen: { type: :boolean },
|
||||
last_read_post_number: { type: :integer },
|
||||
unread: { type: :integer },
|
||||
new_posts: { type: :integer },
|
||||
unread_posts: { type: :integer },
|
||||
pinned: { type: :boolean },
|
||||
unpinned: { type: :boolean },
|
||||
visible: { type: :boolean },
|
||||
|
@ -807,8 +804,7 @@ describe 'topics' do
|
|||
archetype: { type: :string },
|
||||
unseen: { type: :boolean },
|
||||
last_read_post_number: { type: :integer },
|
||||
unread: { type: :integer },
|
||||
new_posts: { type: :integer },
|
||||
unread_posts: { type: :integer },
|
||||
pinned: { type: :boolean },
|
||||
unpinned: { type: :boolean },
|
||||
visible: { type: :boolean },
|
||||
|
|
|
@ -1010,7 +1010,6 @@ RSpec.describe TopicsController do
|
|||
|
||||
topic_user.update!(
|
||||
last_read_post_number: 2,
|
||||
highest_seen_post_number: 2
|
||||
)
|
||||
|
||||
# ensure we have 2 notifications
|
||||
|
@ -1036,7 +1035,7 @@ RSpec.describe TopicsController do
|
|||
expect(PostTiming.where(topic: topic, user: user, post_number: 2).exists?).to eq(false)
|
||||
expect(PostTiming.where(topic: topic, user: user, post_number: 1).exists?).to eq(true)
|
||||
|
||||
expect(TopicUser.where(topic: topic, user: user, last_read_post_number: 1, highest_seen_post_number: 1).exists?).to eq(true)
|
||||
expect(TopicUser.where(topic: topic, user: user, last_read_post_number: 1).exists?).to eq(true)
|
||||
|
||||
user.user_stat.reload
|
||||
expect(user.user_stat.first_unread_at).to eq_time(topic.updated_at)
|
||||
|
@ -1051,7 +1050,7 @@ RSpec.describe TopicsController do
|
|||
delete "/t/#{topic.id}/timings.json?last=1"
|
||||
|
||||
expect(PostTiming.where(topic: topic, user: user, post_number: 1).exists?).to eq(false)
|
||||
expect(TopicUser.where(topic: topic, user: user, last_read_post_number: nil, highest_seen_post_number: nil).exists?).to eq(true)
|
||||
expect(TopicUser.where(topic: topic, user: user, last_read_post_number: nil).exists?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1259,7 +1259,13 @@ describe PostAlerter do
|
|||
fab!(:category) { Fabricate(:category) }
|
||||
|
||||
it 'creates single edit notification when post is modified' do
|
||||
TopicUser.create!(user_id: user.id, topic_id: topic.id, notification_level: TopicUser.notification_levels[:watching], highest_seen_post_number: post.post_number)
|
||||
TopicUser.create!(
|
||||
user_id: user.id,
|
||||
topic_id: topic.id,
|
||||
notification_level: TopicUser.notification_levels[:watching],
|
||||
last_read_post_number: post.post_number
|
||||
)
|
||||
|
||||
PostRevisor.new(post).revise!(last_editor, tags: [tag.name])
|
||||
PostAlerter.new.notify_post_users(post, [])
|
||||
expect(Notification.count).to eq(1)
|
||||
|
@ -1280,7 +1286,7 @@ describe PostAlerter do
|
|||
category: category.id
|
||||
)
|
||||
|
||||
TopicUser.change(user, post.topic_id, highest_seen_post_number: post.post_number)
|
||||
TopicUser.change(user, post.topic_id, last_read_post_number: post.post_number)
|
||||
|
||||
# Manually run job after the user read the topic to simulate a slow
|
||||
# Sidekiq.
|
||||
|
|
Loading…
Reference in New Issue