This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/plugins/chat/assets/javascripts/discourse/models/chat-channel.js
Martin Brennan c0a086a988
DEV: Move ChatThreadsManager to channel (#20304)
This commit changes the ChatThreadsManager into a native
class instead of an ember service, and initializes it
for every ChatChannel model. This way each channel has its
own thread manager and cache that we can load/unload as
needed, and we also move activeThread to the channel since
it makes more sense to keep it there, not inside the chat service.

The pattern of calling setOwner with the passed in owner
from ChatChannel is adapted from the latest ember docs,
and is needed to avoid the error below when calling services
from the native class:

> Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container

It works well _only_ if we use our own getOwner wrapper
from addon/lib/get-owner, which is for backwards compat.

c.f. https://guides.emberjs.com/release/in-depth-topics/native-classes-in-depth/
2023-02-16 10:00:40 +10:00

201 lines
4.9 KiB
JavaScript

import RestModel from "discourse/models/rest";
import I18n from "I18n";
import User from "discourse/models/user";
import UserChatChannelMembership from "discourse/plugins/chat/discourse/models/user-chat-channel-membership";
import { ajax } from "discourse/lib/ajax";
import { escapeExpression } from "discourse/lib/utilities";
import { tracked } from "@glimmer/tracking";
import slugifyChannel from "discourse/plugins/chat/discourse/lib/slugify-channel";
import ChatThreadsManager from "discourse/plugins/chat/discourse/lib/chat-threads-manager";
import { getOwner } from "discourse-common/lib/get-owner";
export const CHATABLE_TYPES = {
directMessageChannel: "DirectMessage",
categoryChannel: "Category",
};
export const CHANNEL_STATUSES = {
open: "open",
readOnly: "read_only",
closed: "closed",
archived: "archived",
};
export function channelStatusName(channelStatus) {
switch (channelStatus) {
case CHANNEL_STATUSES.open:
return I18n.t("chat.channel_status.open");
case CHANNEL_STATUSES.readOnly:
return I18n.t("chat.channel_status.read_only");
case CHANNEL_STATUSES.closed:
return I18n.t("chat.channel_status.closed");
case CHANNEL_STATUSES.archived:
return I18n.t("chat.channel_status.archived");
}
}
export function channelStatusIcon(channelStatus) {
if (channelStatus === CHANNEL_STATUSES.open) {
return null;
}
switch (channelStatus) {
case CHANNEL_STATUSES.closed:
return "lock";
case CHANNEL_STATUSES.readOnly:
return "comment-slash";
case CHANNEL_STATUSES.archived:
return "archive";
}
}
const STAFF_READONLY_STATUSES = [
CHANNEL_STATUSES.readOnly,
CHANNEL_STATUSES.archived,
];
const READONLY_STATUSES = [
CHANNEL_STATUSES.closed,
CHANNEL_STATUSES.readOnly,
CHANNEL_STATUSES.archived,
];
export default class ChatChannel extends RestModel {
@tracked currentUserMembership = null;
@tracked isDraft = false;
@tracked title;
@tracked description;
@tracked chatableType;
@tracked status;
@tracked activeThread;
threadsManager = new ChatThreadsManager(getOwner(this));
get escapedTitle() {
return escapeExpression(this.title);
}
get escapedDescription() {
return escapeExpression(this.description);
}
get slugifiedTitle() {
return this.slug || slugifyChannel(this);
}
get routeModels() {
return [this.slugifiedTitle, this.id];
}
get isDirectMessageChannel() {
return this.chatable_type === CHATABLE_TYPES.directMessageChannel;
}
get isCategoryChannel() {
return this.chatable_type === CHATABLE_TYPES.categoryChannel;
}
get isOpen() {
return !this.status || this.status === CHANNEL_STATUSES.open;
}
get isReadOnly() {
return this.status === CHANNEL_STATUSES.readOnly;
}
get isClosed() {
return this.status === CHANNEL_STATUSES.closed;
}
get isArchived() {
return this.status === CHANNEL_STATUSES.archived;
}
get isJoinable() {
return this.isOpen && !this.isArchived;
}
get isFollowing() {
return this.currentUserMembership.following;
}
canModifyMessages(user) {
if (user.staff) {
return !STAFF_READONLY_STATUSES.includes(this.status);
}
return !READONLY_STATUSES.includes(this.status);
}
updateMembership(membership) {
this.currentUserMembership.following = membership.following;
this.currentUserMembership.muted = membership.muted;
this.currentUserMembership.desktop_notification_level =
membership.desktop_notification_level;
this.currentUserMembership.mobile_notification_level =
membership.mobile_notification_level;
}
updateLastReadMessage(messageId) {
if (!this.isFollowing || !messageId) {
return;
}
return ajax(`/chat/${this.id}/read/${messageId}.json`, {
method: "PUT",
}).then(() => {
this.currentUserMembership.last_read_message_id = messageId;
});
}
}
ChatChannel.reopenClass({
create(args) {
args = args || {};
this._initUserModels(args);
this._initUserMembership(args);
args.chatableType = args.chatable_type;
args.membershipsCount = args.memberships_count;
return this._super(args);
},
_initUserModels(args) {
if (args.chatable?.users?.length) {
for (let i = 0; i < args.chatable?.users?.length; i++) {
const userData = args.chatable.users[i];
args.chatable.users[i] = User.create(userData);
}
}
},
_initUserMembership(args) {
if (args.currentUserMembership instanceof UserChatChannelMembership) {
return;
}
args.currentUserMembership = UserChatChannelMembership.create(
args.current_user_membership || {
following: false,
muted: false,
unread_count: 0,
unread_mentions: 0,
}
);
delete args.current_user_membership;
},
});
export function createDirectMessageChannelDraft() {
return ChatChannel.create({
isDraft: true,
chatable_type: CHATABLE_TYPES.directMessageChannel,
chatable: {
users: [],
},
});
}