diff --git a/packages/rocketchat-analytics/client/trackEvents.js b/packages/rocketchat-analytics/client/trackEvents.js
index c672e8bb73d5..12056bedfaba 100644
--- a/packages/rocketchat-analytics/client/trackEvents.js
+++ b/packages/rocketchat-analytics/client/trackEvents.js
@@ -54,6 +54,12 @@ if (!window._paq || window.ga) {
}
}, RocketChat.callbacks.priority.MEDIUM, 'analytics-room-topic-changed');
+ RocketChat.callbacks.add('roomAnnouncementChanged', (room) => {
+ if (RocketChat.settings.get('Analytics_features_rooms')) {
+ trackEvent('Room', 'Changed Announcement', room.name + ' (' + room._id + ')');
+ }
+ }, RocketChat.callbacks.priority.MEDIUM, 'analytics-room-announcement-changed');
+
RocketChat.callbacks.add('roomTypeChanged', (room) => {
if (RocketChat.settings.get('Analytics_features_rooms')) {
trackEvent('Room', 'Changed Room Type', room.name + ' (' + room._id + ')');
diff --git a/packages/rocketchat-channel-settings/client/startup/messageTypes.coffee b/packages/rocketchat-channel-settings/client/startup/messageTypes.coffee
index 6d34cd8c9397..7911c68604bc 100644
--- a/packages/rocketchat-channel-settings/client/startup/messageTypes.coffee
+++ b/packages/rocketchat-channel-settings/client/startup/messageTypes.coffee
@@ -19,6 +19,16 @@ Meteor.startup ->
room_topic: message.msg
}
+ RocketChat.MessageTypes.registerType
+ id: 'room_changed_announcement'
+ system: true
+ message: 'room_changed_announcement'
+ data: (message) ->
+ return {
+ user_by: message.u?.username
+ room_announcement: message.msg
+ }
+
RocketChat.MessageTypes.registerType
id: 'room_changed_description'
system: true
diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee
index 5d37e615521b..8939671627c6 100644
--- a/packages/rocketchat-channel-settings/client/views/channelSettings.coffee
+++ b/packages/rocketchat-channel-settings/client/views/channelSettings.coffee
@@ -145,6 +145,17 @@ Template.channelSettings.onCreated ->
toastr.success TAPi18n.__ 'Room_topic_changed_successfully'
RocketChat.callbacks.run 'roomTopicChanged', room
+ announcement:
+ type: 'markdown'
+ label: 'Announcement'
+ canView: (room) => true
+ canEdit: (room) => RocketChat.authz.hasAllPermission('edit-room', room._id)
+ save: (value, room) ->
+ Meteor.call 'saveRoomSettings', room._id, 'roomAnnouncement', value, (err, result) ->
+ return handleError err if err
+ toastr.success TAPi18n.__ 'Room_announcement_changed_successfully'
+ RocketChat.callbacks.run 'roomAnnouncementChanged', room
+
description:
type: 'text'
label: 'Description'
diff --git a/packages/rocketchat-channel-settings/package.js b/packages/rocketchat-channel-settings/package.js
index 3f42e734af3f..6bfe2c0b87b9 100644
--- a/packages/rocketchat-channel-settings/package.js
+++ b/packages/rocketchat-channel-settings/package.js
@@ -30,6 +30,7 @@ Package.onUse(function(api) {
'server/functions/saveReactWhenReadOnly.js',
'server/functions/saveRoomType.coffee',
'server/functions/saveRoomTopic.coffee',
+ 'server/functions/saveRoomAnnouncement.js',
'server/functions/saveRoomName.coffee',
'server/functions/saveRoomReadOnly.coffee',
'server/functions/saveRoomDescription.coffee',
diff --git a/packages/rocketchat-channel-settings/server/functions/saveRoomAnnouncement.js b/packages/rocketchat-channel-settings/server/functions/saveRoomAnnouncement.js
new file mode 100644
index 000000000000..e78663e9b6b7
--- /dev/null
+++ b/packages/rocketchat-channel-settings/server/functions/saveRoomAnnouncement.js
@@ -0,0 +1,13 @@
+RocketChat.saveRoomAnnouncement = function(rid, roomAnnouncement, user, sendMessage=true) {
+ if (!Match.test(rid, String)) {
+ throw new Meteor.Error('invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomAnnouncement' });
+ }
+
+ roomAnnouncement = s.escapeHTML(roomAnnouncement);
+ const updated = RocketChat.models.Rooms.setAnnouncementById(rid, roomAnnouncement);
+ if (updated && sendMessage) {
+ RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser('room_changed_announcement', rid, roomAnnouncement, user);
+ }
+
+ return updated;
+};
diff --git a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee
index f51a06949452..ee85e7950767 100644
--- a/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee
+++ b/packages/rocketchat-channel-settings/server/methods/saveRoomSettings.coffee
@@ -6,7 +6,7 @@ Meteor.methods
unless Match.test rid, String
throw new Meteor.Error 'error-invalid-room', 'Invalid room', { method: 'saveRoomSettings' }
- if setting not in ['roomName', 'roomTopic', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode']
+ if setting not in ['roomName', 'roomTopic', 'roomAnnouncement', 'roomDescription', 'roomType', 'readOnly', 'reactWhenReadOnly', 'systemMessages', 'default', 'joinCode']
throw new Meteor.Error 'error-invalid-settings', 'Invalid settings provided', { method: 'saveRoomSettings' }
unless RocketChat.authz.hasPermission(Meteor.userId(), 'edit-room', rid)
@@ -29,6 +29,9 @@ Meteor.methods
when 'roomTopic'
if value isnt room.topic
RocketChat.saveRoomTopic(rid, value, Meteor.user())
+ when 'roomAnnouncement'
+ if value isnt room.announcement
+ RocketChat.saveRoomAnnouncement(rid, value, Meteor.user())
when 'roomDescription'
if value isnt room.description
RocketChat.saveRoomDescription rid, value, Meteor.user()
diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json
index 733b6dfa4ae8..1be49c0ce93b 100644
--- a/packages/rocketchat-i18n/i18n/en.i18n.json
+++ b/packages/rocketchat-i18n/i18n/en.i18n.json
@@ -161,6 +161,7 @@
"and": "and",
"And_more": "And __length__ more",
"Animals_and_Nature": "Animals & Nature",
+ "Announcement": "Announcement",
"API": "API",
"API_Allow_Infinite_Count": "Allow Getting Everything",
"API_Allow_Infinite_Count_Description": "Should calls to the REST API be allowed to return everything in one call?",
@@ -1224,10 +1225,12 @@
"Role_Editing": "Role Editing",
"Role_removed": "Role removed",
"Room": "Room",
+ "Room_announcement_changed_successfully": "Room announcement changed successfully",
"Room_archivation_state": "State",
"Room_archivation_state_false": "Active",
"Room_archivation_state_true": "Archived",
"Room_archived": "Room archived",
+ "room_changed_announcement": "Room announcement changed to: __room_announcement__ by __user_by__",
"room_changed_description": "Room description changed to: __room_description__ by __user_by__",
"room_changed_privacy": "Room type changed to: __room_type__ by __user_by__",
"room_changed_topic": "Room topic changed to: __room_topic__ by __user_by__",
diff --git a/packages/rocketchat-i18n/i18n/zh.i18n.json b/packages/rocketchat-i18n/i18n/zh.i18n.json
index 145471928d18..b368a9701b4a 100644
--- a/packages/rocketchat-i18n/i18n/zh.i18n.json
+++ b/packages/rocketchat-i18n/i18n/zh.i18n.json
@@ -136,6 +136,7 @@
"and": "和",
"And_more": "以及其它 __length__ 条",
"Animals_and_Nature": "动物与自然",
+ "Announcement": "公告",
"API": "API",
"API_Analytics": "分析",
"API_Embed": "嵌入",
@@ -911,10 +912,12 @@
"Role_Editing": "编辑角色",
"Role_removed": "角色已删除",
"Room": "聊天室",
+ "Room_announcement_changed_successfully": "公告已成功修改",
"Room_archivation_state": "状态",
"Room_archivation_state_false": "活跃",
"Room_archivation_state_true": "已归档",
"Room_archived": "房间已归档",
+ "room_changed_announcement": "__user_by__ 将公告修改为:__room_announcement__",
"room_changed_description": "房间描述由 __user_by__ 修改为:__room_description__",
"room_changed_privacy": "__user_by__ 将房间类型修改为:__room_type__",
"room_changed_topic": "__user_by__ 将房间主题修改为:__room_topic__",
diff --git a/packages/rocketchat-lib/server/models/Rooms.coffee b/packages/rocketchat-lib/server/models/Rooms.coffee
index 0830b53f773d..928dde42caa8 100644
--- a/packages/rocketchat-lib/server/models/Rooms.coffee
+++ b/packages/rocketchat-lib/server/models/Rooms.coffee
@@ -499,6 +499,16 @@ class ModelRooms extends RocketChat.models._Base
return @update query, update
+ setAnnouncementById: (_id, announcement) ->
+ query =
+ _id: _id
+
+ update =
+ $set:
+ announcement: announcement
+
+ return @update query, update
+
muteUsernameByRoomId: (_id, username) ->
query =
_id: _id
diff --git a/packages/rocketchat-theme/client/imports/base.less b/packages/rocketchat-theme/client/imports/base.less
index 43c592daf016..97985515451f 100644
--- a/packages/rocketchat-theme/client/imports/base.less
+++ b/packages/rocketchat-theme/client/imports/base.less
@@ -1776,6 +1776,26 @@ label.required::after {
}
}
+.announcement {
+ margin-top: 61px;
+ height: 40px;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 1.2em;
+ background-color: #04436a;
+ color: white;
+ text-align: center;
+ display: block;
+
+ ~ .container-bars {
+ top: 95px;
+ }
+
+ ~ .messages-box {
+ margin-top: 100px;
+ }
+}
+
.cms-page {
max-width: 800px;
margin: 40px auto;
diff --git a/packages/rocketchat-ui-admin/client/rooms/adminRoomInfo.coffee b/packages/rocketchat-ui-admin/client/rooms/adminRoomInfo.coffee
index 62cda0ec7042..de3cea04e2db 100644
--- a/packages/rocketchat-ui-admin/client/rooms/adminRoomInfo.coffee
+++ b/packages/rocketchat-ui-admin/client/rooms/adminRoomInfo.coffee
@@ -137,6 +137,13 @@ Template.adminRoomInfo.onCreated ->
return handleError(err)
toastr.success TAPi18n.__ 'Room_topic_changed_successfully'
RocketChat.callbacks.run 'roomTopicChanged', AdminChatRoom.findOne(rid)
+ when 'roomAnnouncement'
+ if @validateRoomTopic(rid)
+ Meteor.call 'saveRoomSettings', rid, 'roomAnnouncement', @$('input[name=roomAnnouncement]').val(), (err, result) ->
+ if err
+ return handleError(err)
+ toastr.success TAPi18n.__ 'Room_announcement_changed_successfully'
+ RocketChat.callbacks.run 'roomAnnouncementChanged', AdminChatRoom.findOne(rid)
when 'roomType'
if @validateRoomType(rid)
RocketChat.callbacks.run 'roomTypeChanged', AdminChatRoom.findOne(rid)
diff --git a/packages/rocketchat-ui/client/lib/chatMessages.coffee b/packages/rocketchat-ui/client/lib/chatMessages.coffee
index 2b22a3b5f379..9af3ae555789 100644
--- a/packages/rocketchat-ui/client/lib/chatMessages.coffee
+++ b/packages/rocketchat-ui/client/lib/chatMessages.coffee
@@ -15,6 +15,7 @@ class @ChatMessages
resize: ->
dif = (if RocketChat.Layout.isEmbedded() then 0 else 60) + $(".messages-container").find("footer").outerHeight()
+ dif += if $(".announcement").length > 0 then 40 else 0
$(".messages-box").css
height: "calc(100% - #{dif}px)"
diff --git a/packages/rocketchat-ui/client/views/app/room.coffee b/packages/rocketchat-ui/client/views/app/room.coffee
index b2fd6090f87e..10a27d5e295a 100644
--- a/packages/rocketchat-ui/client/views/app/room.coffee
+++ b/packages/rocketchat-ui/client/views/app/room.coffee
@@ -90,6 +90,19 @@ Template.room.helpers
return '' unless roomData
return roomData.topic
+ showAnnouncement: ->
+ roomData = Session.get('roomData' + this._id)
+ return false unless roomData
+ Meteor.defer =>
+ if window.chatMessages and window.chatMessages[roomData._id]
+ window.chatMessages[roomData._id].resize()
+ return roomData.announcement isnt undefined and roomData.announcement isnt ''
+
+ roomAnnouncement: ->
+ roomData = Session.get('roomData' + this._id)
+ return '' unless roomData
+ return roomData.announcement
+
roomIcon: ->
roomData = Session.get('roomData' + this._id)
return '' unless roomData?.t
diff --git a/packages/rocketchat-ui/client/views/app/room.html b/packages/rocketchat-ui/client/views/app/room.html
index 3c07f859095d..c9bf8d2aa09b 100644
--- a/packages/rocketchat-ui/client/views/app/room.html
+++ b/packages/rocketchat-ui/client/views/app/room.html
@@ -8,20 +8,25 @@
{{#unless embeddedVersion}}
-
- {{> burger}}
-
- {{#if showToggleFavorite}}
-
- {{/if}}
-
- {{roomName}}
- {{#if isTranslated}}
-
- {{/if}}
- {{{RocketChatMarkdown roomTopic}}}
-
-
+
+ {{> burger}}
+
+ {{#if showToggleFavorite}}
+
+ {{/if}}
+
+ {{roomName}}
+ {{#if isTranslated}}
+
+ {{/if}}
+ {{{RocketChatMarkdown roomTopic}}}
+
+
+ {{#if showAnnouncement}}
+
+ {{{RocketChatMarkdown roomAnnouncement}}}
+
+ {{/if}}
{{/unless}}