FEATURE: New and Unread messages for user personal messages. (#13603)
* FEATURE: New and Unread messages for user personal messages. Co-authored-by: awesomerobot <kris.aubuchon@discourse.org>
This commit is contained in:
parent
fe3e18f981
commit
016efeadf6
|
@ -154,10 +154,14 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||||
showCategoryChooser: not("model.isPrivateMessage"),
|
showCategoryChooser: not("model.isPrivateMessage"),
|
||||||
|
|
||||||
gotoInbox(name) {
|
gotoInbox(name) {
|
||||||
let url = userPath(this.get("currentUser.username_lower") + "/messages");
|
let url = userPath(`${this.get("currentUser.username_lower")}/messages`);
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
url = url + "/group/" + name;
|
url = `${url}/group/${name}`;
|
||||||
|
} else {
|
||||||
|
url = `${url}/personal`;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscourseURL.routeTo(url);
|
DiscourseURL.routeTo(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@ import { action } from "@ember/object";
|
||||||
import { alias, and, equal } from "@ember/object/computed";
|
import { alias, and, equal } from "@ember/object/computed";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import { VIEW_NAME_WARNINGS } from "discourse/routes/user-private-messages-warnings";
|
import { VIEW_NAME_WARNINGS } from "discourse/routes/user-private-messages-warnings";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
export const PERSONAL_INBOX = "__personal_inbox__";
|
||||||
|
const ALL_INBOX = "__all_inbox__";
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
user: controller(),
|
user: controller(),
|
||||||
|
@ -10,19 +14,101 @@ export default Controller.extend({
|
||||||
pmView: false,
|
pmView: false,
|
||||||
viewingSelf: alias("user.viewingSelf"),
|
viewingSelf: alias("user.viewingSelf"),
|
||||||
isGroup: equal("pmView", "groups"),
|
isGroup: equal("pmView", "groups"),
|
||||||
|
group: null,
|
||||||
|
groupFilter: alias("group.name"),
|
||||||
currentPath: alias("router._router.currentPath"),
|
currentPath: alias("router._router.currentPath"),
|
||||||
pmTaggingEnabled: alias("site.can_tag_pms"),
|
pmTaggingEnabled: alias("site.can_tag_pms"),
|
||||||
tagId: null,
|
tagId: null,
|
||||||
|
|
||||||
showNewPM: and("user.viewingSelf", "currentUser.can_send_private_messages"),
|
showNewPM: and("user.viewingSelf", "currentUser.can_send_private_messages"),
|
||||||
|
|
||||||
|
@discourseComputed("inboxes", "isAllInbox")
|
||||||
|
displayGlobalFilters(inboxes, isAllInbox) {
|
||||||
|
if (inboxes.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (inboxes.length && isAllInbox) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("inboxes")
|
||||||
|
sectionClass(inboxes) {
|
||||||
|
const defaultClass = "user-secondary-navigation user-messages";
|
||||||
|
|
||||||
|
return inboxes.length
|
||||||
|
? `${defaultClass} user-messages-inboxes`
|
||||||
|
: defaultClass;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("pmView")
|
||||||
|
isPersonalInbox(pmView) {
|
||||||
|
return pmView && pmView.startsWith("personal");
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("isPersonalInbox", "group.name")
|
||||||
|
isAllInbox(isPersonalInbox, groupName) {
|
||||||
|
return !this.isPersonalInbox && !groupName;
|
||||||
|
},
|
||||||
|
|
||||||
|
@discourseComputed("isPersonalInbox", "group.name")
|
||||||
|
selectedInbox(isPersonalInbox, groupName) {
|
||||||
|
if (groupName) {
|
||||||
|
return groupName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isPersonalInbox ? PERSONAL_INBOX : ALL_INBOX;
|
||||||
|
},
|
||||||
|
|
||||||
@discourseComputed("viewingSelf", "pmView", "currentUser.admin")
|
@discourseComputed("viewingSelf", "pmView", "currentUser.admin")
|
||||||
showWarningsWarning(viewingSelf, pmView, isAdmin) {
|
showWarningsWarning(viewingSelf, pmView, isAdmin) {
|
||||||
return pmView === VIEW_NAME_WARNINGS && !viewingSelf && !isAdmin;
|
return pmView === VIEW_NAME_WARNINGS && !viewingSelf && !isAdmin;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@discourseComputed("model.groups")
|
||||||
|
inboxes(groups) {
|
||||||
|
const groupsWithMessages = groups?.filter((group) => {
|
||||||
|
return group.has_messages;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!groupsWithMessages || groupsWithMessages.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const inboxes = [];
|
||||||
|
|
||||||
|
inboxes.push({
|
||||||
|
id: ALL_INBOX,
|
||||||
|
name: I18n.t("user.messages.all"),
|
||||||
|
});
|
||||||
|
|
||||||
|
inboxes.push({
|
||||||
|
id: PERSONAL_INBOX,
|
||||||
|
name: I18n.t("user.messages.personal"),
|
||||||
|
icon: "envelope",
|
||||||
|
});
|
||||||
|
|
||||||
|
groupsWithMessages.forEach((group) => {
|
||||||
|
inboxes.push({ id: group.name, name: group.name, icon: "users" });
|
||||||
|
});
|
||||||
|
|
||||||
|
return inboxes;
|
||||||
|
},
|
||||||
|
|
||||||
@action
|
@action
|
||||||
changeGroupNotificationLevel(notificationLevel) {
|
changeGroupNotificationLevel(notificationLevel) {
|
||||||
this.group.setNotification(notificationLevel, this.get("user.model.id"));
|
this.group.setNotification(notificationLevel, this.get("user.model.id"));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateInbox(inbox) {
|
||||||
|
if (inbox === ALL_INBOX) {
|
||||||
|
this.transitionToRoute("userPrivateMessages.index");
|
||||||
|
} else if (inbox === PERSONAL_INBOX) {
|
||||||
|
this.transitionToRoute("userPrivateMessages.personal");
|
||||||
|
} else {
|
||||||
|
this.transitionToRoute("userPrivateMessages.group", inbox);
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export function findOrResetCachedTopicList(session, filter) {
|
export function findOrResetCachedTopicList(session, filter) {
|
||||||
const lastTopicList = session.get("topicList");
|
const lastTopicList = session.get("topicList");
|
||||||
|
|
||||||
if (lastTopicList && lastTopicList.filter === filter) {
|
if (lastTopicList && lastTopicList.filter === filter) {
|
||||||
return lastTopicList;
|
return lastTopicList;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -140,11 +140,20 @@ export default function () {
|
||||||
"userPrivateMessages",
|
"userPrivateMessages",
|
||||||
{ path: "/messages", resetNamespace: true },
|
{ path: "/messages", resetNamespace: true },
|
||||||
function () {
|
function () {
|
||||||
this.route("sent");
|
this.route("new");
|
||||||
|
this.route("unread");
|
||||||
this.route("archive");
|
this.route("archive");
|
||||||
|
this.route("sent");
|
||||||
|
this.route("personal");
|
||||||
|
this.route("personalSent", { path: "personal/sent" });
|
||||||
|
this.route("personalNew", { path: "personal/new" });
|
||||||
|
this.route("personalUnread", { path: "personal/unread" });
|
||||||
|
this.route("personalArchive", { path: "personal/archive" });
|
||||||
this.route("warnings");
|
this.route("warnings");
|
||||||
this.route("group", { path: "group/:name" });
|
this.route("group", { path: "group/:name" });
|
||||||
this.route("groupArchive", { path: "group/:name/archive" });
|
this.route("groupArchive", { path: "group/:name/archive" });
|
||||||
|
this.route("groupNew", { path: "group/:name/new" });
|
||||||
|
this.route("groupUnread", { path: "group/:name/unread" });
|
||||||
this.route("tags");
|
this.route("tags");
|
||||||
this.route("tagsShow", { path: "tags/:id" });
|
this.route("tagsShow", { path: "tags/:id" });
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
import I18n from "I18n";
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
import { findOrResetCachedTopicList } from "discourse/lib/cached-topic-list";
|
||||||
|
|
||||||
|
export default (viewName, channel) => {
|
||||||
|
return createPMRoute("groups", "private-messages-groups").extend({
|
||||||
|
groupName: null,
|
||||||
|
|
||||||
|
titleToken() {
|
||||||
|
const groupName = this.groupName;
|
||||||
|
|
||||||
|
if (groupName) {
|
||||||
|
let title = groupName.capitalize();
|
||||||
|
|
||||||
|
if (viewName !== "index") {
|
||||||
|
title = `${title} ${I18n.t("user.messages." + viewName)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [title, I18n.t(`user.private_messages`)];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
model(params) {
|
||||||
|
const username = this.modelFor("user").get("username_lower");
|
||||||
|
let filter = `topics/private-messages-group/${username}/${params.name}`;
|
||||||
|
|
||||||
|
if (viewName !== "index") {
|
||||||
|
filter = `${filter}/${viewName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastTopicList = findOrResetCachedTopicList(this.session, filter);
|
||||||
|
|
||||||
|
return lastTopicList
|
||||||
|
? lastTopicList
|
||||||
|
: this.store.findFiltered("topicList", { filter });
|
||||||
|
},
|
||||||
|
|
||||||
|
afterModel(model) {
|
||||||
|
const filters = model.get("filter").split("/");
|
||||||
|
let groupName;
|
||||||
|
|
||||||
|
if (viewName !== "index") {
|
||||||
|
groupName = filters[filters.length - 2];
|
||||||
|
} else {
|
||||||
|
groupName = filters.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const group = this.modelFor("user")
|
||||||
|
.get("groups")
|
||||||
|
.filterBy("name", groupName)[0];
|
||||||
|
|
||||||
|
this.setProperties({ groupName: groupName, group });
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController() {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
this.controllerFor("user-private-messages").set("group", this.group);
|
||||||
|
|
||||||
|
if (channel) {
|
||||||
|
this.controllerFor("user-topics-list").subscribe(
|
||||||
|
`/private-messages/group/${this.get(
|
||||||
|
"groupName"
|
||||||
|
).toLowerCase()}/${channel}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
|
@ -23,7 +23,9 @@ export default (viewName, path, channel) => {
|
||||||
model() {
|
model() {
|
||||||
const filter =
|
const filter =
|
||||||
"topics/" + path + "/" + this.modelFor("user").get("username_lower");
|
"topics/" + path + "/" + this.modelFor("user").get("username_lower");
|
||||||
|
|
||||||
const lastTopicList = findOrResetCachedTopicList(this.session, filter);
|
const lastTopicList = findOrResetCachedTopicList(this.session, filter);
|
||||||
|
|
||||||
return lastTopicList
|
return lastTopicList
|
||||||
? lastTopicList
|
? lastTopicList
|
||||||
: this.store.findFiltered("topicList", { filter });
|
: this.store.findFiltered("topicList", { filter });
|
||||||
|
@ -49,6 +51,7 @@ export default (viewName, path, channel) => {
|
||||||
this.controllerFor("user-private-messages").setProperties({
|
this.controllerFor("user-private-messages").setProperties({
|
||||||
archive: false,
|
archive: false,
|
||||||
pmView: viewName,
|
pmView: viewName,
|
||||||
|
group: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.searchService.set("contextType", "private_messages");
|
this.searchService.set("contextType", "private_messages");
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
import createPMRoute from "discourse/routes/build-private-messages-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute("archive", "private-messages-archive", "archive");
|
export default createPMRoute(
|
||||||
|
"archive",
|
||||||
|
"private-messages-all-archive",
|
||||||
|
"archive"
|
||||||
|
);
|
||||||
|
|
|
@ -1,48 +1,3 @@
|
||||||
import I18n from "I18n";
|
import createPMRoute from "discourse/routes/build-private-messages-group-route";
|
||||||
import createPMRoute from "discourse/routes/build-private-messages-route";
|
|
||||||
import { findOrResetCachedTopicList } from "discourse/lib/cached-topic-list";
|
|
||||||
|
|
||||||
export default createPMRoute("groups", "private-messages-groups").extend({
|
export default createPMRoute("archive", "archive");
|
||||||
groupName: null,
|
|
||||||
|
|
||||||
titleToken() {
|
|
||||||
const groupName = this.groupName;
|
|
||||||
|
|
||||||
if (groupName) {
|
|
||||||
return [
|
|
||||||
`${groupName.capitalize()} ${I18n.t("user.messages.archive")}`,
|
|
||||||
I18n.t("user.private_messages"),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
model(params) {
|
|
||||||
const username = this.modelFor("user").get("username_lower");
|
|
||||||
const filter = `topics/private-messages-group/${username}/${params.name}/archive`;
|
|
||||||
const lastTopicList = findOrResetCachedTopicList(this.session, filter);
|
|
||||||
return lastTopicList
|
|
||||||
? lastTopicList
|
|
||||||
: this.store.findFiltered("topicList", { filter });
|
|
||||||
},
|
|
||||||
|
|
||||||
afterModel(model) {
|
|
||||||
const split = model.get("filter").split("/");
|
|
||||||
const groupName = split[split.length - 2];
|
|
||||||
this.set("groupName", groupName);
|
|
||||||
const group = this.modelFor("user")
|
|
||||||
.get("groups")
|
|
||||||
.filterBy("name", groupName)[0];
|
|
||||||
this.controllerFor("user-private-messages").set("group", group);
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
this._super.apply(this, arguments);
|
|
||||||
const split = model.get("filter").split("/");
|
|
||||||
const group = split[split.length - 2];
|
|
||||||
this.controllerFor("user-private-messages").set("groupFilter", group);
|
|
||||||
this.controllerFor("user-private-messages").set("archive", true);
|
|
||||||
this.controllerFor("user-topics-list").subscribe(
|
|
||||||
`/private-messages/group/${group}/archive`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-group-route";
|
||||||
|
|
||||||
|
export default createPMRoute("new", null /* no message bus notifications */);
|
|
@ -0,0 +1,3 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-group-route";
|
||||||
|
|
||||||
|
export default createPMRoute("unread", null /* no message bus notifications */);
|
|
@ -1,42 +1,3 @@
|
||||||
import I18n from "I18n";
|
import createPMRoute from "discourse/routes/build-private-messages-group-route";
|
||||||
import createPMRoute from "discourse/routes/build-private-messages-route";
|
|
||||||
import { findOrResetCachedTopicList } from "discourse/lib/cached-topic-list";
|
|
||||||
|
|
||||||
export default createPMRoute("groups", "private-messages-groups").extend({
|
export default createPMRoute("index", "inbox");
|
||||||
groupName: null,
|
|
||||||
|
|
||||||
titleToken() {
|
|
||||||
const groupName = this.groupName;
|
|
||||||
if (groupName) {
|
|
||||||
return [groupName.capitalize(), I18n.t("user.private_messages")];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
model(params) {
|
|
||||||
const username = this.modelFor("user").get("username_lower");
|
|
||||||
const filter = `topics/private-messages-group/${username}/${params.name}`;
|
|
||||||
const lastTopicList = findOrResetCachedTopicList(this.session, filter);
|
|
||||||
return lastTopicList
|
|
||||||
? lastTopicList
|
|
||||||
: this.store.findFiltered("topicList", { filter });
|
|
||||||
},
|
|
||||||
|
|
||||||
afterModel(model) {
|
|
||||||
const groupName = model.get("filter").split("/").pop();
|
|
||||||
this.set("groupName", groupName);
|
|
||||||
const group = this.modelFor("user")
|
|
||||||
.get("groups")
|
|
||||||
.filterBy("name", groupName)[0];
|
|
||||||
this.controllerFor("user-private-messages").set("group", group);
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
this._super.apply(this, arguments);
|
|
||||||
const group = model.get("filter").split("/").pop();
|
|
||||||
this.controllerFor("user-private-messages").set("groupFilter", group);
|
|
||||||
this.controllerFor("user-private-messages").set("archive", false);
|
|
||||||
this.controllerFor("user-topics-list").subscribe(
|
|
||||||
`/private-messages/group/${group}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import createPMRoute from "discourse/routes/build-private-messages-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute("index", "private-messages", "inbox");
|
export default createPMRoute("index", "private-messages-all", "inbox");
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
|
export default createPMRoute(
|
||||||
|
"new",
|
||||||
|
"private-messages-all-new",
|
||||||
|
null /* no message bus notifications */
|
||||||
|
);
|
|
@ -0,0 +1,3 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
|
export default createPMRoute("personal", "private-messages-archive", "archive");
|
|
@ -0,0 +1,7 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
|
export default createPMRoute(
|
||||||
|
"personal",
|
||||||
|
"private-messages-new",
|
||||||
|
null /* no message bus notifications */
|
||||||
|
);
|
|
@ -0,0 +1,3 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
|
export default createPMRoute("personal", "private-messages-sent", "sent");
|
|
@ -0,0 +1,7 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
|
export default createPMRoute(
|
||||||
|
"personal",
|
||||||
|
"private-messages-unread",
|
||||||
|
null /* no message bus notifications */
|
||||||
|
);
|
|
@ -0,0 +1,3 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
|
export default createPMRoute("personal", "private-messages", "inbox");
|
|
@ -1,3 +1,7 @@
|
||||||
import createPMRoute from "discourse/routes/build-private-messages-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute("sent", "private-messages-sent", "sent");
|
export default createPMRoute(
|
||||||
|
"sent",
|
||||||
|
"private-messages-all-sent",
|
||||||
|
null /* no message bus notifications */
|
||||||
|
);
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
|
export default createPMRoute(
|
||||||
|
"unread",
|
||||||
|
"private-messages-all-unread",
|
||||||
|
null /* no message bus notifications */
|
||||||
|
);
|
|
@ -12,9 +12,11 @@ export default DiscourseRoute.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController(controller, user) {
|
setupController(controller, user) {
|
||||||
const composerController = this.controllerFor("composer");
|
|
||||||
controller.set("model", user);
|
controller.set("model", user);
|
||||||
|
|
||||||
if (this.currentUser) {
|
if (this.currentUser) {
|
||||||
|
const composerController = this.controllerFor("composer");
|
||||||
|
|
||||||
Draft.get("new_private_message").then((data) => {
|
Draft.get("new_private_message").then((data) => {
|
||||||
if (data.draft) {
|
if (data.draft) {
|
||||||
composerController.open({
|
composerController.open({
|
||||||
|
|
|
@ -1,14 +1,29 @@
|
||||||
{{#d-section class="user-secondary-navigation" pageClass="user-messages"}}
|
{{#d-section class=sectionClass pageClass="user-messages"}}
|
||||||
{{#unless site.mobileView}}
|
{{#if inboxes.length}}
|
||||||
{{#if showNewPM}}
|
<div class="inboxes-controls">
|
||||||
{{d-button class="btn-primary new-private-message" action=(route-action "composePrivateMessage") icon="envelope" label="user.new_private_message"}}
|
{{combo-box
|
||||||
|
content=inboxes
|
||||||
|
classNames="user-messages-inboxes-drop"
|
||||||
|
value=selectedInbox
|
||||||
|
onChange=(action "updateInbox")
|
||||||
|
options=(hash
|
||||||
|
filterable=true
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
{{#if (and group site.mobileView)}}
|
||||||
|
{{group-notifications-button
|
||||||
|
value=group.group_user.notification_level
|
||||||
|
onChange=(action "changeGroupNotificationLevel")
|
||||||
|
}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/unless}}
|
|
||||||
|
|
||||||
{{#mobile-nav class="messages-nav" desktopClass="nav-stacked action-list"}}
|
{{#mobile-nav class="messages-nav" desktopClass="nav-stacked action-list"}}
|
||||||
|
{{#if isAllInbox}}
|
||||||
<li class="noGlyph">
|
<li class="noGlyph">
|
||||||
{{#link-to "userPrivateMessages.index" model}}
|
{{#link-to "userPrivateMessages.index" model}}
|
||||||
{{i18n "user.messages.inbox"}}
|
{{i18n "user.messages.latest"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
<li class="noGlyph">
|
<li class="noGlyph">
|
||||||
|
@ -16,34 +31,81 @@
|
||||||
{{i18n "user.messages.sent"}}
|
{{i18n "user.messages.sent"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.new" model}}
|
||||||
|
{{i18n "user.messages.new"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.unread" model}}
|
||||||
|
{{i18n "user.messages.unread"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
<li class="noGlyph">
|
<li class="noGlyph">
|
||||||
{{#link-to "userPrivateMessages.archive" model}}
|
{{#link-to "userPrivateMessages.archive" model}}
|
||||||
{{i18n "user.messages.archive"}}
|
{{i18n "user.messages.archive"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
{{plugin-outlet name="user-messages-nav" connectorTagName="li" args=(hash model=model)}}
|
{{/if}}
|
||||||
{{#each model.groups as |group|}}
|
|
||||||
{{#if group.has_messages}}
|
{{#if group}}
|
||||||
<li>
|
<li class="noGlyph">
|
||||||
{{#link-to "userPrivateMessages.group" group.name}}
|
{{#link-to "userPrivateMessages.group" group.name}}
|
||||||
{{d-icon "users"}}
|
{{i18n "user.messages.latest"}}
|
||||||
{{capitalize-string group.name}}
|
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
<li class="archive">
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.groupNew" group.name}}
|
||||||
|
{{i18n "user.messages.new"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.groupUnread" group.name}}
|
||||||
|
{{i18n "user.messages.unread"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li class="noGlyph">
|
||||||
{{#link-to "userPrivateMessages.groupArchive" group.name}}
|
{{#link-to "userPrivateMessages.groupArchive" group.name}}
|
||||||
{{i18n "user.messages.archive"}}
|
{{i18n "user.messages.archive"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
{{#if pmTaggingEnabled}}
|
{{#if isPersonalInbox}}
|
||||||
<li class="noGlyph">
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.personal" model}}
|
||||||
|
{{i18n "user.messages.latest"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.personalSent" model}}
|
||||||
|
{{i18n "user.messages.sent"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.personalNew" model}}
|
||||||
|
{{i18n "user.messages.new"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.personalUnread" model}}
|
||||||
|
{{i18n "user.messages.unread"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li class="noGlyph">
|
||||||
|
{{#link-to "userPrivateMessages.personalArchive" model}}
|
||||||
|
{{i18n "user.messages.archive"}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if displayGlobalFilters}}
|
||||||
|
{{#if pmTaggingEnabled}}
|
||||||
|
<li class="noGlyph tags">
|
||||||
{{#link-to "userPrivateMessages.tags" model}}
|
{{#link-to "userPrivateMessages.tags" model}}
|
||||||
{{i18n "user.messages.tags"}}
|
{{i18n "user.messages.tags"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
|
||||||
{{#if tagId}}
|
{{#if tagId}}
|
||||||
<li class="archive">
|
<li class="archive">
|
||||||
{{#link-to "userPrivateMessages.tagsShow" tagId}}
|
{{#link-to "userPrivateMessages.tagsShow" tagId}}
|
||||||
|
@ -51,31 +113,36 @@
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{plugin-outlet name="user-messages-nav" connectorTagName="li" args=(hash model=model)}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/mobile-nav}}
|
{{/mobile-nav}}
|
||||||
{{/d-section}}
|
{{/d-section}}
|
||||||
|
|
||||||
<section class="user-content">
|
{{#if (and site.mobileView showNewPM)}}
|
||||||
<div class="list-actions">
|
{{d-button class="btn-primary new-private-message" action=(route-action "composePrivateMessage") icon="envelope" label="user.new_private_message"}}
|
||||||
{{#if site.mobileView}}
|
{{/if}}
|
||||||
{{#if showNewPM}}
|
|
||||||
{{d-button
|
|
||||||
class="btn-primary new-private-message"
|
|
||||||
action=(route-action "composePrivateMessage")
|
|
||||||
icon="envelope"
|
|
||||||
label="user.new_private_message"}}
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if isGroup}}
|
{{#unless site.mobileView}}
|
||||||
|
<section class="user-additional-controls">
|
||||||
|
{{#if group}}
|
||||||
{{group-notifications-button
|
{{group-notifications-button
|
||||||
value=group.group_user.notification_level
|
value=group.group_user.notification_level
|
||||||
onChange=(action "changeGroupNotificationLevel")
|
onChange=(action "changeGroupNotificationLevel")
|
||||||
}}
|
}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
{{#if showNewPM}}
|
||||||
|
{{d-button class="btn-primary new-private-message" action=(route-action "composePrivateMessage") icon="envelope" label="user.new_private_message"}}
|
||||||
|
{{/if}}
|
||||||
|
</section>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
|
<section class="user-content">
|
||||||
{{#if showWarningsWarning}}
|
{{#if showWarningsWarning}}
|
||||||
<div class="alert alert-info">{{html-safe (i18n "admin.user.warnings_list_warning")}}</div>
|
<div class="alert alert-info">{{html-safe (i18n "admin.user.warnings_list_warning")}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
import {
|
||||||
|
acceptance,
|
||||||
|
count,
|
||||||
|
exists,
|
||||||
|
} from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import { visit } from "@ember/test-helpers";
|
||||||
|
import { test } from "qunit";
|
||||||
|
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||||
|
import { PERSONAL_INBOX } from "discourse/controllers/user-private-messages";
|
||||||
|
|
||||||
|
acceptance(
|
||||||
|
"User Private Messages - user with no group messages",
|
||||||
|
function (needs) {
|
||||||
|
needs.user();
|
||||||
|
|
||||||
|
needs.site({
|
||||||
|
can_tag_pms: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
test("viewing messages", async function (assert) {
|
||||||
|
await visit("/u/eviltrout/messages");
|
||||||
|
|
||||||
|
assert.equal(count(".topic-list-item"), 1, "displays the topic list");
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!exists(".user-messages-inboxes-drop"),
|
||||||
|
"does not display inboxes dropdown"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(exists(".messages-nav .tags"), "displays the tags filter");
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!exists(".group-notifications-button"),
|
||||||
|
"displays the group notifications button"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
acceptance(
|
||||||
|
"User Private Messages - user with group messages",
|
||||||
|
function (needs) {
|
||||||
|
needs.user();
|
||||||
|
|
||||||
|
needs.site({
|
||||||
|
can_tag_pms: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
needs.pretender((server, helper) => {
|
||||||
|
server.get("/topics/private-messages-all/:username.json", () => {
|
||||||
|
return helper.response({
|
||||||
|
topic_list: {
|
||||||
|
topics: [
|
||||||
|
{ id: 1, posters: [] },
|
||||||
|
{ id: 2, posters: [] },
|
||||||
|
{ id: 3, posters: [] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get(
|
||||||
|
"/topics/private-messages-group/:username/:group_name.json",
|
||||||
|
() => {
|
||||||
|
return helper.response({
|
||||||
|
topic_list: {
|
||||||
|
topics: [
|
||||||
|
{ id: 1, posters: [] },
|
||||||
|
{ id: 2, posters: [] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("viewing messages", async function (assert) {
|
||||||
|
await visit("/u/charlie/messages");
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
count(".topic-list-item"),
|
||||||
|
3,
|
||||||
|
"displays the right topic list"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
exists(".user-messages-inboxes-drop"),
|
||||||
|
"displays inboxes dropdown"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(exists(".messages-nav .tags"), "displays the tags filter");
|
||||||
|
|
||||||
|
await selectKit(".user-messages-inboxes-drop").expand();
|
||||||
|
await selectKit(".user-messages-inboxes-drop").selectRowByValue(
|
||||||
|
PERSONAL_INBOX
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
count(".topic-list-item"),
|
||||||
|
1,
|
||||||
|
"displays the right topic list"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!exists(".messages-nav .tags"),
|
||||||
|
"does not display the tags filter"
|
||||||
|
);
|
||||||
|
|
||||||
|
await selectKit(".user-messages-inboxes-drop").expand();
|
||||||
|
await selectKit(".user-messages-inboxes-drop").selectRowByValue(
|
||||||
|
"awesome_group"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
count(".topic-list-item"),
|
||||||
|
2,
|
||||||
|
"displays the right topic list"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
exists(".group-notifications-button"),
|
||||||
|
"displays the group notifications button"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!exists(".messages-nav .tags"),
|
||||||
|
"does not display the tags filter"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
|
@ -38,11 +38,6 @@ acceptance("User Routes", function (needs) {
|
||||||
assert.ok($("body.user-invites-page").length, "has the body class");
|
assert.ok($("body.user-invites-page").length, "has the body class");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Messages", async function (assert) {
|
|
||||||
await visit("/u/eviltrout/messages");
|
|
||||||
assert.ok($("body.user-messages-page").length, "has the body class");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Notifications", async function (assert) {
|
test("Notifications", async function (assert) {
|
||||||
await visit("/u/eviltrout/notifications");
|
await visit("/u/eviltrout/notifications");
|
||||||
assert.ok($("body.user-notifications-page").length, "has the body class");
|
assert.ok($("body.user-notifications-page").length, "has the body class");
|
||||||
|
|
|
@ -2648,6 +2648,33 @@ export default {
|
||||||
default_notification_level: 3,
|
default_notification_level: 3,
|
||||||
membership_request_template: null,
|
membership_request_template: null,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 14,
|
||||||
|
automatic: false,
|
||||||
|
name: "awesome_group",
|
||||||
|
display_name: "awesome_group",
|
||||||
|
user_count: 3,
|
||||||
|
mentionable_level: 0,
|
||||||
|
messageable_level: 0,
|
||||||
|
visibility_level: 0,
|
||||||
|
automatic_membership_email_domains: null,
|
||||||
|
primary_group: false,
|
||||||
|
title: null,
|
||||||
|
grant_trust_level: null,
|
||||||
|
incoming_email: null,
|
||||||
|
has_messages: true,
|
||||||
|
flair_url: null,
|
||||||
|
flair_bg_color: null,
|
||||||
|
flair_color: null,
|
||||||
|
bio_raw: null,
|
||||||
|
bio_cooked: null,
|
||||||
|
public_admission: false,
|
||||||
|
public_exit: false,
|
||||||
|
allow_membership_requests: false,
|
||||||
|
full_name: null,
|
||||||
|
default_notification_level: 3,
|
||||||
|
membership_request_template: null,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
group_users: [
|
group_users: [
|
||||||
{ group_id: 10, user_id: 5, notification_level: 3 },
|
{ group_id: 10, user_id: 5, notification_level: 3 },
|
||||||
|
|
|
@ -207,12 +207,14 @@ export function applyDefaultHandlers(pretender) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pretender.get("/topics/private-messages/eviltrout.json", () => {
|
[
|
||||||
|
"/topics/private-messages-all/:username.json",
|
||||||
|
"/topics/private-messages/:username.json",
|
||||||
|
"/topics/private-messages-warnings/eviltrout.json",
|
||||||
|
].forEach((url) => {
|
||||||
|
pretender.get(url, () => {
|
||||||
return response(fixturesByUrl["/topics/private-messages/eviltrout.json"]);
|
return response(fixturesByUrl["/topics/private-messages/eviltrout.json"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
pretender.get("/topics/private-messages-warnings/eviltrout.json", () => {
|
|
||||||
return response(fixturesByUrl["/topics/private-messages/eviltrout.json"]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
pretender.get("/topics/feature_stats.json", () => {
|
pretender.get("/topics/feature_stats.json", () => {
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
.user-content {
|
.user-content {
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-additional-controls + .user-content,
|
.user-additional-controls + .user-content,
|
||||||
.user-secondary-navigation + .user-content {
|
.user-secondary-navigation + .user-content {
|
||||||
grid-column-start: 2;
|
grid-column-start: 2;
|
||||||
|
|
|
@ -66,12 +66,10 @@
|
||||||
.nav-stacked {
|
.nav-stacked {
|
||||||
@extend %nav;
|
@extend %nav;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: hidden;
|
|
||||||
background: var(--primary-low);
|
background: var(--primary-low);
|
||||||
|
|
||||||
li {
|
li {
|
||||||
border-bottom: 1px solid var(--primary-low);
|
border-bottom: 1px solid var(--primary-low);
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:last-of-type {
|
&:last-of-type {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
|
@ -89,6 +87,7 @@
|
||||||
line-height: $line-height-small;
|
line-height: $line-height-small;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
|
@include ellipsis;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: var(--secondary);
|
color: var(--secondary);
|
||||||
|
|
|
@ -6,10 +6,6 @@
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.show-mores {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-horizontal .control-group.category {
|
.form-horizontal .control-group.category {
|
||||||
|
@ -20,10 +16,20 @@
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-secondary-navigation {
|
.user-secondary-navigation {
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
|
|
||||||
|
.combo-box {
|
||||||
|
width: 100%;
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
margin-bottom: 0.875em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.nav-stacked {
|
.nav-stacked {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
|
@ -47,6 +53,42 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select-kit + .messages-nav {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inboxes-controls {
|
||||||
|
margin-bottom: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.user-messages {
|
||||||
|
--left-padding: 0.8em;
|
||||||
|
.user-messages-inboxes-drop {
|
||||||
|
padding: 0 1em 0 0;
|
||||||
|
|
||||||
|
.select-kit-header {
|
||||||
|
padding-left: var(--left-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-kit-selected-name {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-stacked {
|
||||||
|
a {
|
||||||
|
padding-left: calc(
|
||||||
|
var(--left-padding) - 1px
|
||||||
|
); // 1px accounts for border on select-kit elements above
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.user-additional-controls {
|
||||||
|
button {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-content {
|
.user-content {
|
||||||
|
@ -226,6 +268,20 @@ table.user-invite-list {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-messages-page {
|
||||||
|
.topic-list th {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-mores {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-messages {
|
||||||
|
margin-right: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
.user-preferences {
|
.user-preferences {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-left: 30px;
|
padding-left: 30px;
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
grid-template-rows: auto auto auto;
|
grid-template-rows: auto auto auto;
|
||||||
grid-row-gap: 20px;
|
grid-gap: 16px;
|
||||||
grid-column-gap: 16px;
|
|
||||||
.user-primary-navigation {
|
.user-primary-navigation {
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
grid-row-start: 1;
|
grid-row-start: 1;
|
||||||
|
@ -30,6 +29,71 @@
|
||||||
grid-row-start: 3;
|
grid-row-start: 3;
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specific to messages
|
||||||
|
|
||||||
|
.user-messages.user-messages-inboxes {
|
||||||
|
grid-row-start: 2;
|
||||||
|
grid-column-start: 1;
|
||||||
|
grid-column-end: 3;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
+ .user-additional-controls {
|
||||||
|
grid-row-start: 2;
|
||||||
|
grid-column-start: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inboxes-controls {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-messages-inboxes-drop {
|
||||||
|
padding: 0;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
.select-kit-header {
|
||||||
|
padding: 8px 10px;
|
||||||
|
|
||||||
|
.caret-icon {
|
||||||
|
color: var(--primary-medium);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.messages-nav {
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-column-end: 3;
|
||||||
|
grid-row-start: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-private-message {
|
||||||
|
grid-row-start: 1;
|
||||||
|
grid-column-start: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-notifications-button {
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
.select-kit-header {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.selected-name .name {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-messages-page {
|
||||||
|
.paginated-topics-list {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.show-mores {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-main {
|
.user-main {
|
||||||
|
@ -166,6 +230,10 @@
|
||||||
flex: 1 1 25%;
|
flex: 1 1 25%;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -223,6 +291,7 @@
|
||||||
|
|
||||||
.user-main .collapsed-info.about .details {
|
.user-main .collapsed-info.about .details {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin-bottom: 16px;
|
||||||
.user-profile-avatar {
|
.user-profile-avatar {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
|
@ -146,35 +146,27 @@ class ListController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.generate_message_route(action)
|
def self.generate_message_route(action)
|
||||||
case action
|
define_method action do
|
||||||
when :private_messages_tag
|
|
||||||
define_method("#{action}") do
|
|
||||||
raise Discourse::NotFound if !guardian.can_tag_pms?
|
|
||||||
message_route(action)
|
message_route(action)
|
||||||
end
|
end
|
||||||
when :private_messages_group, :private_messages_group_archive
|
|
||||||
define_method("#{action}") do
|
|
||||||
group = Group.find_by("LOWER(name) = ?", params[:group_name].downcase)
|
|
||||||
raise Discourse::NotFound if !group
|
|
||||||
raise Discourse::NotFound unless guardian.can_see_group_messages?(group)
|
|
||||||
|
|
||||||
message_route(action)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
define_method("#{action}") do
|
|
||||||
message_route(action)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def message_route(action)
|
def message_route(action)
|
||||||
target_user = fetch_user_from_params({ include_inactive: current_user.try(:staff?) }, [:user_stat, :user_option])
|
target_user = fetch_user_from_params({ include_inactive: current_user.try(:staff?) }, [:user_stat, :user_option])
|
||||||
|
|
||||||
case action
|
case action
|
||||||
|
when :private_messages_tag
|
||||||
|
raise Discourse::NotFound if !guardian.can_tag_pms?
|
||||||
when :private_messages_warnings
|
when :private_messages_warnings
|
||||||
guardian.ensure_can_see_warnings!(target_user)
|
guardian.ensure_can_see_warnings!(target_user)
|
||||||
|
when :private_messages_group, :private_messages_group_archive
|
||||||
|
group = Group.find_by("LOWER(name) = ?", params[:group_name].downcase)
|
||||||
|
raise Discourse::NotFound if !group
|
||||||
|
raise Discourse::NotFound unless guardian.can_see_group_messages?(group)
|
||||||
else
|
else
|
||||||
guardian.ensure_can_see_private_messages!(target_user.id)
|
guardian.ensure_can_see_private_messages!(target_user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
list_opts = build_topic_list_options
|
list_opts = build_topic_list_options
|
||||||
list = generate_list_for(action.to_s, target_user, list_opts)
|
list = generate_list_for(action.to_s, target_user, list_opts)
|
||||||
url_prefix = "topics"
|
url_prefix = "topics"
|
||||||
|
@ -187,11 +179,19 @@ class ListController < ApplicationController
|
||||||
private_messages
|
private_messages
|
||||||
private_messages_sent
|
private_messages_sent
|
||||||
private_messages_unread
|
private_messages_unread
|
||||||
|
private_messages_new
|
||||||
private_messages_archive
|
private_messages_archive
|
||||||
private_messages_group
|
private_messages_group
|
||||||
|
private_messages_group_new
|
||||||
|
private_messages_group_unread
|
||||||
private_messages_group_archive
|
private_messages_group_archive
|
||||||
private_messages_tag
|
|
||||||
private_messages_warnings
|
private_messages_warnings
|
||||||
|
private_messages_all
|
||||||
|
private_messages_all_sent
|
||||||
|
private_messages_all_unread
|
||||||
|
private_messages_all_new
|
||||||
|
private_messages_all_archive
|
||||||
|
private_messages_tag
|
||||||
}.each do |action|
|
}.each do |action|
|
||||||
generate_message_route(action)
|
generate_message_route(action)
|
||||||
end
|
end
|
||||||
|
|
|
@ -136,16 +136,16 @@ class Tag < ActiveRecord::Base
|
||||||
WHERE topic_tags.topic_id IN (
|
WHERE topic_tags.topic_id IN (
|
||||||
SELECT topic_id
|
SELECT topic_id
|
||||||
FROM topic_allowed_users
|
FROM topic_allowed_users
|
||||||
WHERE user_id = #{user_id}
|
WHERE user_id = #{user_id.to_i}
|
||||||
UNION
|
UNION
|
||||||
SELECT tg.topic_id
|
SELECT tg.topic_id
|
||||||
FROM topic_allowed_groups tg
|
FROM topic_allowed_groups tg
|
||||||
JOIN group_users gu ON gu.user_id = #{user_id}
|
JOIN group_users gu ON gu.user_id = #{user_id.to_i}
|
||||||
AND gu.group_id = tg.group_id
|
AND gu.group_id = tg.group_id
|
||||||
)
|
)
|
||||||
GROUP BY tags.name
|
GROUP BY tags.name
|
||||||
ORDER BY count DESC
|
ORDER BY count DESC
|
||||||
LIMIT #{limit}
|
LIMIT #{limit.to_i}
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -545,8 +545,9 @@ class TopicTrackingState
|
||||||
group_user_ids = group.users.pluck(:id)
|
group_user_ids = group.users.pluck(:id)
|
||||||
next if group_user_ids.blank?
|
next if group_user_ids.blank?
|
||||||
group_channels = []
|
group_channels = []
|
||||||
group_channels << "/private-messages/group/#{group.name.downcase}"
|
channel_prefix = "/private-messages/group/#{group.name.downcase}"
|
||||||
group_channels << "#{group_channels.first}/archive" if group_archive
|
group_channels << "#{channel_prefix}/inbox"
|
||||||
|
group_channels << "#{channel_prefix}/archive" if group_archive
|
||||||
group_channels.each { |channel| channels[channel] = group_user_ids }
|
group_channels.each { |channel| channels[channel] = group_user_ids }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1172,9 +1172,13 @@ en:
|
||||||
rejected_posts: "rejected posts"
|
rejected_posts: "rejected posts"
|
||||||
|
|
||||||
messages:
|
messages:
|
||||||
all: "All"
|
all: "all inboxes"
|
||||||
inbox: "Inbox"
|
inbox: "Inbox"
|
||||||
|
personal: "Personal"
|
||||||
|
latest: "Latest"
|
||||||
sent: "Sent"
|
sent: "Sent"
|
||||||
|
unread: "Unread"
|
||||||
|
new: "New"
|
||||||
archive: "Archive"
|
archive: "Archive"
|
||||||
groups: "My Groups"
|
groups: "My Groups"
|
||||||
move_to_inbox: "Move to Inbox"
|
move_to_inbox: "Move to Inbox"
|
||||||
|
|
|
@ -447,9 +447,10 @@ Discourse::Application.routes.draw do
|
||||||
get "#{root_path}/:username/private-messages/:filter" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
|
get "#{root_path}/:username/private-messages/:filter" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
|
||||||
get "#{root_path}/:username/messages" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
|
get "#{root_path}/:username/messages" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
|
||||||
get "#{root_path}/:username/messages/:filter" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
|
get "#{root_path}/:username/messages/:filter" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
|
||||||
|
get "#{root_path}/:username/messages/personal" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
|
||||||
|
get "#{root_path}/:username/messages/personal/:filter" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
|
||||||
get "#{root_path}/:username/messages/group/:group_name" => "user_actions#private_messages", constraints: { username: RouteFormat.username, group_name: RouteFormat.username }
|
get "#{root_path}/:username/messages/group/:group_name" => "user_actions#private_messages", constraints: { username: RouteFormat.username, group_name: RouteFormat.username }
|
||||||
get "#{root_path}/:username/messages/group/:group_name/archive" => "user_actions#private_messages", constraints: { username: RouteFormat.username, group_name: RouteFormat.username }
|
get "#{root_path}/:username/messages/group/:group_name/:filter" => "user_actions#private_messages", constraints: { username: RouteFormat.username, group_name: RouteFormat.username }
|
||||||
get "#{root_path}/:username/messages/tags/:tag_id" => "user_actions#private_messages", constraints: StaffConstraint.new
|
|
||||||
get "#{root_path}/:username.json" => "users#show", constraints: { username: RouteFormat.username }, defaults: { format: :json }
|
get "#{root_path}/:username.json" => "users#show", constraints: { username: RouteFormat.username }, defaults: { format: :json }
|
||||||
get({ "#{root_path}/:username" => "users#show", constraints: { username: RouteFormat.username } }.merge(index == 1 ? { as: 'user' } : {}))
|
get({ "#{root_path}/:username" => "users#show", constraints: { username: RouteFormat.username } }.merge(index == 1 ? { as: 'user' } : {}))
|
||||||
put "#{root_path}/:username" => "users#update", constraints: { username: RouteFormat.username }, defaults: { format: :json }
|
put "#{root_path}/:username" => "users#update", constraints: { username: RouteFormat.username }, defaults: { format: :json }
|
||||||
|
@ -764,17 +765,25 @@ Discourse::Application.routes.draw do
|
||||||
|
|
||||||
scope "/topics", username: RouteFormat.username do
|
scope "/topics", username: RouteFormat.username do
|
||||||
get "created-by/:username" => "list#topics_by", as: "topics_by", defaults: { format: :json }
|
get "created-by/:username" => "list#topics_by", as: "topics_by", defaults: { format: :json }
|
||||||
|
get "private-messages-all/:username" => "list#private_messages_all", as: "topics_private_messages_all", defaults: { format: :json }
|
||||||
|
get "private-messages-all-sent/:username" => "list#private_messages_all_sent", as: "topics_private_messages_all_sent", defaults: { format: :json }
|
||||||
|
get "private-messages-all-new/:username" => "list#private_messages_all_new", as: "topics_private_messages_all_new", defaults: { format: :json }
|
||||||
|
get "private-messages-all-unread/:username" => "list#private_messages_all_unread", as: "topics_private_messages_all_unread", defaults: { format: :json }
|
||||||
|
get "private-messages-all-archive/:username" => "list#private_messages_all_archive", as: "topics_private_messages_all_archive", defaults: { format: :json }
|
||||||
get "private-messages/:username" => "list#private_messages", as: "topics_private_messages", defaults: { format: :json }
|
get "private-messages/:username" => "list#private_messages", as: "topics_private_messages", defaults: { format: :json }
|
||||||
get "private-messages-sent/:username" => "list#private_messages_sent", as: "topics_private_messages_sent", defaults: { format: :json }
|
get "private-messages-sent/:username" => "list#private_messages_sent", as: "topics_private_messages_sent", defaults: { format: :json }
|
||||||
get "private-messages-archive/:username" => "list#private_messages_archive", as: "topics_private_messages_archive", defaults: { format: :json }
|
get "private-messages-archive/:username" => "list#private_messages_archive", as: "topics_private_messages_archive", defaults: { format: :json }
|
||||||
get "private-messages-unread/:username" => "list#private_messages_unread", as: "topics_private_messages_unread", defaults: { format: :json }
|
get "private-messages-unread/:username" => "list#private_messages_unread", as: "topics_private_messages_unread", defaults: { format: :json }
|
||||||
get "private-messages-tags/:username/:tag_id.json" => "list#private_messages_tag", as: "topics_private_messages_tag", defaults: { format: :json }
|
get "private-messages-tags/:username/:tag_id.json" => "list#private_messages_tag", as: "topics_private_messages_tag", defaults: { format: :json }
|
||||||
|
get "private-messages-new/:username" => "list#private_messages_new", as: "topics_private_messages_new", defaults: { format: :json }
|
||||||
get "private-messages-warnings/:username" => "list#private_messages_warnings", as: "topics_private_messages_warnings", defaults: { format: :json }
|
get "private-messages-warnings/:username" => "list#private_messages_warnings", as: "topics_private_messages_warnings", defaults: { format: :json }
|
||||||
get "groups/:group_name" => "list#group_topics", as: "group_topics", group_name: RouteFormat.username
|
get "groups/:group_name" => "list#group_topics", as: "group_topics", group_name: RouteFormat.username
|
||||||
|
|
||||||
scope "/private-messages-group/:username", group_name: RouteFormat.username do
|
scope "/private-messages-group/:username", group_name: RouteFormat.username do
|
||||||
get ":group_name.json" => "list#private_messages_group", as: "topics_private_messages_group"
|
get ":group_name.json" => "list#private_messages_group", as: "topics_private_messages_group"
|
||||||
get ":group_name/archive.json" => "list#private_messages_group_archive", as: "topics_private_messages_group_archive"
|
get ":group_name/archive.json" => "list#private_messages_group_archive", as: "topics_private_messages_group_archive"
|
||||||
|
get ":group_name/new.json" => "list#private_messages_group_new", as: "topics_private_messages_group_new"
|
||||||
|
get ":group_name/unread.json" => "list#private_messages_group_unread", as: "topics_private_messages_group_unread"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class TopicQuery
|
class TopicQuery
|
||||||
|
include PrivateMessageLists
|
||||||
|
|
||||||
PG_MAX_INT ||= 2147483647
|
PG_MAX_INT ||= 2147483647
|
||||||
DEFAULT_PER_PAGE_COUNT ||= 30
|
DEFAULT_PER_PAGE_COUNT ||= 30
|
||||||
|
|
||||||
|
@ -293,12 +295,6 @@ class TopicQuery
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def not_archived(list, user)
|
|
||||||
list.joins("LEFT JOIN user_archived_messages um
|
|
||||||
ON um.user_id = #{user.id.to_i} AND um.topic_id = topics.id")
|
|
||||||
.where('um.user_id IS NULL')
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_group_topics(group)
|
def list_group_topics(group)
|
||||||
list = default_results.where("
|
list = default_results.where("
|
||||||
topics.user_id IN (
|
topics.user_id IN (
|
||||||
|
@ -309,79 +305,6 @@ class TopicQuery
|
||||||
create_list(:group_topics, {}, list)
|
create_list(:group_topics, {}, list)
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_private_messages(user)
|
|
||||||
list = private_messages_for(user, :user)
|
|
||||||
|
|
||||||
list = not_archived(list, user)
|
|
||||||
.where('NOT (topics.participant_count = 1 AND topics.user_id = ? AND topics.moderator_posts_count = 0)', user.id)
|
|
||||||
|
|
||||||
create_list(:private_messages, {}, list)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_private_messages_archive(user)
|
|
||||||
list = private_messages_for(user, :user)
|
|
||||||
list = list.joins(:user_archived_messages).where('user_archived_messages.user_id = ?', user.id)
|
|
||||||
create_list(:private_messages, {}, list)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_private_messages_sent(user)
|
|
||||||
list = private_messages_for(user, :user)
|
|
||||||
list = list.where('EXISTS (
|
|
||||||
SELECT 1 FROM posts
|
|
||||||
WHERE posts.topic_id = topics.id AND
|
|
||||||
posts.user_id = ?
|
|
||||||
)', user.id)
|
|
||||||
list = not_archived(list, user)
|
|
||||||
create_list(:private_messages, {}, list)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_private_messages_unread(user)
|
|
||||||
list = private_messages_for(user, :user)
|
|
||||||
|
|
||||||
list = TopicQuery.unread_filter(
|
|
||||||
list,
|
|
||||||
staff: user.staff?
|
|
||||||
)
|
|
||||||
|
|
||||||
first_unread_pm_at = UserStat.where(user_id: user.id).pluck_first(:first_unread_pm_at)
|
|
||||||
list = list.where("topics.updated_at >= ?", first_unread_pm_at) if first_unread_pm_at
|
|
||||||
create_list(:private_messages, {}, list)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_private_messages_group(user)
|
|
||||||
list = private_messages_for(user, :group)
|
|
||||||
group = Group.where('name ilike ?', @options[:group_name]).select(:id, :publish_read_state).first
|
|
||||||
publish_read_state = !!group&.publish_read_state
|
|
||||||
list = list.joins("LEFT JOIN group_archived_messages gm ON gm.topic_id = topics.id AND
|
|
||||||
gm.group_id = #{group&.id&.to_i}")
|
|
||||||
list = list.where("gm.id IS NULL")
|
|
||||||
list = append_read_state(list, group) if publish_read_state
|
|
||||||
create_list(:private_messages, { publish_read_state: publish_read_state }, list)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_private_messages_group_archive(user)
|
|
||||||
list = private_messages_for(user, :group)
|
|
||||||
group_id = Group.where('name ilike ?', @options[:group_name]).pluck_first(:id)
|
|
||||||
list = list.joins("JOIN group_archived_messages gm ON gm.topic_id = topics.id AND
|
|
||||||
gm.group_id = #{group_id.to_i}")
|
|
||||||
create_list(:private_messages, {}, list)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_private_messages_tag(user)
|
|
||||||
list = private_messages_for(user, :all)
|
|
||||||
list = list.joins("JOIN topic_tags tt ON tt.topic_id = topics.id
|
|
||||||
JOIN tags t ON t.id = tt.tag_id AND t.name = '#{@options[:tags][0]}'")
|
|
||||||
create_list(:private_messages, {}, list)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_private_messages_warnings(user)
|
|
||||||
list = private_messages_for(user, :user)
|
|
||||||
list = list.where('topics.subtype = ?', TopicSubtype.moderator_warning)
|
|
||||||
# Exclude official warnings that the user created, instead of received
|
|
||||||
list = list.where('topics.user_id <> ?', user.id)
|
|
||||||
create_list(:private_messages, {}, list)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_category_topic_ids(category)
|
def list_category_topic_ids(category)
|
||||||
query = default_results(category: category.id)
|
query = default_results(category: category.id)
|
||||||
pinned_ids = query.where('topics.pinned_at IS NOT NULL AND topics.category_id = ?', category.id).limit(nil).order('pinned_at DESC').pluck(:id)
|
pinned_ids = query.where('topics.pinned_at IS NOT NULL AND topics.category_id = ?', category.id).limit(nil).order('pinned_at DESC').pluck(:id)
|
||||||
|
@ -590,50 +513,6 @@ class TopicQuery
|
||||||
DEFAULT_PER_PAGE_COUNT
|
DEFAULT_PER_PAGE_COUNT
|
||||||
end
|
end
|
||||||
|
|
||||||
def private_messages_for(user, type)
|
|
||||||
options = @options
|
|
||||||
options.reverse_merge!(per_page: per_page_setting)
|
|
||||||
|
|
||||||
result = Topic.includes(:allowed_users)
|
|
||||||
result = result.includes(:tags) if SiteSetting.tagging_enabled
|
|
||||||
|
|
||||||
if type == :group
|
|
||||||
result = result.joins(
|
|
||||||
"INNER JOIN topic_allowed_groups tag ON tag.topic_id = topics.id AND tag.group_id IN (SELECT id FROM groups WHERE LOWER(name) = '#{PG::Connection.escape_string(@options[:group_name].downcase)}')"
|
|
||||||
)
|
|
||||||
|
|
||||||
unless user.admin?
|
|
||||||
result = result.joins("INNER JOIN group_users gu ON gu.group_id = tag.group_id AND gu.user_id = #{user.id.to_i}")
|
|
||||||
end
|
|
||||||
elsif type == :user
|
|
||||||
result = result.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = #{user.id.to_i})")
|
|
||||||
elsif type == :all
|
|
||||||
result = result.where("topics.id IN (
|
|
||||||
SELECT topic_id
|
|
||||||
FROM topic_allowed_users
|
|
||||||
WHERE user_id = #{user.id.to_i}
|
|
||||||
UNION ALL
|
|
||||||
SELECT topic_id FROM topic_allowed_groups
|
|
||||||
WHERE group_id IN (
|
|
||||||
SELECT group_id FROM group_users WHERE user_id = #{user.id.to_i}
|
|
||||||
)
|
|
||||||
)")
|
|
||||||
end
|
|
||||||
|
|
||||||
result = result.joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{user.id.to_i})")
|
|
||||||
.order("topics.bumped_at DESC")
|
|
||||||
.private_messages
|
|
||||||
|
|
||||||
result = result.limit(options[:per_page]) unless options[:limit] == false
|
|
||||||
result = result.visible if options[:visible] || @user.nil? || @user.regular?
|
|
||||||
|
|
||||||
if options[:page]
|
|
||||||
offset = options[:page].to_i * options[:per_page]
|
|
||||||
result = result.offset(offset) if offset > 0
|
|
||||||
end
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply_shared_drafts(result, category_id, options)
|
def apply_shared_drafts(result, category_id, options)
|
||||||
|
|
||||||
# PERF: avoid any penalty if there are no shared drafts enabled
|
# PERF: avoid any penalty if there are no shared drafts enabled
|
||||||
|
@ -955,7 +834,7 @@ class TopicQuery
|
||||||
list
|
list
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_muted_tags(list, user, opts = nil)
|
def remove_muted_tags(list, user, opts = {})
|
||||||
if !SiteSetting.tagging_enabled || SiteSetting.remove_muted_tags_from_latest == 'never'
|
if !SiteSetting.tagging_enabled || SiteSetting.remove_muted_tags_from_latest == 'never'
|
||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
|
@ -1149,18 +1028,4 @@ class TopicQuery
|
||||||
|
|
||||||
result.order('topics.bumped_at DESC')
|
result.order('topics.bumped_at DESC')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def append_read_state(list, group)
|
|
||||||
group_id = group&.id
|
|
||||||
return list if group_id.nil?
|
|
||||||
|
|
||||||
selected_values = list.select_values.empty? ? ['topics.*'] : list.select_values
|
|
||||||
selected_values << "COALESCE(tg.last_read_post_number, 0) AS last_read_post_number"
|
|
||||||
|
|
||||||
list
|
|
||||||
.joins("LEFT OUTER JOIN topic_groups tg ON topics.id = tg.topic_id AND tg.group_id = #{group_id}")
|
|
||||||
.select(*selected_values)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class TopicQuery
|
||||||
|
module PrivateMessageLists
|
||||||
|
def list_private_messages_all(user)
|
||||||
|
list = private_messages_for(user, :all)
|
||||||
|
list = filter_archived(list, user, archived: false)
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_all_sent(user)
|
||||||
|
list = private_messages_for(user, :all)
|
||||||
|
|
||||||
|
list = list.where(<<~SQL, user.id)
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1 FROM posts
|
||||||
|
WHERE posts.topic_id = topics.id AND posts.user_id = ?
|
||||||
|
)
|
||||||
|
SQL
|
||||||
|
|
||||||
|
list = filter_archived(list, user, archived: false)
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_all_archive(user)
|
||||||
|
list = private_messages_for(user, :all)
|
||||||
|
list = filter_archived(list, user, archived: true)
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_all_new(user)
|
||||||
|
list_private_messages_new(user, :all)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_all_unread(user)
|
||||||
|
list_private_messages_unread(user, :all)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages(user)
|
||||||
|
list = private_messages_for(user, :user)
|
||||||
|
list = not_archived(list, user)
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_archive(user)
|
||||||
|
list = private_messages_for(user, :user)
|
||||||
|
list = list.joins(:user_archived_messages).where('user_archived_messages.user_id = ?', user.id)
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_sent(user)
|
||||||
|
list = private_messages_for(user, :user)
|
||||||
|
|
||||||
|
list = list.where(<<~SQL, user.id)
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1 FROM posts
|
||||||
|
WHERE posts.topic_id = topics.id AND posts.user_id = ?
|
||||||
|
)
|
||||||
|
SQL
|
||||||
|
|
||||||
|
list = not_archived(list, user)
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_new(user, type = :user)
|
||||||
|
list = TopicQuery.new_filter(
|
||||||
|
private_messages_for(user, type),
|
||||||
|
treat_as_new_topic_start_date: user.user_option.treat_as_new_topic_start_date
|
||||||
|
)
|
||||||
|
|
||||||
|
list = remove_muted_tags(list, user)
|
||||||
|
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_unread(user, type = :user)
|
||||||
|
list = TopicQuery.unread_filter(
|
||||||
|
private_messages_for(user, type),
|
||||||
|
staff: user.staff?
|
||||||
|
)
|
||||||
|
|
||||||
|
first_unread_pm_at = UserStat
|
||||||
|
.where(user_id: user.id)
|
||||||
|
.pluck_first(:first_unread_pm_at)
|
||||||
|
|
||||||
|
if first_unread_pm_at
|
||||||
|
list = list.where("topics.updated_at >= ?", first_unread_pm_at)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_group(user)
|
||||||
|
list = private_messages_for(user, :group)
|
||||||
|
|
||||||
|
list = list.joins(<<~SQL)
|
||||||
|
LEFT JOIN group_archived_messages gm
|
||||||
|
ON gm.topic_id = topics.id AND gm.group_id = #{group.id.to_i}
|
||||||
|
SQL
|
||||||
|
|
||||||
|
list = list.where("gm.id IS NULL")
|
||||||
|
publish_read_state = !!group.publish_read_state
|
||||||
|
list = append_read_state(list, group) if publish_read_state
|
||||||
|
create_list(:private_messages, { publish_read_state: publish_read_state }, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_group_archive(user)
|
||||||
|
list = private_messages_for(user, :group)
|
||||||
|
|
||||||
|
list = list.joins(<<~SQL)
|
||||||
|
INNER JOIN group_archived_messages gm
|
||||||
|
ON gm.topic_id = topics.id AND gm.group_id = #{group.id.to_i}
|
||||||
|
SQL
|
||||||
|
|
||||||
|
publish_read_state = !!group.publish_read_state
|
||||||
|
list = append_read_state(list, group) if publish_read_state
|
||||||
|
create_list(:private_messages, { publish_read_state: publish_read_state }, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_group_new(user)
|
||||||
|
list = TopicQuery.new_filter(
|
||||||
|
private_messages_for(user, :group),
|
||||||
|
treat_as_new_topic_start_date: user.user_option.treat_as_new_topic_start_date
|
||||||
|
)
|
||||||
|
|
||||||
|
publish_read_state = !!group.publish_read_state
|
||||||
|
list = append_read_state(list, group) if publish_read_state
|
||||||
|
create_list(:private_messages, { publish_read_state: publish_read_state }, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_group_unread(user)
|
||||||
|
list = TopicQuery.unread_filter(
|
||||||
|
private_messages_for(user, :group),
|
||||||
|
staff: user.staff?
|
||||||
|
)
|
||||||
|
|
||||||
|
first_unread_pm_at = UserStat
|
||||||
|
.where(user_id: user.id)
|
||||||
|
.pluck_first(:first_unread_pm_at)
|
||||||
|
|
||||||
|
if first_unread_pm_at
|
||||||
|
list = list.where("topics.updated_at >= ?", first_unread_pm_at)
|
||||||
|
end
|
||||||
|
|
||||||
|
publish_read_state = !!group.publish_read_state
|
||||||
|
list = append_read_state(list, group) if publish_read_state
|
||||||
|
create_list(:private_messages, { publish_read_state: publish_read_state }, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_warnings(user)
|
||||||
|
list = private_messages_for(user, :user)
|
||||||
|
list = list.where('topics.subtype = ?', TopicSubtype.moderator_warning)
|
||||||
|
# Exclude official warnings that the user created, instead of received
|
||||||
|
list = list.where('topics.user_id <> ?', user.id)
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def private_messages_for(user, type)
|
||||||
|
options = @options
|
||||||
|
options.reverse_merge!(per_page: per_page_setting)
|
||||||
|
|
||||||
|
result = Topic.includes(:allowed_users)
|
||||||
|
result = result.includes(:tags) if SiteSetting.tagging_enabled
|
||||||
|
|
||||||
|
if type == :group
|
||||||
|
result = result.joins(
|
||||||
|
"INNER JOIN topic_allowed_groups tag ON tag.topic_id = topics.id AND tag.group_id IN (SELECT id FROM groups WHERE LOWER(name) = '#{PG::Connection.escape_string(@options[:group_name].downcase)}')"
|
||||||
|
)
|
||||||
|
|
||||||
|
unless user.admin?
|
||||||
|
result = result.joins("INNER JOIN group_users gu ON gu.group_id = tag.group_id AND gu.user_id = #{user.id.to_i}")
|
||||||
|
end
|
||||||
|
elsif type == :user
|
||||||
|
result = result.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = #{user.id.to_i})")
|
||||||
|
elsif type == :all
|
||||||
|
result = result.where("topics.id IN (
|
||||||
|
SELECT topic_id
|
||||||
|
FROM topic_allowed_users
|
||||||
|
WHERE user_id = #{user.id.to_i}
|
||||||
|
UNION ALL
|
||||||
|
SELECT topic_id FROM topic_allowed_groups
|
||||||
|
WHERE group_id IN (
|
||||||
|
SELECT group_id FROM group_users WHERE user_id = #{user.id.to_i}
|
||||||
|
)
|
||||||
|
)")
|
||||||
|
end
|
||||||
|
|
||||||
|
result = result.joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{user.id.to_i})")
|
||||||
|
.order("topics.bumped_at DESC")
|
||||||
|
.private_messages
|
||||||
|
|
||||||
|
result = result.limit(options[:per_page]) unless options[:limit] == false
|
||||||
|
result = result.visible if options[:visible] || @user.nil? || @user.regular?
|
||||||
|
|
||||||
|
if options[:page]
|
||||||
|
offset = options[:page].to_i * options[:per_page]
|
||||||
|
result = result.offset(offset) if offset > 0
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_tag(user)
|
||||||
|
list = private_messages_for(user, :all)
|
||||||
|
list = list.joins("JOIN topic_tags tt ON tt.topic_id = topics.id
|
||||||
|
JOIN tags t ON t.id = tt.tag_id AND t.name = '#{@options[:tags][0]}'")
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def append_read_state(list, group)
|
||||||
|
group_id = group.id
|
||||||
|
return list if group_id.nil?
|
||||||
|
|
||||||
|
selected_values = list.select_values.empty? ? ['topics.*'] : list.select_values
|
||||||
|
selected_values << "COALESCE(tg.last_read_post_number, 0) AS last_read_post_number"
|
||||||
|
|
||||||
|
list
|
||||||
|
.joins("LEFT OUTER JOIN topic_groups tg ON topics.id = tg.topic_id AND tg.group_id = #{group_id}")
|
||||||
|
.select(*selected_values)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_archived(list, user, archived: true)
|
||||||
|
list = list.joins(<<~SQL)
|
||||||
|
LEFT JOIN group_archived_messages gm ON gm.topic_id = topics.id
|
||||||
|
LEFT JOIN user_archived_messages um
|
||||||
|
ON um.user_id = #{user.id.to_i}
|
||||||
|
AND um.topic_id = topics.id
|
||||||
|
SQL
|
||||||
|
|
||||||
|
list =
|
||||||
|
if archived
|
||||||
|
list.where("um.user_id IS NOT NULL OR gm.topic_id IS NOT NULL")
|
||||||
|
else
|
||||||
|
list.where("um.user_id IS NULL AND gm.topic_id IS NULL")
|
||||||
|
end
|
||||||
|
|
||||||
|
list
|
||||||
|
end
|
||||||
|
|
||||||
|
def not_archived(list, user)
|
||||||
|
list.joins("LEFT JOIN user_archived_messages um
|
||||||
|
ON um.user_id = #{user.id.to_i} AND um.topic_id = topics.id")
|
||||||
|
.where('um.user_id IS NULL')
|
||||||
|
end
|
||||||
|
|
||||||
|
def group
|
||||||
|
@group ||= begin
|
||||||
|
Group
|
||||||
|
.where('name ilike ?', @options[:group_name])
|
||||||
|
.select(:id, :publish_read_state)
|
||||||
|
.first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1067,7 +1067,6 @@ describe TopicQuery do
|
||||||
|
|
||||||
expect(TopicQuery.new(user, tags: [tag.name]).list_private_messages_tag(user).topics).to eq([private_message])
|
expect(TopicQuery.new(user, tags: [tag.name]).list_private_messages_tag(user).topics).to eq([private_message])
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1193,75 +1192,6 @@ describe TopicQuery do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#list_private_messages_group' do
|
|
||||||
fab!(:group) { Fabricate(:group) }
|
|
||||||
|
|
||||||
let!(:group_message) do
|
|
||||||
Fabricate(:private_message_topic,
|
|
||||||
allowed_groups: [group],
|
|
||||||
topic_allowed_users: [
|
|
||||||
Fabricate.build(:topic_allowed_user, user: Fabricate(:user)),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
|
||||||
group.add(creator)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should return the right list for a group user' do
|
|
||||||
topics = TopicQuery.new(nil, group_name: group.name)
|
|
||||||
.list_private_messages_group(creator)
|
|
||||||
.topics
|
|
||||||
|
|
||||||
expect(topics).to contain_exactly(group_message)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should return the right list for an admin not part of the group' do
|
|
||||||
group.update!(name: group.name.capitalize)
|
|
||||||
|
|
||||||
topics = TopicQuery.new(nil, group_name: group.name.upcase)
|
|
||||||
.list_private_messages_group(Fabricate(:admin))
|
|
||||||
.topics
|
|
||||||
|
|
||||||
expect(topics).to contain_exactly(group_message)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not allow a moderator not part of the group to view the group's messages" do
|
|
||||||
topics = TopicQuery.new(nil, group_name: group.name)
|
|
||||||
.list_private_messages_group(Fabricate(:moderator))
|
|
||||||
.topics
|
|
||||||
|
|
||||||
expect(topics).to eq([])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not allow a user not part of the group to view the group's messages" do
|
|
||||||
topics = TopicQuery.new(nil, group_name: group.name)
|
|
||||||
.list_private_messages_group(Fabricate(:user))
|
|
||||||
.topics
|
|
||||||
|
|
||||||
expect(topics).to eq([])
|
|
||||||
end
|
|
||||||
|
|
||||||
context "Calculating minimum unread count for a topic" do
|
|
||||||
before { group.update!(publish_read_state: true) }
|
|
||||||
|
|
||||||
let(:listed_message) do
|
|
||||||
TopicQuery.new(nil, group_name: group.name)
|
|
||||||
.list_private_messages_group(creator)
|
|
||||||
.topics.first
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns the last read post number' do
|
|
||||||
topic_group = TopicGroup.create!(
|
|
||||||
topic: group_message, group: group, last_read_post_number: 10
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(listed_message.last_read_post_number).to eq(topic_group.last_read_post_number)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "shared drafts" do
|
context "shared drafts" do
|
||||||
fab!(:category) { Fabricate(:category_with_definition) }
|
fab!(:category) { Fabricate(:category_with_definition) }
|
||||||
fab!(:shared_drafts_category) { Fabricate(:category_with_definition) }
|
fab!(:shared_drafts_category) { Fabricate(:category_with_definition) }
|
||||||
|
@ -1349,16 +1279,4 @@ describe TopicQuery do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#list_private_messages' do
|
|
||||||
it "includes topics with moderator posts" do
|
|
||||||
private_message_topic = Fabricate(:private_message_post, user: user).topic
|
|
||||||
|
|
||||||
expect(TopicQuery.new(user).list_private_messages(user).topics).to be_empty
|
|
||||||
|
|
||||||
private_message_topic.add_moderator_post(admin, "Thank you for your flag")
|
|
||||||
|
|
||||||
expect(TopicQuery.new(user).list_private_messages(user).topics).to eq([private_message_topic])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,305 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe TopicQuery::PrivateMessageLists do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
fab!(:user_2) { Fabricate(:user) }
|
||||||
|
|
||||||
|
fab!(:group) do
|
||||||
|
Fabricate(:group, messageable_level: Group::ALIAS_LEVELS[:everyone]).tap do |g|
|
||||||
|
g.add(user_2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:group_message) do
|
||||||
|
create_post(
|
||||||
|
user: user,
|
||||||
|
target_group_names: [group.name],
|
||||||
|
archetype: Archetype.private_message
|
||||||
|
).topic
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:private_message) do
|
||||||
|
create_post(
|
||||||
|
user: user,
|
||||||
|
target_usernames: [user_2.username],
|
||||||
|
archetype: Archetype.private_message
|
||||||
|
).topic
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_all' do
|
||||||
|
it 'returns a list of all private messages that a user has access to' do
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all(user).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(group_message, private_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not include user or group archived messages' do
|
||||||
|
UserArchivedMessage.archive!(user.id, group_message)
|
||||||
|
UserArchivedMessage.archive!(user.id, private_message)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all(user).topics
|
||||||
|
|
||||||
|
expect(topics).to eq([])
|
||||||
|
|
||||||
|
GroupArchivedMessage.archive!(user_2.id, group_message)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(private_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_all_sent' do
|
||||||
|
it 'returns a list of all private messages that a user has sent' do
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_sent(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to eq([])
|
||||||
|
|
||||||
|
create_post(user: user_2, topic: private_message)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_sent(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(private_message)
|
||||||
|
|
||||||
|
create_post(user: user_2, topic: group_message)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_sent(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(private_message, group_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not include user or group archived messages' do
|
||||||
|
create_post(user: user_2, topic: private_message)
|
||||||
|
create_post(user: user_2, topic: group_message)
|
||||||
|
|
||||||
|
UserArchivedMessage.archive!(user_2.id, private_message)
|
||||||
|
GroupArchivedMessage.archive!(user_2.id, group_message)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_sent(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to eq([])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_all_archive' do
|
||||||
|
it 'returns a list of all private messages that has been archived' do
|
||||||
|
UserArchivedMessage.archive!(user_2.id, private_message)
|
||||||
|
GroupArchivedMessage.archive!(user_2.id, group_message)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_archive(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(private_message, group_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_all_new' do
|
||||||
|
it 'returns a list of new private messages' do
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_new(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(private_message, group_message)
|
||||||
|
|
||||||
|
TopicUser.find_by(user: user_2, topic: group_message).update!(
|
||||||
|
last_read_post_number: 1
|
||||||
|
)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_new(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(private_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_all_unread' do
|
||||||
|
it 'returns a list of unread private messages' do
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_unread(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to eq([])
|
||||||
|
|
||||||
|
TopicUser.find_by(user: user_2, topic: group_message).update!(
|
||||||
|
last_read_post_number: 1
|
||||||
|
)
|
||||||
|
|
||||||
|
create_post(user: user, topic: group_message)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages_all_unread(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(group_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages' do
|
||||||
|
it 'returns a list of all private messages that a user has access to' do
|
||||||
|
topics = TopicQuery.new(nil).list_private_messages(user_2).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(private_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_group' do
|
||||||
|
it 'should return the right list for a group user' do
|
||||||
|
group.add(user_2)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil, group_name: group.name)
|
||||||
|
.list_private_messages_group(user_2)
|
||||||
|
.topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(group_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the right list for an admin not part of the group' do
|
||||||
|
group.update!(name: group.name.capitalize)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil, group_name: group.name.upcase)
|
||||||
|
.list_private_messages_group(Fabricate(:admin))
|
||||||
|
.topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(group_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow a moderator not part of the group to view the group's messages" do
|
||||||
|
topics = TopicQuery.new(nil, group_name: group.name)
|
||||||
|
.list_private_messages_group(Fabricate(:moderator))
|
||||||
|
.topics
|
||||||
|
|
||||||
|
expect(topics).to eq([])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow a user not part of the group to view the group's messages" do
|
||||||
|
topics = TopicQuery.new(nil, group_name: group.name)
|
||||||
|
.list_private_messages_group(Fabricate(:user))
|
||||||
|
.topics
|
||||||
|
|
||||||
|
expect(topics).to eq([])
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Calculating minimum unread count for a topic" do
|
||||||
|
before do
|
||||||
|
group.update!(publish_read_state: true)
|
||||||
|
group.add(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:listed_message) do
|
||||||
|
TopicQuery.new(nil, group_name: group.name)
|
||||||
|
.list_private_messages_group(user)
|
||||||
|
.topics.first
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the last read post number' do
|
||||||
|
topic_group = TopicGroup.create!(
|
||||||
|
topic: group_message, group: group, last_read_post_number: 10
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(listed_message.last_read_post_number).to eq(topic_group.last_read_post_number)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_group_new' do
|
||||||
|
it 'returns a list of new private messages for a group that user is a part of' do
|
||||||
|
topics = TopicQuery.new(nil, group_name: group.name)
|
||||||
|
.list_private_messages_group_new(user_2)
|
||||||
|
.topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(group_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_group_unread' do
|
||||||
|
it 'returns a list of unread private messages for a group that user is a part of' do
|
||||||
|
topics = TopicQuery.new(nil, group_name: group.name)
|
||||||
|
.list_private_messages_group_unread(user_2)
|
||||||
|
.topics
|
||||||
|
|
||||||
|
expect(topics).to eq([])
|
||||||
|
|
||||||
|
TopicUser.find_by(user: user_2, topic: group_message).update!(
|
||||||
|
last_read_post_number: 1
|
||||||
|
)
|
||||||
|
|
||||||
|
create_post(user: user, topic: group_message)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(nil, group_name: group.name)
|
||||||
|
.list_private_messages_group_unread(user_2)
|
||||||
|
.topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(group_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_unread' do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
fab!(:user_2) { Fabricate(:user) }
|
||||||
|
|
||||||
|
fab!(:pm) do
|
||||||
|
create_post(
|
||||||
|
user: user,
|
||||||
|
target_usernames: [user_2.username],
|
||||||
|
archetype: Archetype.private_message
|
||||||
|
).topic
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:pm_2) do
|
||||||
|
create_post(
|
||||||
|
user: user,
|
||||||
|
target_usernames: [user_2.username],
|
||||||
|
archetype: Archetype.private_message
|
||||||
|
).topic
|
||||||
|
end
|
||||||
|
|
||||||
|
fab!(:pm_3) do
|
||||||
|
create_post(
|
||||||
|
user: user,
|
||||||
|
target_usernames: [user_2.username],
|
||||||
|
archetype: Archetype.private_message
|
||||||
|
).topic
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a list of private messages with unread posts that user is at least tracking' do
|
||||||
|
freeze_time 1.minute.from_now do
|
||||||
|
create_post(user: user_2, topic_id: pm.id)
|
||||||
|
create_post(user: user_2, topic_id: pm_3.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
TopicUser.find_by(user: user, topic: pm_3).update!(
|
||||||
|
notification_level: TopicUser.notification_levels[:regular]
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(TopicQuery.new(user).list_private_messages_unread(user).topics)
|
||||||
|
.to contain_exactly(pm)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#list_private_messages_new' do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
fab!(:user_2) { Fabricate(:user) }
|
||||||
|
|
||||||
|
fab!(:pm) do
|
||||||
|
create_post(
|
||||||
|
user: user,
|
||||||
|
target_usernames: [user_2.username],
|
||||||
|
archetype: Archetype.private_message
|
||||||
|
).topic
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a list of new private messages' do
|
||||||
|
expect(TopicQuery.new(user_2).list_private_messages_new(user_2).topics)
|
||||||
|
.to contain_exactly(pm)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a list of new private messages accounting for muted tags' do
|
||||||
|
tag = Fabricate(:tag)
|
||||||
|
|
||||||
|
pm.tags << tag
|
||||||
|
|
||||||
|
TagUser.create!(
|
||||||
|
tag: tag,
|
||||||
|
user: user_2,
|
||||||
|
notification_level: TopicUser.notification_levels[:muted]
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(TopicQuery.new(user_2).list_private_messages_new(user_2).topics)
|
||||||
|
.to eq([])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -205,8 +205,8 @@ describe TopicTrackingState do
|
||||||
|
|
||||||
expect(messages.map(&:channel)).to contain_exactly(
|
expect(messages.map(&:channel)).to contain_exactly(
|
||||||
'/private-messages/inbox',
|
'/private-messages/inbox',
|
||||||
"/private-messages/group/#{group1.name}",
|
"/private-messages/group/#{group1.name}/inbox",
|
||||||
"/private-messages/group/#{group2.name}"
|
"/private-messages/group/#{group2.name}/inbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
message = messages.find do |m|
|
message = messages.find do |m|
|
||||||
|
@ -218,7 +218,7 @@ describe TopicTrackingState do
|
||||||
|
|
||||||
[group1, group2].each do |group|
|
[group1, group2].each do |group|
|
||||||
message = messages.find do |m|
|
message = messages.find do |m|
|
||||||
m.channel == "/private-messages/group/#{group.name}"
|
m.channel == "/private-messages/group/#{group.name}/inbox"
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(message.data["topic_id"]).to eq(private_message_topic.id)
|
expect(message.data["topic_id"]).to eq(private_message_topic.id)
|
||||||
|
@ -237,9 +237,9 @@ describe TopicTrackingState do
|
||||||
|
|
||||||
expect(messages.map(&:channel)).to contain_exactly(
|
expect(messages.map(&:channel)).to contain_exactly(
|
||||||
'/private-messages/inbox',
|
'/private-messages/inbox',
|
||||||
"/private-messages/group/#{group1.name}",
|
"/private-messages/group/#{group1.name}/inbox",
|
||||||
"/private-messages/group/#{group1.name}/archive",
|
"/private-messages/group/#{group1.name}/archive",
|
||||||
"/private-messages/group/#{group2.name}",
|
"/private-messages/group/#{group2.name}/inbox",
|
||||||
"/private-messages/group/#{group2.name}/archive",
|
"/private-messages/group/#{group2.name}/archive",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -249,11 +249,9 @@ describe TopicTrackingState do
|
||||||
expect(message.user_ids).to eq(private_message_topic.allowed_users.map(&:id))
|
expect(message.user_ids).to eq(private_message_topic.allowed_users.map(&:id))
|
||||||
|
|
||||||
[group1, group2].each do |group|
|
[group1, group2].each do |group|
|
||||||
group_channel = "/private-messages/group/#{group.name}"
|
|
||||||
|
|
||||||
[
|
[
|
||||||
group_channel,
|
"/private-messages/group/#{group.name}/inbox",
|
||||||
"#{group_channel}/archive"
|
"/private-messages/group/#{group.name}/archive"
|
||||||
].each do |channel|
|
].each do |channel|
|
||||||
message = messages.find { |m| m.channel == channel }
|
message = messages.find { |m| m.channel == channel }
|
||||||
expect(message.data["topic_id"]).to eq(private_message_topic.id)
|
expect(message.data["topic_id"]).to eq(private_message_topic.id)
|
||||||
|
@ -291,7 +289,7 @@ describe TopicTrackingState do
|
||||||
expected_channels = [
|
expected_channels = [
|
||||||
'/private-messages/inbox',
|
'/private-messages/inbox',
|
||||||
'/private-messages/sent',
|
'/private-messages/sent',
|
||||||
"/private-messages/group/#{group.name}"
|
"/private-messages/group/#{group.name}/inbox"
|
||||||
]
|
]
|
||||||
|
|
||||||
expect(messages.map(&:channel)).to contain_exactly(*expected_channels)
|
expect(messages.map(&:channel)).to contain_exactly(*expected_channels)
|
||||||
|
|
|
@ -473,7 +473,7 @@ describe TagsController do
|
||||||
it "can't see pm tags" do
|
it "can't see pm tags" do
|
||||||
get "/tags/personal_messages/#{regular_user.username}.json"
|
get "/tags/personal_messages/#{regular_user.username}.json"
|
||||||
|
|
||||||
expect(response).not_to be_successful
|
expect(response.status).to eq(403)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -485,7 +485,7 @@ describe TagsController do
|
||||||
it "can't see pm tags for regular user" do
|
it "can't see pm tags for regular user" do
|
||||||
get "/tags/personal_messages/#{regular_user.username}.json"
|
get "/tags/personal_messages/#{regular_user.username}.json"
|
||||||
|
|
||||||
expect(response).not_to be_successful
|
expect(response.status).to eq(404)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can see their own pm tags" do
|
it "can see their own pm tags" do
|
||||||
|
|
Loading…
Reference in New Issue