Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show system messages when channel members are changed #1087

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const RemoveChannelMemberModal = ({ onClose, member }: RemoveChannelMembe
<Flex direction={'column'} gap='2'>
<ErrorBanner error={errorFetchingChannelMember} />
<ErrorBanner error={error} />
<Text size='1'>This person will no longer have access to the channel and can only rejoin by invitation.</Text>
<Text size='2'>This person will no longer have access to the channel.</Text>
</Flex>

<Flex gap="3" mt="4" justify="end">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,7 @@ export const MessageItem = ({ message, setDeleteMessage, isHighlighted, onReplyM
data-[state=open]:shadow-sm
transition-colors
px-1
py-2
sm:p-2
py-1.5
rounded-md`, isHighlighted ? 'bg-yellow-50 hover:bg-yellow-50 dark:bg-yellow-300/20 dark:hover:bg-yellow-300/20' : !isDesktop && isHovered ? 'bg-gray-2 dark:bg-gray-3' : '', isEmojiPickerOpen ? 'bg-gray-2 dark:bg-gray-3' : '')}>
<Flex className='gap-2.5 sm:gap-3 items-start'>
<MessageLeftElement message={message} user={user} isActive={isActive} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Flex, Text } from '@radix-ui/themes'
import { SystemMessage } from '../../../../../../types/Messaging/Message'
import { DateTooltipShort } from './Renderers/DateTooltip'

const SystemMessageBlock = ({ message }: { message: SystemMessage }) => {
return (
<Flex align='center' gap='2' id={`message-${message.name}`} className='pl-1 py-2.5'>
<DateTooltipShort timestamp={message.creation} />
<Text as='span' color='gray' className='pl-1.5' size='1'>{message.text}</Text>
</Flex>

)
}

export default SystemMessageBlock
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ErrorBanner } from '@/components/layout/AlertBanner'
import { ForwardMessageDialog, useForwardMessage } from '../ChatMessage/MessageActions/ForwardMessage'
import AttachFileToDocumentDialog, { useAttachFileToDocument } from '../ChatMessage/MessageActions/AttachFileToDocument'
import { ReactionAnalyticsDialog, useMessageReactionAnalytics } from '../ChatMessage/MessageActions/MessageReactionAnalytics'
import SystemMessageBlock from '../ChatMessage/SystemMessageBlock'

/**
* Anatomy of a message
Expand Down Expand Up @@ -132,6 +133,8 @@ const ChatStream = ({ channelID, replyToMessage, showThreadButton = true }: Prop
return <DateSeparator key={`date-${message.creation}`} id={`date-${message.creation}`} className='p-2 z-10 relative'>
{message.creation}
</DateSeparator>
} else if (message.message_type === 'System') {
return <SystemMessageBlock key={`${message.name}_${message.modified}`} message={message} />
} else {
return <div key={`${message.name}_${message.modified}`} id={`message-${message.name}`}>
<div className="w-full overflow-x-clip overflow-y-visible text-ellipsis animate-fadein">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,9 @@ const useChatStream = (channelID: string, scrollRef: MutableRefObject<HTMLDivEle
}

const currentMessageSender = message.is_bot_message ? message.bot : message.owner
const nextMessageSender = messages[i + 1].is_bot_message ? messages[i + 1].bot : messages[i + 1].owner

const nextMessage = messages[i + 1]
const nextMessageSender = nextMessage.message_type === "System" ? null : nextMessage.is_bot_message ? nextMessage.bot : nextMessage.owner

if (currentMessageSender !== nextMessageSender) {
messagesWithDateSeparators.push({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,19 @@ def before_insert(self):
self.allow_notifications = 1

def after_delete(self):

member_name = frappe.get_cached_value("Raven User", self.user_id, "full_name")

current_user_name = frappe.get_cached_value("Raven User", frappe.session.user, "full_name")

# If this was the last member of a private channel, archive the channel
if (
frappe.db.count("Raven Channel Member", {"channel_id": self.channel_id}) == 0
and frappe.db.get_value("Raven Channel", self.channel_id, "type") == "Private"
):
frappe.db.set_value("Raven Channel", self.channel_id, "is_archived", 1)

# If this member was the only admin, then make the next oldest member an admin
if (
self.get_admin_count() == 0
and frappe.db.count("Raven Channel Member", {"channel_id": self.channel_id}) > 0
Expand All @@ -61,6 +69,40 @@ def after_delete(self):
)
frappe.db.set_value("Raven Channel Member", first_member.name, "is_admin", 1)

first_member_name = frappe.get_cached_value("Raven User", first_member.user_id, "full_name")

# Add a system message to the channel mentioning the new admin
frappe.get_doc(
{
"doctype": "Raven Message",
"channel_id": self.channel_id,
"message_type": "System",
"text": f"{member_name} was removed by {current_user_name} and {first_member_name} is the new admin of this channel.",
}
).insert()
else:
# If the member who left is the current user, then add a system message to the channel mentioning that the user left
if member_name == current_user_name:
# Add a system message to the channel mentioning the member who left
frappe.get_doc(
{
"doctype": "Raven Message",
"channel_id": self.channel_id,
"message_type": "System",
"text": f"{member_name} left.",
}
).insert(ignore_permissions=True)
else:
# Add a system message to the channel mentioning the member who left
frappe.get_doc(
{
"doctype": "Raven Message",
"channel_id": self.channel_id,
"message_type": "System",
"text": f"{current_user_name} removed {member_name}.",
}
).insert()

def on_trash(self):
# if the leaving member is admin, then the first member becomes new admin
if (
Expand Down Expand Up @@ -119,6 +161,33 @@ def after_insert(self):
if not is_direct_message and self.allow_notifications:
subscribe_user_to_topic(self.channel_id, self.user_id)

if not is_direct_message:

is_thread = self.is_thread()

# Send a system message to the channel mentioning the member who joined
if not is_thread:
member_name = frappe.get_cached_value("Raven User", self.user_id, "full_name")
if self.user_id == frappe.session.user:
frappe.get_doc(
{
"doctype": "Raven Message",
"channel_id": self.channel_id,
"message_type": "System",
"text": f"{member_name} joined.",
}
).insert()
else:
current_user_name = frappe.get_cached_value("Raven User", frappe.session.user, "full_name")
frappe.get_doc(
{
"doctype": "Raven Message",
"channel_id": self.channel_id,
"message_type": "System",
"text": f"{current_user_name} added {member_name}.",
}
).insert()

def on_update(self):
"""
Check if the notification preference is changed and update the subscription
Expand All @@ -134,9 +203,27 @@ def on_update(self):
else:
unsubscribe_user_to_topic(self.channel_id, self.user_id)

if self.has_value_changed("is_admin") and not self.flags.in_insert and not self.is_thread():
# Send a system message to the channel mentioning the member who became admin
member_name = frappe.get_cached_value("Raven User", self.user_id, "full_name")
text = (
f"{member_name} is now an admin." if self.is_admin else f"{member_name} is no longer an admin."
)
frappe.get_doc(
{
"doctype": "Raven Message",
"channel_id": self.channel_id,
"message_type": "System",
"text": text,
}
).insert()

def get_admin_count(self):
return frappe.db.count("Raven Channel Member", {"channel_id": self.channel_id, "is_admin": 1})

def is_thread(self):
return frappe.get_cached_value("Raven Channel", self.channel_id, "is_thread")


def on_doctype_update():
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"fieldname": "message_type",
"fieldtype": "Select",
"label": "Message Type",
"options": "Text\nImage\nFile\nPoll"
"options": "Text\nImage\nFile\nPoll\nSystem"
},
{
"fieldname": "message_reactions",
Expand Down Expand Up @@ -191,7 +191,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-08-16 16:09:36.292391",
"modified": "2024-10-11 18:42:44.984706",
"modified_by": "Administrator",
"module": "Raven Messaging",
"name": "Raven Message",
Expand Down
4 changes: 2 additions & 2 deletions raven/raven_messaging/doctype/raven_message/raven_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class RavenMessage(Document):
linked_message: DF.Link | None
mentions: DF.Table[RavenMention]
message_reactions: DF.JSON | None
message_type: DF.Literal["Text", "Image", "File", "Poll"]
message_type: DF.Literal["Text", "Image", "File", "Poll", "System"]
poll_id: DF.Link | None
replied_message_details: DF.JSON | None
text: DF.LongText | None
Expand All @@ -55,7 +55,7 @@ class RavenMessage(Document):

def before_validate(self):
try:
if self.text:
if self.text and not self.message_type == "System":
content = html2text(self.text)
# Remove trailing new line characters and white spaces
self.content = content.rstrip()
Expand Down
9 changes: 7 additions & 2 deletions types/Messaging/Message.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type Message = FileMessage | TextMessage | ImageMessage | PollMessage
export type Message = FileMessage | TextMessage | ImageMessage | PollMessage | SystemMessage

export interface BaseMessage {
name: string,
Expand All @@ -7,7 +7,7 @@ export interface BaseMessage {
channel_id: string,
creation: string,
modified: string,
message_type: 'Text' | 'File' | 'Image' | 'Poll',
message_type: 'Text' | 'File' | 'Image' | 'Poll' | 'System',
message_reactions?: string | null,
is_continuation: 1 | 0
is_reply: 1 | 0
Expand Down Expand Up @@ -53,6 +53,11 @@ export interface PollMessage extends BaseMessage {
content?: string
}

export interface SystemMessage extends BaseMessage {
message_type: 'System',
text: string,
}

export type DateBlock = {
block_type: 'date',
data: string
Expand Down
Loading