FEATURE: add composer warning when user haven't been seen in a long time (#18340)
* FEATURE: add composer warning when user haven't been seen in a long time When a user creates a PM and adds a recipient that hasn't been seen in a long time then we'll now show a warning in composer indicating that the user hasn't been seen in a long time.
This commit is contained in:
parent
0f5db0838d
commit
2ee721f8aa
|
@ -5,8 +5,10 @@ import LinkLookup from "discourse/lib/link-lookup";
|
|||
import { not } from "@ember/object/computed";
|
||||
import { scheduleOnce } from "@ember/runloop";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
let _messagesCache = {};
|
||||
let _recipient_names = [];
|
||||
|
||||
export default Component.extend({
|
||||
classNameBindings: [":composer-popup-container", "hidden"],
|
||||
|
@ -18,6 +20,7 @@ export default Component.extend({
|
|||
_similarTopicsMessage: null,
|
||||
_yourselfConfirm: null,
|
||||
similarTopics: null,
|
||||
usersNotSeen: null,
|
||||
|
||||
hidden: not("composer.viewOpenOrFullscreen"),
|
||||
|
||||
|
@ -119,6 +122,53 @@ export default Component.extend({
|
|||
const composer = this.composer;
|
||||
if (composer.get("privateMessage")) {
|
||||
const recipients = composer.targetRecipientsArray;
|
||||
const recipient_names = recipients
|
||||
.filter((r) => r.type === "user")
|
||||
.map(({ name }) => name);
|
||||
|
||||
if (
|
||||
recipient_names.length > 0 &&
|
||||
recipient_names.length !== _recipient_names.length &&
|
||||
!recipient_names.every((v, i) => v === _recipient_names[i])
|
||||
) {
|
||||
_recipient_names = recipient_names;
|
||||
|
||||
ajax(`/composer_messages/user_not_seen_in_a_while`, {
|
||||
type: "GET",
|
||||
data: {
|
||||
usernames: recipient_names,
|
||||
},
|
||||
}).then((response) => {
|
||||
if (
|
||||
response.user_count > 0 &&
|
||||
this.get("usersNotSeen") !== response.usernames.join("-")
|
||||
) {
|
||||
this.set("usersNotSeen", response.usernames.join("-"));
|
||||
this.messagesByTemplate["education"] = undefined;
|
||||
|
||||
let usernames = [];
|
||||
response.usernames.forEach((username, index) => {
|
||||
usernames[
|
||||
index
|
||||
] = `<a class='mention' href='/u/${username}'>@${username}</a>`;
|
||||
});
|
||||
|
||||
let body_key = "composer.user_not_seen_in_a_while.single";
|
||||
if (response.user_count > 1) {
|
||||
body_key = "composer.user_not_seen_in_a_while.multiple";
|
||||
}
|
||||
const message = composer.store.createRecord("composer-message", {
|
||||
id: "user-not-seen",
|
||||
templateName: "education",
|
||||
body: I18n.t(body_key, {
|
||||
usernames: usernames.join(", "),
|
||||
time_ago: response.time_ago,
|
||||
}),
|
||||
});
|
||||
this.send("popup", message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
recipients.length > 0 &&
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, triggerKeyEvent, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
|
||||
acceptance("Composer - Messages", function (needs) {
|
||||
needs.user();
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/composer_messages/user_not_seen_in_a_while", () => {
|
||||
return helper.response({
|
||||
user_count: 1,
|
||||
usernames: ["charlie"],
|
||||
time_ago: "1 year ago",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Shows warning in composer if user hasn't been seen in a long time.", async function (assert) {
|
||||
await visit("/u/charlie");
|
||||
await click("button.compose-pm");
|
||||
assert.ok(
|
||||
!exists(".composer-popup"),
|
||||
"composer warning is not shown by default"
|
||||
);
|
||||
await triggerKeyEvent(".d-editor-input", "keyup", "Space");
|
||||
assert.ok(exists(".composer-popup"), "shows composer warning message");
|
||||
assert.ok(
|
||||
query(".composer-popup").innerHTML.includes(
|
||||
I18n.t("composer.user_not_seen_in_a_while.single", {
|
||||
usernames: ['<a class="mention" href="/u/charlie">@charlie</a>'],
|
||||
time_ago: "1 year ago",
|
||||
})
|
||||
),
|
||||
"warning message has correct body"
|
||||
);
|
||||
});
|
||||
});
|
|
@ -17,4 +17,22 @@ class ComposerMessagesController < ApplicationController
|
|||
|
||||
render_json_dump(json, rest_serializer: true)
|
||||
end
|
||||
|
||||
def user_not_seen_in_a_while
|
||||
usernames = params.require(:usernames)
|
||||
users = ComposerMessagesFinder.user_not_seen_in_a_while(usernames)
|
||||
user_count = users.count
|
||||
warning_message = nil
|
||||
|
||||
if user_count > 0
|
||||
message_locale = if user_count == 1
|
||||
"education.user_not_seen_in_a_while.single"
|
||||
else
|
||||
"education.user_not_seen_in_a_while.multiple"
|
||||
end
|
||||
end
|
||||
|
||||
json = { user_count: user_count, usernames: users, time_ago: FreedomPatches::Rails4.time_ago_in_words(SiteSetting.pm_warn_user_last_seen_months_ago.month.ago, true, scope: :'datetime.distance_in_words_verbose') }
|
||||
render_json_dump(json)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2275,6 +2275,9 @@ en:
|
|||
body: "Right now this message is only being sent to yourself!"
|
||||
slow_mode:
|
||||
error: "This topic is in slow mode. You already posted recently; you can post again in %{timeLeft}."
|
||||
user_not_seen_in_a_while:
|
||||
single: "The person you are messaging, <b>%{usernames}</b>, hasn’t been seen here in a very long time – %{time_ago}. They may not receive your message. You may wish to seek out alternate methods of contacting %{usernames}."
|
||||
multiple: "The following people you are messaging: <b>%{usernames}</b>, haven’t been seen here in a very long time – %{time_ago}. They may not receive your message. You may wish to seek out alternate methods of contacting them."
|
||||
|
||||
admin_options_title: "Optional staff settings for this topic"
|
||||
|
||||
|
|
|
@ -2149,6 +2149,8 @@ en:
|
|||
|
||||
disable_avatar_education_message: "Disable education message for changing avatar."
|
||||
|
||||
pm_warn_user_last_seen_months_ago: "When creating a new PM warn users when target recepient has not been seen more than n months ago."
|
||||
|
||||
suppress_uncategorized_badge: "Don't show the badge for uncategorized topics in topic lists."
|
||||
|
||||
header_dropdown_category_count: "How many categories can be displayed in the header dropdown menu."
|
||||
|
|
|
@ -387,6 +387,7 @@ Discourse::Application.routes.draw do
|
|||
end
|
||||
get "session/scopes" => "session#scopes"
|
||||
get "composer_messages" => "composer_messages#index"
|
||||
get "composer_messages/user_not_seen_in_a_while" => "composer_messages#user_not_seen_in_a_while"
|
||||
|
||||
resources :static
|
||||
post "login" => "static#enter"
|
||||
|
|
|
@ -2272,6 +2272,7 @@ uncategorized:
|
|||
get_a_room_threshold: 3
|
||||
dominating_topic_minimum_percent: 20
|
||||
disable_avatar_education_message: false
|
||||
pm_warn_user_last_seen_months_ago: 24
|
||||
|
||||
global_notice:
|
||||
default: ""
|
||||
|
|
|
@ -212,6 +212,10 @@ class ComposerMessagesFinder
|
|||
}
|
||||
end
|
||||
|
||||
def self.user_not_seen_in_a_while(usernames)
|
||||
User.where(username_lower: usernames).where("last_seen_at < ?", SiteSetting.pm_warn_user_last_seen_months_ago.months.ago).pluck(:username).sort
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def educate_reply?(type)
|
||||
|
|
|
@ -501,4 +501,26 @@ RSpec.describe ComposerMessagesFinder do
|
|||
expect(edit_post_finder.find).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#user_not_seen_in_a_while' do
|
||||
fab!(:user_1) { Fabricate(:user, last_seen_at: 3.years.ago) }
|
||||
fab!(:user_2) { Fabricate(:user, last_seen_at: 2.years.ago) }
|
||||
fab!(:user_3) { Fabricate(:user, last_seen_at: 6.months.ago) }
|
||||
|
||||
before do
|
||||
SiteSetting.pm_warn_user_last_seen_months_ago = 24
|
||||
end
|
||||
|
||||
it 'returns users that have not been seen recently' do
|
||||
users = ComposerMessagesFinder.user_not_seen_in_a_while([user_1.username, user_2.username, user_3.username])
|
||||
expect(users).to contain_exactly(user_1.username, user_2.username)
|
||||
end
|
||||
|
||||
it 'accounts for pm_warn_user_last_seen_months_ago site setting' do
|
||||
SiteSetting.pm_warn_user_last_seen_months_ago = 30
|
||||
users = ComposerMessagesFinder.user_not_seen_in_a_while([user_1.username, user_2.username, user_3.username])
|
||||
expect(users).to contain_exactly(user_1.username)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -30,4 +30,45 @@ RSpec.describe ComposerMessagesController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#user_not_seen_in_a_while' do
|
||||
fab!(:user_1) { Fabricate(:user, last_seen_at: 3.years.ago) }
|
||||
fab!(:user_2) { Fabricate(:user, last_seen_at: 2.years.ago) }
|
||||
fab!(:user_3) { Fabricate(:user, last_seen_at: 6.months.ago) }
|
||||
|
||||
it 'requires you to be logged in' do
|
||||
get '/composer_messages/user_not_seen_in_a_while.json', params: { usernames: [user_1.username, user_2.username, user_3.username] }
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
|
||||
context 'when logged in' do
|
||||
let!(:user) { sign_in(Fabricate(:user)) }
|
||||
|
||||
before do
|
||||
SiteSetting.pm_warn_user_last_seen_months_ago = 24
|
||||
end
|
||||
|
||||
it 'requires usernames parameter to be present' do
|
||||
get '/composer_messages/user_not_seen_in_a_while.json'
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
|
||||
it 'returns users that have not been seen recently' do
|
||||
get '/composer_messages/user_not_seen_in_a_while.json', params: { usernames: [user_1.username, user_2.username, user_3.username] }
|
||||
expect(response.status).to eq(200)
|
||||
json = response.parsed_body
|
||||
expect(json["user_count"]).to eq(2)
|
||||
expect(json["usernames"]).to contain_exactly(user_1.username, user_2.username)
|
||||
end
|
||||
|
||||
it 'accounts for pm_warn_user_last_seen_months_ago site setting' do
|
||||
SiteSetting.pm_warn_user_last_seen_months_ago = 30
|
||||
get '/composer_messages/user_not_seen_in_a_while.json', params: { usernames: [user_1.username, user_2.username, user_3.username] }
|
||||
expect(response.status).to eq(200)
|
||||
json = response.parsed_body
|
||||
expect(json["user_count"]).to eq(1)
|
||||
expect(json["usernames"]).to contain_exactly(user_1.username)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue