FEATURE: Special call-out for new / returning posters. (#7115)
This commit is contained in:
parent
65464969cd
commit
35942f7c7c
|
@ -134,6 +134,13 @@ export default function transformPost(
|
||||||
postAtts.topicUrl = topic.get("url");
|
postAtts.topicUrl = topic.get("url");
|
||||||
postAtts.isSaving = post.isSaving;
|
postAtts.isSaving = post.isSaving;
|
||||||
|
|
||||||
|
if (post.post_notice_type) {
|
||||||
|
postAtts.postNoticeType = post.post_notice_type;
|
||||||
|
if (postAtts.postNoticeType === "returning") {
|
||||||
|
postAtts.postNoticeTime = new Date(post.post_notice_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const showPMMap =
|
const showPMMap =
|
||||||
topic.archetype === "private_message" && post.post_number === 1;
|
topic.archetype === "private_message" && post.post_number === 1;
|
||||||
if (showPMMap) {
|
if (showPMMap) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
formatUsername
|
formatUsername
|
||||||
} from "discourse/lib/utilities";
|
} from "discourse/lib/utilities";
|
||||||
import hbs from "discourse/widgets/hbs-compiler";
|
import hbs from "discourse/widgets/hbs-compiler";
|
||||||
|
import { relativeAge } from "discourse/lib/formatter";
|
||||||
|
|
||||||
function transformWithCallbacks(post) {
|
function transformWithCallbacks(post) {
|
||||||
let transformed = transformBasicPost(post);
|
let transformed = transformBasicPost(post);
|
||||||
|
@ -427,6 +428,29 @@ createWidget("post-contents", {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
createWidget("post-notice", {
|
||||||
|
tagName: "div.post-notice",
|
||||||
|
|
||||||
|
html(attrs) {
|
||||||
|
let text, icon;
|
||||||
|
if (attrs.postNoticeType === "first") {
|
||||||
|
icon = "hands-helping";
|
||||||
|
text = I18n.t("post.notice.first", { user: attrs.username });
|
||||||
|
} else if (attrs.postNoticeType === "returning") {
|
||||||
|
icon = "far-smile";
|
||||||
|
text = I18n.t("post.notice.return", {
|
||||||
|
user: attrs.username,
|
||||||
|
time: relativeAge(attrs.postNoticeTime, {
|
||||||
|
format: "tiny",
|
||||||
|
addAgo: true
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return h("p", [iconNode(icon), text]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
createWidget("post-body", {
|
createWidget("post-body", {
|
||||||
tagName: "div.topic-body.clearfix",
|
tagName: "div.topic-body.clearfix",
|
||||||
|
|
||||||
|
@ -505,6 +529,10 @@ createWidget("post-article", {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attrs.postNoticeType) {
|
||||||
|
rows.push(h("div.row", [this.attach("post-notice", attrs)]));
|
||||||
|
}
|
||||||
|
|
||||||
rows.push(
|
rows.push(
|
||||||
h("div.row", [
|
h("div.row", [
|
||||||
this.attach("post-avatar", attrs),
|
this.attach("post-avatar", attrs),
|
||||||
|
|
|
@ -864,3 +864,22 @@ a.mention-group {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post-notice {
|
||||||
|
background-color: $tertiary-low;
|
||||||
|
border-top: 1px solid $primary-low;
|
||||||
|
color: $primary;
|
||||||
|
padding: 1em;
|
||||||
|
width: calc(
|
||||||
|
#{$topic-body-width} + #{$topic-avatar-width} - #{$topic-body-width-padding} +
|
||||||
|
3px
|
||||||
|
);
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-icon {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -194,6 +194,7 @@ class Post < ActiveRecord::Base
|
||||||
def recover!
|
def recover!
|
||||||
super
|
super
|
||||||
update_flagged_posts_count
|
update_flagged_posts_count
|
||||||
|
delete_post_notices
|
||||||
recover_public_post_actions
|
recover_public_post_actions
|
||||||
TopicLink.extract_from(self)
|
TopicLink.extract_from(self)
|
||||||
QuotedPost.extract_from(self)
|
QuotedPost.extract_from(self)
|
||||||
|
@ -381,6 +382,11 @@ class Post < ActiveRecord::Base
|
||||||
PostAction.update_flagged_posts_count
|
PostAction.update_flagged_posts_count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_post_notices
|
||||||
|
self.custom_fields.delete("post_notice_type")
|
||||||
|
self.custom_fields.delete("post_notice_time")
|
||||||
|
end
|
||||||
|
|
||||||
def recover_public_post_actions
|
def recover_public_post_actions
|
||||||
PostAction.publics
|
PostAction.publics
|
||||||
.with_deleted
|
.with_deleted
|
||||||
|
|
|
@ -70,6 +70,8 @@ class PostSerializer < BasicPostSerializer
|
||||||
:is_auto_generated,
|
:is_auto_generated,
|
||||||
:action_code,
|
:action_code,
|
||||||
:action_code_who,
|
:action_code_who,
|
||||||
|
:post_notice_type,
|
||||||
|
:post_notice_time,
|
||||||
:last_wiki_edit,
|
:last_wiki_edit,
|
||||||
:locked,
|
:locked,
|
||||||
:excerpt
|
:excerpt
|
||||||
|
@ -363,6 +365,22 @@ class PostSerializer < BasicPostSerializer
|
||||||
include_action_code? && action_code_who.present?
|
include_action_code? && action_code_who.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def post_notice_type
|
||||||
|
post_custom_fields["post_notice_type"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_post_notice_type?
|
||||||
|
post_notice_type.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def post_notice_time
|
||||||
|
post_custom_fields["post_notice_time"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_post_notice_time?
|
||||||
|
post_notice_time.present?
|
||||||
|
end
|
||||||
|
|
||||||
def locked
|
def locked
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
|
@ -2149,6 +2149,10 @@ en:
|
||||||
one: "view 1 hidden reply"
|
one: "view 1 hidden reply"
|
||||||
other: "view {{count}} hidden replies"
|
other: "view {{count}} hidden replies"
|
||||||
|
|
||||||
|
notice:
|
||||||
|
first: "This is the first time {{user}} has posted — let's welcome them to our community!"
|
||||||
|
return: "It's been a while since we've seen {{user}} — their last post was in {{time}}."
|
||||||
|
|
||||||
unread: "Post is unread"
|
unread: "Post is unread"
|
||||||
has_replies:
|
has_replies:
|
||||||
one: "{{count}} Reply"
|
one: "{{count}} Reply"
|
||||||
|
|
|
@ -1901,6 +1901,8 @@ en:
|
||||||
max_allowed_message_recipients: "Maximum recipients allowed in a message."
|
max_allowed_message_recipients: "Maximum recipients allowed in a message."
|
||||||
watched_words_regular_expressions: "Watched words are regular expressions."
|
watched_words_regular_expressions: "Watched words are regular expressions."
|
||||||
|
|
||||||
|
returning_users_days: "How many days should pass before a user is considered to be returning."
|
||||||
|
|
||||||
default_email_digest_frequency: "How often users receive summary emails by default."
|
default_email_digest_frequency: "How often users receive summary emails by default."
|
||||||
default_include_tl0_in_digests: "Include posts from new users in summary emails by default. Users can change this in their preferences."
|
default_include_tl0_in_digests: "Include posts from new users in summary emails by default. Users can change this in their preferences."
|
||||||
default_email_personal_messages: "Send an email when someone messages the user by default."
|
default_email_personal_messages: "Send an email when someone messages the user by default."
|
||||||
|
|
|
@ -807,6 +807,8 @@ posting:
|
||||||
default: false
|
default: false
|
||||||
client: true
|
client: true
|
||||||
shadowed_by_global: true
|
shadowed_by_global: true
|
||||||
|
returning_users_days:
|
||||||
|
default: 60
|
||||||
|
|
||||||
email:
|
email:
|
||||||
email_time_window_mins:
|
email_time_window_mins:
|
||||||
|
|
|
@ -165,6 +165,7 @@ class PostCreator
|
||||||
transaction do
|
transaction do
|
||||||
build_post_stats
|
build_post_stats
|
||||||
create_topic
|
create_topic
|
||||||
|
create_post_notice
|
||||||
save_post
|
save_post
|
||||||
extract_links
|
extract_links
|
||||||
track_topic
|
track_topic
|
||||||
|
@ -508,6 +509,21 @@ class PostCreator
|
||||||
@user.update_attributes(last_posted_at: @post.created_at)
|
@user.update_attributes(last_posted_at: @post.created_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_post_notice
|
||||||
|
last_post_time = Post.where(user_id: @user.id)
|
||||||
|
.order(created_at: :desc)
|
||||||
|
.limit(1)
|
||||||
|
.pluck(:created_at)
|
||||||
|
.first
|
||||||
|
|
||||||
|
if !last_post_time
|
||||||
|
@post.custom_fields["post_notice_type"] = "first"
|
||||||
|
elsif SiteSetting.returning_users_days > 0 && last_post_time < SiteSetting.returning_users_days.days.ago
|
||||||
|
@post.custom_fields["post_notice_type"] = "returning"
|
||||||
|
@post.custom_fields["post_notice_time"] = last_post_time
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def publish
|
def publish
|
||||||
return if @opts[:import_mode] || @post.post_number == 1
|
return if @opts[:import_mode] || @post.post_number == 1
|
||||||
@post.publish_change_to_clients! :created
|
@post.publish_change_to_clients! :created
|
||||||
|
|
|
@ -118,6 +118,7 @@ module SvgSprite
|
||||||
"globe",
|
"globe",
|
||||||
"globe-americas",
|
"globe-americas",
|
||||||
"hand-point-right",
|
"hand-point-right",
|
||||||
|
"hands-helping",
|
||||||
"heading",
|
"heading",
|
||||||
"heart",
|
"heart",
|
||||||
"home",
|
"home",
|
||||||
|
|
|
@ -18,7 +18,7 @@ class TopicView
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.default_post_custom_fields
|
def self.default_post_custom_fields
|
||||||
@default_post_custom_fields ||= ["action_code_who"]
|
@default_post_custom_fields ||= ["action_code_who", "post_notice_type", "post_notice_time"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.post_custom_fields_whitelisters
|
def self.post_custom_fields_whitelisters
|
||||||
|
|
|
@ -1238,4 +1238,32 @@ describe PostCreator do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "#create_post_notice" do
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
let(:new_user) { Fabricate(:user) }
|
||||||
|
let(:returning_user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
it "generates post notices" do
|
||||||
|
# new users
|
||||||
|
post = PostCreator.create(new_user, title: "one of my first topics", raw: "one of my first posts")
|
||||||
|
expect(post.custom_fields["post_notice_type"]).to eq("first")
|
||||||
|
post = PostCreator.create(new_user, title: "another one of my first topics", raw: "another one of my first posts")
|
||||||
|
expect(post.custom_fields["post_notice_type"]).to eq(nil)
|
||||||
|
|
||||||
|
# returning users
|
||||||
|
SiteSetting.returning_users_days = 30
|
||||||
|
old_post = Fabricate(:post, user: returning_user, created_at: 31.days.ago)
|
||||||
|
post = PostCreator.create(returning_user, title: "this is a returning topic", raw: "this is a post")
|
||||||
|
expect(post.custom_fields["post_notice_type"]).to eq("returning")
|
||||||
|
expect(post.custom_fields["post_notice_time"]).to eq(old_post.created_at.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not generate post notices" do
|
||||||
|
Fabricate(:post, user: user, created_at: 3.days.ago)
|
||||||
|
post = PostCreator.create(user, title: "this is another topic", raw: "this is my another post")
|
||||||
|
expect(post.custom_fields["post_notice_type"]).to eq(nil)
|
||||||
|
expect(post.custom_fields["post_notice_time"]).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -134,6 +134,29 @@ describe Post do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'a post with notices' do
|
||||||
|
let(:post) {
|
||||||
|
post = Fabricate(:post, post_args)
|
||||||
|
post.custom_fields["post_notice_type"] = "returning"
|
||||||
|
post.custom_fields["post_notice_time"] = 1.day.ago
|
||||||
|
post
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
post.trash!
|
||||||
|
post.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'recovery' do
|
||||||
|
it 'deletes notices' do
|
||||||
|
post.recover!
|
||||||
|
|
||||||
|
expect(post.custom_fields).not_to have_key("post_notice_type")
|
||||||
|
expect(post.custom_fields).not_to have_key("post_notice_time")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'flagging helpers' do
|
describe 'flagging helpers' do
|
||||||
|
|
|
@ -852,3 +852,22 @@ widgetTest("pm map", {
|
||||||
assert.equal(find(".private-message-map .user").length, 1);
|
assert.equal(find(".private-message-map .user").length, 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
widgetTest("post notice", {
|
||||||
|
template: '{{mount-widget widget="post" args=args}}',
|
||||||
|
beforeEach() {
|
||||||
|
this.set("args", {
|
||||||
|
postNoticeType: "returning",
|
||||||
|
postNoticeTime: new Date("2010-01-01 12:00:00 UTC"),
|
||||||
|
username: "codinghorror"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
test(assert) {
|
||||||
|
assert.equal(
|
||||||
|
find(".post-notice")
|
||||||
|
.text()
|
||||||
|
.trim(),
|
||||||
|
I18n.t("post.notice.return", { user: "codinghorror", time: "Jan '10" })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue