27 | = Icon::get('chevron-down', [
28 | 'htmlOptions' => [
29 | 'id' => 'conversation-settings-button',
30 | 'data-bs-toggle' => 'dropdown',
31 | 'aria-haspopup' => 'true',
32 | 'aria-expanded' => 'false',
33 | ],
34 | ]) ?>
35 |
76 |
77 |
--------------------------------------------------------------------------------
/models/forms/ReplyForm.php:
--------------------------------------------------------------------------------
1 | [self::SCENARIO_HAS_FILES]],
44 | ['message', 'validateRecipients'],
45 | ];
46 | }
47 |
48 | public function validateRecipients($attribute)
49 | {
50 | if ($this->model->isBlocked()) {
51 | $this->addError($attribute, Yii::t('MailModule.base', 'You are not allowed to reply to users {userNames}!', [
52 | 'userNames' => implode(', ', $this->model->getBlockerNames()),
53 | ]));
54 | }
55 | }
56 |
57 | /**
58 | * Declares customized attribute labels.
59 | * If not declared here, an attribute would have a label that is
60 | * the same as its name with the first letter in upper case.
61 | */
62 | public function attributeLabels()
63 | {
64 | return [
65 | 'message' => Yii::t('MailModule.base', 'Message'),
66 | ];
67 | }
68 |
69 | public function getUrl()
70 | {
71 | return Url::toReply($this->model);
72 | }
73 |
74 | public function save()
75 | {
76 | if (!$this->validate()) {
77 | return false;
78 | }
79 |
80 | $this->reply = new MessageEntry([
81 | 'message_id' => $this->model->id,
82 | 'user_id' => Yii::$app->user->id,
83 | 'content' => $this->message,
84 | ]);
85 | if ($this->scenario === self::SCENARIO_HAS_FILES) {
86 | $this->reply->scenario = MessageEntry::SCENARIO_HAS_FILES;
87 | }
88 |
89 | if ($this->reply->save()) {
90 | $this->reply->refresh(); // Update created_by date, otherwise db expression is set...
91 | $this->reply->fileManager->attach(Yii::$app->request->post('fileList'));
92 | $this->reply->notify();
93 |
94 | // Update last viewed date to avoid marking the conversation as unread
95 | $userMessage = $this->model->getUserMessage($this->reply->user_id);
96 | if ($userMessage) {
97 | $userMessage->last_viewed = date('Y-m-d G:i:s');
98 | $userMessage->save();
99 | }
100 |
101 | return true;
102 | }
103 |
104 | return false;
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/controllers/rest/MessageController.php:
--------------------------------------------------------------------------------
1 | innerJoin('user_message', 'message_id = id')
35 | ->where(['user_id' => Yii::$app->user->id]);
36 |
37 | $pagination = $this->handlePagination($messagesQuery);
38 | foreach ($messagesQuery->all() as $message) {
39 | $results[] = RestDefinitions::getMessage($message);
40 | }
41 | return $this->returnPagination($messagesQuery, $pagination, $results);
42 | }
43 |
44 | /**
45 | * Get a mail conversation by id
46 | *
47 | * @param $id
48 | * @return array
49 | * @throws HttpException
50 | */
51 | public function actionView($id)
52 | {
53 | $message = static::getMessage($id);
54 | return RestDefinitions::getMessage($message);
55 | }
56 |
57 | /**
58 | * Create a mail conversation
59 | *
60 | * @return array
61 | * @throws \Throwable
62 | */
63 | public function actionCreate()
64 | {
65 | if (!Yii::$app->user->isAdmin() && !Yii::$app->user->getPermissionManager()->can(StartConversation::class)) {
66 | return $this->returnError(403, 'You cannot create conversations!');
67 | }
68 |
69 | $message = new CreateMessage();
70 | $message->load(['CreateMessage' => Yii::$app->request->post()]);
71 |
72 | if ($message->save()) {
73 | return $this->actionView($message->messageInstance->id);
74 | }
75 |
76 | if ($message->hasErrors()) {
77 | return $this->returnError(400, 'Validation failed', $message->getErrors());
78 | }
79 |
80 | Yii::error('Could not create validated conversation.', 'api');
81 | return $this->returnError(500, 'Internal error while save conversation!');
82 | }
83 |
84 | /**
85 | * Get conversation by id
86 | *
87 | * @param $id
88 | * @return Message
89 | * @throws HttpException
90 | */
91 | public static function getMessage($id)
92 | {
93 | $message = Message::findOne(['id' => $id]);
94 | if ($message === null) {
95 | throw new HttpException(404, 'Message not found!');
96 | }
97 |
98 | if (!$message->isParticipant(Yii::$app->user)) {
99 | throw new ForbiddenHttpException('You must be a participant of the conversation.');
100 | }
101 |
102 | return $message;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Module.php:
--------------------------------------------------------------------------------
1 | 6
25 | */
26 | public $inboxInitPageSize = 30;
27 |
28 | /**
29 | * @var int Defines the page size when loading more conversation page entries (autoscroller)
30 | */
31 | public $inboxUpdatePageSize = 5;
32 |
33 | /**
34 | * @var int Defines the initial message amount loaded for a conversation
35 | */
36 | public $conversationInitPageSize = 50;
37 |
38 | /**
39 | * @var int Defines the amount of messages loaded when loading more messages
40 | */
41 | public $conversationUpdatePageSize = 50;
42 |
43 | /**
44 | * @inheritdoc
45 | */
46 | public function init()
47 | {
48 | parent::init();
49 |
50 | if (Yii::$app instanceof ConsoleApplication) {
51 | // Prevents the Yii HelpCommand from crawling all web controllers and possibly throwing errors at REST endpoints if the REST module is not available.
52 | $this->controllerNamespace = 'mail/commands';
53 | }
54 | }
55 |
56 | /**
57 | * @return static
58 | */
59 | public static function getModuleInstance()
60 | {
61 | return Yii::$app->getModule('mail');
62 | }
63 |
64 | /**
65 | * @inheritdoc
66 | */
67 | public function getConfigUrl()
68 | {
69 | return Url::toConfig();
70 | }
71 |
72 | /**
73 | * @inheritdoc
74 | */
75 | public function getPermissions($contentContainer = null)
76 | {
77 | if (!$contentContainer) {
78 | return [
79 | new StartConversation(),
80 | ];
81 | } elseif ($contentContainer instanceof User) {
82 | return [
83 | new SendMail(),
84 | ];
85 | }
86 |
87 | return [];
88 | }
89 |
90 | public function getNotifications()
91 | {
92 | return [
93 | MailNotification::class,
94 | ConversationNotification::class,
95 | ];
96 | }
97 |
98 | /**
99 | * Determines showInTopNav is enabled or not
100 | *
101 | * @return bool is showInTopNav enabled
102 | */
103 | public function hideInTopNav()
104 | {
105 | return !$this->settings->get('showInTopNav', false);
106 | }
107 |
108 | /**
109 | * @inheritdoc
110 | */
111 | public function disable()
112 | {
113 | foreach (MessageEntry::find()->each() as $messageEntry) {
114 | $messageEntry->delete();
115 | }
116 |
117 | parent::disable();
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/tests/codeception/unit/UserMessageTagTest.php:
--------------------------------------------------------------------------------
1 | becomeUser('User1');
15 | $user2 = User::findOne(['id' => 3]);
16 |
17 | $message = new CreateMessage([
18 | 'message' => 'Hey!',
19 | 'title' => 'Test Conversation',
20 | 'recipient' => [$user2->guid],
21 | 'tags' => $tags,
22 | ]);
23 |
24 | $this->assertTrue($message->save());
25 |
26 | return $message;
27 | }
28 |
29 | public function testSingleTagIsCreatedOnMessageCreation()
30 | {
31 | $message = $this->createMessage(['_add:TestTag']);
32 |
33 | $this->assertCount(7, MessageTag::find()->all());
34 | $this->assertCount(7, UserMessageTag::find()->all());
35 |
36 | /** @var MessageTag[] $tag */
37 | $tags = MessageTag::findByMessage(Yii::$app->user->id, $message->messageInstance)->all();
38 | $this->assertNotNull($tags);
39 | $this->assertCount(1, $tags);
40 | $this->assertEquals(Yii::$app->user->id, $tags[0]->user_id);
41 | $this->assertEquals('TestTag', $tags[0]->name);
42 | }
43 |
44 | public function testMultipleTagIsCreatedOnMessageCreation()
45 | {
46 | $message = $this->createMessage(['_add:TestTag', '_add:TestTag2']);
47 |
48 | $this->assertCount(8, MessageTag::find()->all());
49 | $this->assertCount(8, UserMessageTag::find()->all());
50 |
51 | /** @var MessageTag[] $tag */
52 | $tags = MessageTag::findByMessage(Yii::$app->user->id, $message->messageInstance)->all();
53 | $this->assertNotNull($tags);
54 | $this->assertCount(2, $tags);
55 | $this->assertEquals(Yii::$app->user->id, $tags[0]->user_id);
56 | $this->assertEquals(Yii::$app->user->id, $tags[1]->user_id);
57 | $this->assertEquals('TestTag', $tags[0]->name);
58 | $this->assertEquals('TestTag2', $tags[1]->name);
59 | }
60 |
61 | public function testDuplicateTagIsAttachedOnlyOnce()
62 | {
63 | $message = $this->createMessage(['_add:TestTag', '_add:TestTag']);
64 |
65 | $this->assertCount(7, MessageTag::find()->all());
66 | $this->assertCount(7, UserMessageTag::find()->all());
67 |
68 | /** @var MessageTag[] $tag */
69 | $tags = MessageTag::findByMessage(Yii::$app->user->id, $message->messageInstance)->all();
70 | $this->assertNotNull($tags);
71 | $this->assertCount(1, $tags);
72 | $this->assertEquals(Yii::$app->user->id, $tags[0]->user_id);
73 | $this->assertEquals('TestTag', $tags[0]->name);
74 | }
75 |
76 | public function testMissingTagsAreDeletedOnAttach()
77 | {
78 | $message = $this->createMessage(['_add:TestTag', '_add:TestTag2']);
79 |
80 | $tags = MessageTag::findByMessage(Yii::$app->user->id, $message->messageInstance)->all();
81 | $editForm = new ConversationTagsForm(['message' => $message->messageInstance, 'tags' => [$tags[0]]]);
82 | $editForm->save();
83 |
84 | $updatedTags = MessageTag::findByMessage(Yii::$app->user->id, $message->messageInstance)->all();
85 | $this->assertCount(1, $updatedTags);
86 | $this->assertEquals('TestTag', $updatedTags[0]->name);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/resources/js/humhub.mail.conversation.js:
--------------------------------------------------------------------------------
1 | humhub.module('mail.conversation', function (module, require, $) {
2 | var Widget = require('ui.widget').Widget;
3 | var modal = require('ui.modal');
4 | var client = require('client');
5 | var event = require('event');
6 | var mail = require('mail.notification');
7 |
8 | var submitEditEntry = function (evt) {
9 | modal.submit(evt).then(function (response) {
10 | if (response.success) {
11 | var entry = getEntry(evt.$trigger.data('entry-id'));
12 | if (entry) {
13 | setTimeout(function () {
14 | entry.replace(response.content);
15 | }, 300)
16 | }
17 |
18 | return;
19 | }
20 |
21 | module.log.error(null, true);
22 | }).catch(function (e) {
23 | module.log.error(e, true);
24 | });
25 | };
26 |
27 | var deleteEntry = function (evt) {
28 | var entry = getEntry(evt.$trigger.data('entry-id'));
29 |
30 | if (!entry) {
31 | module.log.error(null, true);
32 | return;
33 | }
34 |
35 | client.post(entry.options.deleteUrl).then(function (response) {
36 | modal.global.close();
37 |
38 | if (response.success) {
39 | setTimeout(function () {
40 | entry.remove();
41 | }, 1000);
42 | }
43 | }).catch(function (e) {
44 | module.log.error(e, true);
45 | });
46 | };
47 |
48 | var getEntry = function (id) {
49 | return Widget.instance('.mail-conversation-entry[data-entry-id="' + id + '"]');
50 | };
51 |
52 | var getRootView = function () {
53 | return Widget.instance('#mail-conversation-root');
54 | };
55 |
56 | var init = function () {
57 | event.on('humhub:modules:mail:live:NewUserMessage', function (evt, events) {
58 | if(!$('#inbox').length) {
59 | return;
60 | }
61 |
62 | var root = getRootView();
63 | var updated = false;
64 | var updatedMessages = [];
65 | events.forEach(function (event) {
66 | updatedMessages.push(event.data.message_id);
67 | if (!updated && root && root.options.messageId == event.data.message_id) {
68 | root.loadUpdate();
69 | updated = true;
70 | root.markSeen(event.data.message_id);
71 | }
72 | });
73 |
74 | Widget.instance('#inbox').updateEntries(updatedMessages);
75 | }).on('humhub:modules:mail:live:UserMessageDeleted', function (evt, events, update) {
76 | if(!$('#inbox').length) {
77 | return;
78 | }
79 |
80 | events.forEach(function (event) {
81 | var entry = getEntry(event.data.entry_id);
82 | if (entry) {
83 | entry.remove();
84 | }
85 | mail.setMailMessageCount(event.data.count);
86 | });
87 | });
88 | };
89 |
90 | var linkAction = function (evt) {
91 | client.post(evt).then(function (response) {
92 | if (response.redirect) {
93 | client.pjax.redirect(response.redirect);
94 | }
95 | }).catch(function (e) {
96 | module.log.error(e, true);
97 | });
98 | };
99 |
100 | module.export({
101 | init,
102 | linkAction,
103 | submitEditEntry,
104 | deleteEntry,
105 | });
106 | });
107 |
--------------------------------------------------------------------------------
/resources/js/humhub.mail.notification.js:
--------------------------------------------------------------------------------
1 | humhub.module('mail.notification', function (module, require, $) {
2 | var client = require('client');
3 | var loader = require('ui.loader');
4 | var event = require('event');
5 | var Widget = require('ui.widget').Widget;
6 | var currentXhr;
7 | var newMessageCount = 0;
8 |
9 | module.initOnPjaxLoad = true;
10 |
11 | var init = function (isPjax) {
12 | // open the messages menu
13 | if (!isPjax) {
14 | event.on('humhub:modules:mail:live:NewUserMessage', function (evt, events) {
15 | var evtx = events[events.length - 1];
16 | setMailMessageCount(evtx.data.count);
17 | }).on('humhub:modules:mail:live:UserMessageDeleted', function (evt, events) {
18 | var evtx = events[events.length - 1];
19 | setMailMessageCount(evtx.data.count);
20 | });
21 |
22 |
23 | $('#icon-messages').click(function () {
24 | if (currentXhr) {
25 | currentXhr.abort();
26 | }
27 |
28 | const messageLoader = $('#loader_messages');
29 | const messageList = messageLoader.parent();
30 |
31 | // remove all entries from dropdown
32 | messageLoader.parent().find(':not(#loader_messages)').remove();
33 | loader.set(messageLoader.removeClass('d-none'));
34 |
35 | client.get(module.config.url.list, {
36 | beforeSend: function (xhr) {
37 | currentXhr = xhr;
38 | }
39 | }).then(function (response) {
40 | currentXhr = undefined;
41 | messageList.prepend($(response.html));
42 | messageLoader.addClass('d-none');
43 | messageList.niceScroll({
44 | cursorwidth: '7',
45 | cursorborder: '',
46 | cursorcolor: '#555',
47 | cursoropacitymax: '0.2',
48 | nativeparentscrolling: false,
49 | railpadding: {top: 0, right: 3, left: 0, bottom: 0}
50 | });
51 | });
52 | });
53 | }
54 |
55 | updateCount();
56 | };
57 |
58 | var updateCount = function () {
59 | client.get(module.config.url.count).then(function (response) {
60 | setMailMessageCount(parseInt(response.newMessages));
61 | });
62 | };
63 |
64 | var setMailMessageCount = function (count) {
65 | // show or hide the badge for new messages
66 | var $badge = $('#badge-messages');
67 | if (!count || parseInt(count) === 0) {
68 | $badge.addClass('d-none');
69 | newMessageCount = 0;
70 | } else {
71 | $badge.removeClass('d-none');
72 | newMessageCount = count;
73 | $badge.empty();
74 | $badge.append(count);
75 | $badge.fadeIn('fast');
76 | }
77 |
78 | event.trigger('humhub:modules:notification:UpdateTitleNotificationCount');
79 | };
80 |
81 | var loadMessage = function (evt) {
82 | var root = Widget.instance('#mail-conversation-root');
83 | if (root && typeof(root.loadMessage) === 'function') {
84 | root.loadMessage(evt);
85 | root.$.closest('.container').addClass('mail-conversation-single-message');
86 | } else {
87 | client.redirect(evt.url);
88 | }
89 | evt.finish();
90 | };
91 |
92 | var getNewMessageCount = function () {
93 | return newMessageCount;
94 | };
95 |
96 | module.export({
97 | init: init,
98 | loadMessage: loadMessage,
99 | setMailMessageCount: setMailMessageCount,
100 | updateCount: updateCount,
101 | getNewMessageCount: getNewMessageCount,
102 | });
103 | });
104 |
--------------------------------------------------------------------------------
/controllers/TagController.php:
--------------------------------------------------------------------------------
1 | render('manage', ['model' => new AddTag()]);
40 | }
41 |
42 | public function actionAdd()
43 | {
44 | $model = new AddTag();
45 | $model->load(Yii::$app->request->post());
46 | if ($model->save()) {
47 | $model = new AddTag();
48 | }
49 | return $this->render('manage', ['model' => $model]);
50 | }
51 |
52 | public function actionEdit($id)
53 | {
54 | $tag = $this->findTag($id);
55 |
56 | if ($tag->load(Yii::$app->request->post()) && $tag->save()) {
57 | return ModalClose::widget(['reload' => true]);
58 | }
59 |
60 | return $this->renderAjax('editModal', ['model' => $tag]);
61 |
62 | }
63 |
64 | /**
65 | * @param $id
66 | * @return MessageTag
67 | * @throws NotFoundHttpException
68 | */
69 | private function findTag($id)
70 | {
71 | $tag = MessageTag::findByUser(Yii::$app->user->id)->andWhere(['id' => $id])->one();
72 |
73 | if (!$tag) {
74 | throw new NotFoundHttpException();
75 | }
76 |
77 | return $tag;
78 | }
79 |
80 | /**
81 | * @param $id
82 | * @return TagController|\yii\console\Response|\yii\web\Response
83 | * @throws NotFoundHttpException
84 | * @throws \Throwable
85 | * @throws \yii\db\StaleObjectException
86 | * @throws \yii\web\HttpException
87 | */
88 | public function actionDelete($id)
89 | {
90 | $this->forcePostRequest();
91 | $this->findTag($id)->delete();
92 | return $this->redirect(Url::toManageTags());
93 | }
94 |
95 | public function actionSearch($keyword)
96 | {
97 | $results = MessageTag::search(Yii::$app->user->id, $keyword);
98 |
99 | return $this->asJson(array_map(fn(MessageTag $tag) => ['id' => $tag->id, 'text' => $tag->name, 'image' => ConversationTagPicker::getIcon()], $results));
100 | }
101 |
102 | public function actionEditConversation($messageId)
103 | {
104 | $message = Message::findOne(['id' => $messageId]);
105 |
106 | if (!$message) {
107 | throw new NotFoundHttpException();
108 | }
109 |
110 | if (!$message->isParticipant(Yii::$app->user->getIdentity())) {
111 | throw new ForbiddenHttpException();
112 | }
113 |
114 | $model = new ConversationTagsForm(['message' => $message]);
115 |
116 | if ($model->load(Yii::$app->request->post()) && $model->save()) {
117 | return ModalClose::widget([
118 | 'script' => '$("#' . ConversationTags::ID . '").replaceWith(\'' . ConversationTags::widget(['message' => $message]) . '\');',
119 | ]);
120 | }
121 |
122 | return $this->renderAjax('editConversationTagsModal', ['model' => new ConversationTagsForm(['message' => $message])]);
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/models/forms/InviteParticipantForm.php:
--------------------------------------------------------------------------------
1 | Yii::t('MailModule.base', 'Recipient'),
58 | ];
59 | }
60 |
61 | /**
62 | * Form Validator which checks the recipient field
63 | *
64 | * @param type $attribute
65 | * @param type $params
66 | */
67 | public function checkRecipient($attribute, $params)
68 | {
69 | foreach ($this->recipients as $userGuid) {
70 | $user = User::findOne(['guid' => $userGuid]);
71 | if ($user) {
72 | $name = Html::encode($user->getDisplayName());
73 | if (Yii::$app->user->identity->is($user)) {
74 | $this->addError($attribute, Yii::t('MailModule.base', "You cannot send a email to yourself!"));
75 | } elseif ($this->message->isParticipant($user)) {
76 | $this->addError($attribute, Yii::t('MailModule.base', "User {name} is already participating!", ['name' => $name]));
77 | } elseif (!$user->can(SendMail::class) && !Yii::$app->user->isAdmin()) {
78 | $this->addError($attribute, Yii::t('MailModule.base', "You are not allowed to send user {name} is already!", ['name' => $name]));
79 | } else {
80 | $this->recipientUsers[] = $user;
81 | }
82 | }
83 | }
84 | }
85 |
86 | public function getPickerUrl()
87 | {
88 | return Url::toSearchNewParticipants($this->message);
89 | }
90 |
91 | public function getUrl()
92 | {
93 | return Url::toAddParticipant($this->message);
94 | }
95 |
96 | public function save()
97 | {
98 | if (!$this->validate()) {
99 | return false;
100 | }
101 |
102 | foreach ($this->recipientUsers as $user) {
103 | $userMessage = new UserMessage([
104 | 'message_id' => $this->message->id,
105 | 'user_id' => $user->id,
106 | 'is_originator' => 0,
107 | ]);
108 |
109 | if ($userMessage->save()) {
110 | $this->message->refresh();
111 | (new MessageNotification($this->message))
112 | ->setEntrySender(Yii::$app->user->getIdentity())
113 | ->notifyAll();
114 | }
115 | }
116 |
117 | unset($this->message->users);
118 | return true;
119 | }
120 |
121 | /**
122 | * Returns an Array with selected recipients
123 | */
124 | public function getRecipients()
125 | {
126 | return $this->recipients;
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/views/tag/manage.php:
--------------------------------------------------------------------------------
1 | MessageTag::findByUser(Yii::$app->user->id)
22 | ])
23 |
24 | ?>
25 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
37 |
38 | = Yii::t('MailModule.base', 'Here you can manage your private conversation tags.') ?>
39 | = Yii::t('MailModule.base', 'Conversation tags can be used to filter conversations and are only visible to you.') ?>
40 |
41 |
42 | Url::toAddTag()]); ?>
43 |
44 |
45 | = Html::activeTextInput($model->tag, 'name', ['style' => 'height:36px', 'class' => 'form-control', 'placeholder' => Yii::t('MailModule.base', 'Add Tag')]) ?>
46 | = Button::light()->icon('fa-plus')->loader()->submit() ?>
47 |
48 |
49 | = Html::error($model->tag, 'name') ?>
50 |
51 |
52 |
53 |
54 | = GridView::widget([
55 | 'dataProvider' => $dataProvider,
56 | 'options' => ['class' => 'grid-view', 'style' => 'padding-top:0'],
57 | 'tableOptions' => ['class' => 'table table-hover'],
58 | 'showHeader' => false,
59 | 'summary' => false,
60 | 'columns' => [
61 | 'name',
62 | [
63 | 'header' => Yii::t('base', 'Actions'),
64 | 'class' => ActionColumn::class,
65 | 'options' => ['width' => '80px'],
66 | 'contentOptions' => ['style' => 'text-align:right'],
67 | 'buttons' => [
68 | 'update' => fn($url, $model) =>
69 | /* @var $model Topic */
70 | ModalButton::primary()->load(Url::toEditTag($model->id))->icon('fa-pencil')->sm()->loader(false),
71 | 'view' => fn() => '',
72 | 'delete' => fn($url, $model) =>
73 | /* @var $model Topic */
74 | Button::danger()->icon('fa-times')->action('client.post', Url::toDeleteTag($model->id))->confirm(
75 | Yii::t('MailModule.base', '
Confirm tag deletion'),
76 | Yii::t('MailModule.base', 'Do you really want to delete this tag?'),
77 | Yii::t('base', 'Delete'))->sm()->loader(false),
78 | ],
79 | ],
80 | ]]) ?>
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/widgets/ConversationEntry.php:
--------------------------------------------------------------------------------
1 | entry->type === MessageEntry::type()) {
52 | return $this->runMessage();
53 | }
54 |
55 | return $this->runState();
56 | }
57 |
58 | public function runMessage(): string
59 | {
60 | $showUser = $this->showUser();
61 |
62 | return $this->render('conversationEntry', [
63 | 'entry' => $this->entry,
64 | 'contentClass' => $this->getContentClass(),
65 | 'showUser' => $showUser,
66 | 'userColor' => $showUser ? $this->getUserColor() : null,
67 | 'showDateBadge' => $this->showDateBadge(),
68 | 'options' => $this->getOptions(),
69 | 'isOwnMessage' => $this->isOwnMessage(),
70 | ]);
71 | }
72 |
73 | public function runState(): string
74 | {
75 | return $this->render('conversationState', [
76 | 'entry' => $this->entry,
77 | 'showDateBadge' => $this->showDateBadge(),
78 | ]);
79 | }
80 |
81 | private function getContentClass(): string
82 | {
83 | $result = 'conversation-entry-content';
84 |
85 | if ($this->isOwnMessage()) {
86 | $result .= ' own';
87 | }
88 |
89 | return $result;
90 | }
91 |
92 | private function isOwnMessage(): bool
93 | {
94 | return $this->entry->user->is(Yii::$app->user->getIdentity());
95 | }
96 |
97 | public function getData()
98 | {
99 | return [
100 | 'entry-id' => $this->entry->id,
101 | 'delete-url' => Url::toDeleteMessageEntry($this->entry),
102 | ];
103 | }
104 |
105 | public function getAttributes()
106 | {
107 | $result = [
108 | 'class' => 'media mail-conversation-entry',
109 | ];
110 |
111 | if ($this->isOwnMessage()) {
112 | Html::addCssClass($result, 'own');
113 | }
114 |
115 | if ($this->isPrevEntryFromSameUser()) {
116 | Html::addCssClass($result, 'hideUserInfo');
117 | }
118 |
119 | return $result;
120 | }
121 |
122 | private function isPrevEntryFromSameUser(): bool
123 | {
124 | return $this->prevEntry && $this->prevEntry->created_by === $this->entry->created_by;
125 | }
126 |
127 | private function showUser(): bool
128 | {
129 | return !$this->isOwnMessage();
130 | }
131 |
132 | private function getUserColor(): string
133 | {
134 | return $this->userColors[$this->entry->created_by % count($this->userColors)];
135 | }
136 |
137 | private function showDateBadge(): bool
138 | {
139 | if (!$this->showDateBadge) {
140 | return false;
141 | }
142 |
143 | if (!$this->prevEntry) {
144 | return true;
145 | }
146 |
147 | $previousEntryDay = Yii::$app->formatter->asDatetime($this->prevEntry->created_at, 'php:Y-m-d');
148 | $currentEntryDay = Yii::$app->formatter->asDatetime($this->entry->created_at, 'php:Y-m-d');
149 |
150 | return $previousEntryDay !== $currentEntryDay;
151 | }
152 |
153 | }
154 |
--------------------------------------------------------------------------------
/tests/codeception/api/EntryCest.php:
--------------------------------------------------------------------------------
1 | isRestModuleEnabled()) {
13 | return;
14 | }
15 |
16 | $I->wantTo('see entries of the conversation by id');
17 | $I->amAdmin();
18 | $I->seePaginationGetResponse('mail/3/entries', [
19 | ['id' => 4, 'content' => 'Third Message entry text 1.', 'user_id' => 1],
20 | ['id' => 5, 'content' => 'Third Message entry text 2.', 'user_id' => 2],
21 | ['id' => 6, 'content' => 'Third Message entry text 3.', 'user_id' => 3],
22 | ]);
23 | }
24 |
25 | public function testGetById(ApiTester $I)
26 | {
27 | if (!$this->isRestModuleEnabled()) {
28 | return;
29 | }
30 |
31 | $I->wantTo('see entry by id');
32 | $I->amUser1();
33 | $I->sendGet('mail/2/entry/3');
34 | $I->seeSuccessResponseContainsJson([
35 | 'id' => 3,
36 | 'user_id' => 2,
37 | 'content' => 'Second Message entry text 2.',
38 | ]);
39 | }
40 |
41 | public function testCreateEntry(ApiTester $I)
42 | {
43 | if (!$this->isRestModuleEnabled()) {
44 | return;
45 | }
46 |
47 | $I->wantTo('create entry');
48 | $I->amUser1();
49 | $newMessage = 'New sample reply for conversation #2';
50 | $I->sendPost('mail/2/entry', ['message' => $newMessage]);
51 | $I->seeSuccessResponseContainsJson([
52 | 'id' => 7,
53 | 'user_id' => 2,
54 | 'content' => $newMessage,
55 | ]);
56 | }
57 |
58 | public function testCreateEntryByNotParticipant(ApiTester $I)
59 | {
60 | if (!$this->isRestModuleEnabled()) {
61 | return;
62 | }
63 |
64 | $I->wantTo('cannot create entry by not participant');
65 | $I->amUser3();
66 | $newMessage = 'New sample reply for conversation #2';
67 | $I->sendPost('mail/2/entry', ['message' => $newMessage]);
68 | $I->seeForbiddenResponseContainsJson([
69 | 'message' => 'You must be a participant of the conversation.',
70 | ]);
71 | }
72 |
73 | public function testUpdateEntry(ApiTester $I)
74 | {
75 | if (!$this->isRestModuleEnabled()) {
76 | return;
77 | }
78 |
79 | $I->wantTo('update entry by id');
80 | $I->amAdmin();
81 | $updatedMessage = 'Updated content of the entry #4';
82 | $I->sendPut('mail/3/entry/4', ['content' => $updatedMessage]);
83 | $I->seeSuccessResponseContainsJson([
84 | 'id' => 4,
85 | 'user_id' => 1,
86 | 'content' => $updatedMessage,
87 | ]);
88 | }
89 |
90 | public function testCannotUpdateEntry(ApiTester $I)
91 | {
92 | if (!$this->isRestModuleEnabled()) {
93 | return;
94 | }
95 |
96 | $I->wantTo('cannot update not own entry');
97 | $I->amUser1();
98 | $updatedMessage = 'Updated content of the entry #2';
99 | $I->sendPut('mail/3/entry/4', ['content' => $updatedMessage]);
100 | $I->seeForbiddenResponseContainsJson([
101 | 'message' => 'You cannot edit the conversation entry!',
102 | ]);
103 | }
104 |
105 | public function testDeleteEntry(ApiTester $I)
106 | {
107 | if (!$this->isRestModuleEnabled()) {
108 | return;
109 | }
110 |
111 | $I->wantTo('delete entry');
112 | $I->amUser1();
113 | $I->sendDelete('mail/3/entry/5');
114 | $I->seeSuccessResponseContainsJson([
115 | 'message' => 'Conversation entry successfully deleted!',
116 | ]);
117 | }
118 |
119 | public function testCannotDeleteEntry(ApiTester $I)
120 | {
121 | if (!$this->isRestModuleEnabled()) {
122 | return;
123 | }
124 |
125 | $I->wantTo('cannot delete not own entry');
126 | $I->amAdmin();
127 | $I->sendDelete('mail/3/entry/6');
128 | $I->seeForbiddenResponseContainsJson([
129 | 'message' => 'You cannot delete the conversation entry!',
130 | ]);
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/messages/am/base.php:
--------------------------------------------------------------------------------
1 | Confirm deleting conversation' => '',
4 | '
Confirm leaving conversation' => '',
5 | '
Confirm message deletion' => '',
6 | '
Confirm tag deletion' => '',
7 | '
Edit conversation tags' => '',
8 | '
Edit tag' => '',
9 | '
Manage conversation tags' => '',
10 | '
Messenger module configuration' => '',
11 | '
New conversation' => '',
12 | '
New message' => '',
13 | 'A tag with the same name already exists.' => '',
14 | 'Add Tag' => '',
15 | 'Add participants' => '',
16 | 'Add recipients' => '',
17 | 'Add user' => '',
18 | 'Advanced Messages Search' => '',
19 | 'Allow others to send you private messages' => '',
20 | 'Allow users to start new conversations' => '',
21 | 'Cancel' => 'ይቅር',
22 | 'Confirm' => 'አረጋግጥ',
23 | 'Conversation' => '',
24 | 'Conversation tags can be used to filter conversations and are only visible to you.' => '',
25 | 'Conversations' => '',
26 | 'Created At' => '',
27 | 'Created By' => '',
28 | 'Delete' => 'አስወግድ',
29 | 'Delete conversation' => '',
30 | 'Do you really want to delete this conversation?' => '',
31 | 'Do you really want to delete this message?' => '',
32 | 'Do you really want to delete this tag?' => '',
33 | 'Do you really want to leave this conversation?' => '',
34 | 'Edit' => 'ማስተካከያ',
35 | 'Edit message entry' => '',
36 | 'Edit message...' => '',
37 | 'Filter' => 'አጣራ',
38 | 'Friday' => '',
39 | 'Here you can manage your private conversation tags.' => '',
40 | 'Is Originator' => '',
41 | 'Last Viewed' => '',
42 | 'Leave' => '',
43 | 'Leave conversation' => '',
44 | 'Leave fields blank in order to disable a restriction.' => '',
45 | 'Manage Tags' => '',
46 | 'Mark Unread' => '',
47 | 'Max messages allowed per day' => '',
48 | 'Max number of messages allowed for a new user per day' => '',
49 | 'Max number of new conversations allowed for a new user per day' => '',
50 | 'Max number of new conversations allowed for a user per day' => '',
51 | 'Message' => 'መልዕክት',
52 | 'Messages' => '',
53 | 'Monday' => '',
54 | 'My Tags' => '',
55 | 'New conversation from {senderName}' => '',
56 | 'New message from {senderName}' => '',
57 | 'Participants' => '',
58 | 'Pin' => '',
59 | 'Pinned' => 'የተሰካ',
60 | 'Receive Notifications when someone opens a new conversation.' => '',
61 | 'Receive Notifications when someone sends you a message.' => '',
62 | 'Receive private messages' => '',
63 | 'Recipient' => '',
64 | 'Reply now' => '',
65 | 'Saturday' => '',
66 | 'Search' => 'ፈልግ',
67 | 'Send' => '',
68 | 'Send message' => '',
69 | 'Seperate restrictions for new users' => '',
70 | 'Show all messages' => '',
71 | 'Show menu item in top Navigation' => '',
72 | 'Start new conversations' => '',
73 | 'Subject' => 'ርዕስ',
74 | 'Sunday' => '',
75 | 'Tags' => '',
76 | 'There are no messages yet.' => '',
77 | 'This user is already participating in this conversation.' => '',
78 | 'Thursday' => '',
79 | 'Title' => 'ርዕስ',
80 | 'Today' => '',
81 | 'Tuesday' => '',
82 | 'Unpin' => 'ንቀል',
83 | 'Until a user is member since (days)' => '',
84 | 'Updated At' => '',
85 | 'Updated By' => '',
86 | 'User' => 'ተጠቃሚ',
87 | 'User {name} is already participating!' => '',
88 | 'Wednesday' => '',
89 | 'Write a message...' => '',
90 | 'Yesterday' => '',
91 | 'You' => '',
92 | 'You are not allowed to participate in this conversation. You have been blocked by: {userNames}.' => '',
93 | 'You are not allowed to reply to users {userNames}!' => '',
94 | 'You are not allowed to send user {name} is already!' => '',
95 | 'You are not allowed to start a conversation with this user.' => '',
96 | 'You are not allowed to start a conversation with {userName}!' => '',
97 | 'You cannot send a email to yourself!' => '',
98 | 'You cannot send a message to yourself!' => '',
99 | 'You cannot send a message without recipients!' => '',
100 | 'You joined the conversation.' => '',
101 | 'You left the conversation.' => '',
102 | 'You\'ve exceeded your daily amount of new conversations.' => '',
103 | 'edited' => '',
104 | '{n,plural,=1{# other} other{# others}}' => '',
105 | '{senderName} created a new conversation {conversationTitle}' => '',
106 | '{senderName} sent you a new message in {conversationTitle}' => '',
107 | '{username} joined the conversation.' => '',
108 | '{username} left the conversation.' => '',
109 | ];
110 |
--------------------------------------------------------------------------------
/messages/ko/base.php:
--------------------------------------------------------------------------------
1 | Confirm deleting conversation' => '',
4 | '
Confirm leaving conversation' => '',
5 | '
Confirm message deletion' => '',
6 | '
Confirm tag deletion' => '',
7 | '
Edit conversation tags' => '',
8 | '
Edit tag' => '',
9 | '
Manage conversation tags' => '',
10 | '
Messenger module configuration' => '',
11 | '
New conversation' => '',
12 | '
New message' => '',
13 | 'A tag with the same name already exists.' => '',
14 | 'Add Tag' => '',
15 | 'Add participants' => '',
16 | 'Add recipients' => '',
17 | 'Add user' => '',
18 | 'Advanced Messages Search' => '',
19 | 'Allow others to send you private messages' => '',
20 | 'Allow users to start new conversations' => '',
21 | 'Cancel' => '취소',
22 | 'Confirm' => '확인',
23 | 'Conversation' => '',
24 | 'Conversation tags can be used to filter conversations and are only visible to you.' => '',
25 | 'Conversations' => '',
26 | 'Created At' => '만든 위치',
27 | 'Created By' => '만든 사람',
28 | 'Delete' => '삭제',
29 | 'Delete conversation' => '',
30 | 'Do you really want to delete this conversation?' => '',
31 | 'Do you really want to delete this message?' => '',
32 | 'Do you really want to delete this tag?' => '',
33 | 'Do you really want to leave this conversation?' => '',
34 | 'Edit' => '편집',
35 | 'Edit message entry' => '',
36 | 'Edit message...' => '',
37 | 'Filter' => '필터',
38 | 'Friday' => '',
39 | 'Here you can manage your private conversation tags.' => '',
40 | 'Is Originator' => '',
41 | 'Last Viewed' => '',
42 | 'Leave' => '',
43 | 'Leave conversation' => '',
44 | 'Leave fields blank in order to disable a restriction.' => '',
45 | 'Manage Tags' => '',
46 | 'Mark Unread' => '',
47 | 'Max messages allowed per day' => '',
48 | 'Max number of messages allowed for a new user per day' => '',
49 | 'Max number of new conversations allowed for a new user per day' => '',
50 | 'Max number of new conversations allowed for a user per day' => '',
51 | 'Message' => '',
52 | 'Messages' => '',
53 | 'Monday' => '',
54 | 'My Tags' => '',
55 | 'New conversation from {senderName}' => '',
56 | 'New message from {senderName}' => '',
57 | 'Participants' => '',
58 | 'Pin' => '',
59 | 'Pinned' => '고정',
60 | 'Receive Notifications when someone opens a new conversation.' => '',
61 | 'Receive Notifications when someone sends you a message.' => '',
62 | 'Receive private messages' => '',
63 | 'Recipient' => '',
64 | 'Reply now' => '',
65 | 'Saturday' => '',
66 | 'Search' => '검색',
67 | 'Send' => '보내기',
68 | 'Send message' => '',
69 | 'Seperate restrictions for new users' => '',
70 | 'Show all messages' => '',
71 | 'Show menu item in top Navigation' => '',
72 | 'Start new conversations' => '',
73 | 'Subject' => '',
74 | 'Sunday' => '',
75 | 'Tags' => 'ㅡㅡ',
76 | 'There are no messages yet.' => '',
77 | 'This user is already participating in this conversation.' => '',
78 | 'Thursday' => '',
79 | 'Title' => '제목',
80 | 'Today' => '',
81 | 'Tuesday' => '',
82 | 'Unpin' => '고정 해제',
83 | 'Until a user is member since (days)' => '',
84 | 'Updated At' => '업데이트 날짜',
85 | 'Updated By' => '업데이트 작성자',
86 | 'User' => '사용자',
87 | 'User {name} is already participating!' => '',
88 | 'Wednesday' => '',
89 | 'Write a message...' => '',
90 | 'Yesterday' => '',
91 | 'You' => '당신',
92 | 'You are not allowed to participate in this conversation. You have been blocked by: {userNames}.' => '',
93 | 'You are not allowed to reply to users {userNames}!' => '',
94 | 'You are not allowed to send user {name} is already!' => '',
95 | 'You are not allowed to start a conversation with this user.' => '',
96 | 'You are not allowed to start a conversation with {userName}!' => '',
97 | 'You cannot send a email to yourself!' => '',
98 | 'You cannot send a message to yourself!' => '',
99 | 'You cannot send a message without recipients!' => '',
100 | 'You joined the conversation.' => '',
101 | 'You left the conversation.' => '',
102 | 'You\'ve exceeded your daily amount of new conversations.' => '',
103 | 'edited' => '',
104 | '{n,plural,=1{# other} other{# others}}' => '',
105 | '{senderName} created a new conversation {conversationTitle}' => '',
106 | '{senderName} sent you a new message in {conversationTitle}' => '',
107 | '{username} joined the conversation.' => '',
108 | '{username} left the conversation.' => '',
109 | ];
110 |
--------------------------------------------------------------------------------
/messages/ro/base.php:
--------------------------------------------------------------------------------
1 | Confirm deleting conversation' => '',
4 | '
Confirm leaving conversation' => '',
5 | '
Confirm message deletion' => '',
6 | '
Confirm tag deletion' => '',
7 | '
Edit conversation tags' => '',
8 | '
Edit tag' => '',
9 | '
Manage conversation tags' => '',
10 | '
Messenger module configuration' => '',
11 | '
New conversation' => '',
12 | '
New message' => '',
13 | 'A tag with the same name already exists.' => '',
14 | 'Add Tag' => '',
15 | 'Add participants' => '',
16 | 'Add recipients' => '',
17 | 'Add user' => '',
18 | 'Advanced Messages Search' => '',
19 | 'Allow others to send you private messages' => '',
20 | 'Allow users to start new conversations' => '',
21 | 'Cancel' => 'Anulează',
22 | 'Confirm' => 'Confirmă',
23 | 'Conversation' => '',
24 | 'Conversation tags can be used to filter conversations and are only visible to you.' => '',
25 | 'Conversations' => '',
26 | 'Created At' => '',
27 | 'Created By' => '',
28 | 'Delete' => 'Șterge',
29 | 'Delete conversation' => '',
30 | 'Do you really want to delete this conversation?' => '',
31 | 'Do you really want to delete this message?' => '',
32 | 'Do you really want to delete this tag?' => '',
33 | 'Do you really want to leave this conversation?' => '',
34 | 'Edit' => 'Editează',
35 | 'Edit message entry' => '',
36 | 'Edit message...' => '',
37 | 'Filter' => 'Filtrează',
38 | 'Friday' => '',
39 | 'Here you can manage your private conversation tags.' => '',
40 | 'Is Originator' => '',
41 | 'Last Viewed' => '',
42 | 'Leave' => '',
43 | 'Leave conversation' => '',
44 | 'Leave fields blank in order to disable a restriction.' => '',
45 | 'Manage Tags' => '',
46 | 'Mark Unread' => '',
47 | 'Max messages allowed per day' => '',
48 | 'Max number of messages allowed for a new user per day' => '',
49 | 'Max number of new conversations allowed for a new user per day' => '',
50 | 'Max number of new conversations allowed for a user per day' => '',
51 | 'Message' => 'Mesaj',
52 | 'Messages' => '',
53 | 'Monday' => '',
54 | 'My Tags' => '',
55 | 'New conversation from {senderName}' => '',
56 | 'New message from {senderName}' => '',
57 | 'Participants' => 'Participanți',
58 | 'Pin' => '',
59 | 'Pinned' => 'Fixat',
60 | 'Receive Notifications when someone opens a new conversation.' => '',
61 | 'Receive Notifications when someone sends you a message.' => '',
62 | 'Receive private messages' => '',
63 | 'Recipient' => '',
64 | 'Reply now' => '',
65 | 'Saturday' => '',
66 | 'Search' => 'Căutare',
67 | 'Send' => 'Trimite',
68 | 'Send message' => '',
69 | 'Seperate restrictions for new users' => '',
70 | 'Show all messages' => '',
71 | 'Show menu item in top Navigation' => '',
72 | 'Start new conversations' => '',
73 | 'Subject' => '제목',
74 | 'Sunday' => '',
75 | 'Tags' => '',
76 | 'There are no messages yet.' => '',
77 | 'This user is already participating in this conversation.' => '',
78 | 'Thursday' => '',
79 | 'Title' => 'Titlul',
80 | 'Today' => '',
81 | 'Tuesday' => '',
82 | 'Unpin' => 'Anulează Anunț',
83 | 'Until a user is member since (days)' => '',
84 | 'Updated At' => '',
85 | 'Updated By' => '',
86 | 'User' => 'Utilizator',
87 | 'User {name} is already participating!' => '',
88 | 'Wednesday' => '',
89 | 'Write a message...' => '',
90 | 'Yesterday' => '',
91 | 'You' => 'Tu',
92 | 'You are not allowed to participate in this conversation. You have been blocked by: {userNames}.' => '',
93 | 'You are not allowed to reply to users {userNames}!' => '',
94 | 'You are not allowed to send user {name} is already!' => '',
95 | 'You are not allowed to start a conversation with this user.' => '',
96 | 'You are not allowed to start a conversation with {userName}!' => '',
97 | 'You cannot send a email to yourself!' => '',
98 | 'You cannot send a message to yourself!' => '',
99 | 'You cannot send a message without recipients!' => '',
100 | 'You joined the conversation.' => '',
101 | 'You left the conversation.' => '',
102 | 'You\'ve exceeded your daily amount of new conversations.' => '',
103 | 'edited' => '',
104 | '{n,plural,=1{# other} other{# others}}' => '',
105 | '{senderName} created a new conversation {conversationTitle}' => '',
106 | '{senderName} sent you a new message in {conversationTitle}' => '',
107 | '{username} joined the conversation.' => '',
108 | '{username} left the conversation.' => '',
109 | ];
110 |
--------------------------------------------------------------------------------
/models/UserMessage.php:
--------------------------------------------------------------------------------
1 | hasOne(Message::class, ['id' => 'message_id']);
60 | }
61 |
62 | public function getUser()
63 | {
64 | return $this->hasOne(User::class, ['id' => 'user_id']);
65 | }
66 |
67 | /**
68 | * @return array customized attribute labels (name=>label)
69 | */
70 | public function attributeLabels()
71 | {
72 | return [
73 | 'message_id' => Yii::t('MailModule.base', 'Message'),
74 | 'user_id' => Yii::t('MailModule.base', 'User'),
75 | 'is_originator' => Yii::t('MailModule.base', 'Is Originator'),
76 | 'last_viewed' => Yii::t('MailModule.base', 'Last Viewed'),
77 | 'created_at' => Yii::t('MailModule.base', 'Created At'),
78 | 'created_by' => Yii::t('MailModule.base', 'Created By'),
79 | 'updated_at' => Yii::t('MailModule.base', 'Updated At'),
80 | 'updated_by' => Yii::t('MailModule.base', 'Updated By'),
81 | ];
82 | }
83 |
84 | /**
85 | * Returns the new message count for given User Id
86 | *
87 | * @param int $userId
88 | * @return int
89 | */
90 | public static function getNewMessageCount($userId = null)
91 | {
92 | if ($userId === null) {
93 | $userId = Yii::$app->user->id;
94 | }
95 |
96 | if ($userId instanceof User) {
97 | $userId = $userId->id;
98 | }
99 |
100 | return static::findByUser($userId)
101 | ->andWhere("message.updated_at > user_message.last_viewed OR user_message.last_viewed IS NULL")
102 | ->andWhere(["<>", 'message.updated_by', $userId])->count();
103 | }
104 |
105 | public static function findByUser($userId = null)
106 | {
107 | if ($userId === null) {
108 | $userId = Yii::$app->user->id;
109 | }
110 |
111 | if ($userId instanceof User) {
112 | $userId = $userId->id;
113 | }
114 |
115 | return static::find()->joinWith('message')
116 | ->where(['user_message.user_id' => $userId])
117 | ->orderBy([
118 | 'user_message.pinned' => SORT_DESC,
119 | 'message.updated_at' => SORT_DESC,
120 | ]);
121 | }
122 |
123 | public function isUnread(): bool
124 | {
125 | return $this->message->updated_at > $this->last_viewed;
126 | }
127 |
128 | public function afterSave($insert, $changedAttributes)
129 | {
130 | parent::afterSave($insert, $changedAttributes);
131 |
132 | if ($insert && $this->informAfterAdd) {
133 | MessageUserJoined::inform($this->message, $this->user);
134 | }
135 | }
136 |
137 | /**
138 | * @inheritdoc
139 | */
140 | public function afterDelete()
141 | {
142 | parent::afterDelete();
143 | MessageUserLeft::inform($this->message, $this->user);
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/helpers/Url.php:
--------------------------------------------------------------------------------
1 | $userGuid] : ['/mail/mail/create'];
15 | return static::to($route);
16 | }
17 |
18 | public static function toDeleteMessageEntry(MessageEntry $entry)
19 | {
20 | return static::to(['/mail/mail/delete-entry', 'id' => $entry->id]);
21 | }
22 |
23 | public static function toLoadMessage()
24 | {
25 | return static::to(['/mail/mail/show']);
26 | }
27 |
28 | public static function toUpdateMessage()
29 | {
30 | return static::to(['/mail/mail/update']);
31 | }
32 |
33 | public static function toEditMessageEntry(MessageEntry $entry)
34 | {
35 | return static::to(['/mail/mail/edit-entry', 'id' => $entry->id]);
36 | }
37 |
38 | public static function toEditConversationTags(Message $message)
39 | {
40 | return static::to(['/mail/tag/edit-conversation', 'messageId' => $message->id]);
41 | }
42 |
43 | public static function toManageTags()
44 | {
45 | return static::to(['/mail/tag/manage']);
46 | }
47 |
48 | public static function toAddTag()
49 | {
50 | return static::to(['/mail/tag/add']);
51 | }
52 |
53 | public static function toEditTag($id)
54 | {
55 | return static::to(['/mail/tag/edit', 'id' => $id]);
56 | }
57 |
58 | public static function toDeleteTag($id)
59 | {
60 | return static::to(['/mail/tag/delete', 'id' => $id]);
61 | }
62 |
63 | public static function toUpdateInbox()
64 | {
65 | return static::to(['/mail/inbox/index']);
66 | }
67 |
68 | public static function toConversationUserList(Message $message)
69 | {
70 | return static::to(['/mail/mail/user-list', 'id' => $message->id]);
71 | }
72 |
73 | public static function toMarkUnreadConversation(Message $message)
74 | {
75 | return static::to(['/mail/mail/mark-unread', 'id' => $message->id]);
76 | }
77 |
78 | public static function toPinConversation(Message $message)
79 | {
80 | return static::to(['/mail/mail/pin', 'id' => $message->id]);
81 | }
82 |
83 | public static function toUnpinConversation(Message $message)
84 | {
85 | return static::to(['/mail/mail/unpin', 'id' => $message->id]);
86 | }
87 |
88 | public static function toLeaveConversation(Message $message)
89 | {
90 | return static::to(['/mail/mail/leave', 'id' => $message->id]);
91 | }
92 |
93 | public static function toMessenger(?Message $message = null, $scheme = false)
94 | {
95 | $route = $message ? ['/mail/mail/index', 'id' => $message->id] : ['/mail/mail/index'];
96 | return static::to($route, $scheme);
97 | }
98 |
99 | public static function toConfig()
100 | {
101 | return static::to(['/mail/config']);
102 | }
103 |
104 | public static function toMessageCountUpdate()
105 | {
106 | return static::to(['/mail/mail/get-new-message-count-json']);
107 | }
108 |
109 | public static function toNotificationList()
110 | {
111 | return static::to(['/mail/mail/notification-list']);
112 | }
113 |
114 | public static function toNotificationSeen()
115 | {
116 | return static::to(['/mail/mail/seen']);
117 | }
118 |
119 | public static function toSearchNewParticipants(?Message $message = null)
120 | {
121 | $route = $message ? ['/mail/mail/search-user', 'id' => $message->id] : ['/mail/mail/search-user'];
122 | return static::to($route);
123 | }
124 |
125 | public static function toAddParticipant(Message $message)
126 | {
127 | return static::to(['/mail/mail/add-user', 'id' => $message->id]);
128 | }
129 |
130 | public static function toReply(Message $message)
131 | {
132 | return static::to(['/mail/mail/reply', 'id' => $message->id]);
133 | }
134 |
135 | public static function toInboxLoadMore()
136 | {
137 | return static::to(['/mail/inbox/load-more']);
138 | }
139 |
140 | public static function toInboxUpdateEntries()
141 | {
142 | return static::to(['/mail/inbox/update-entries']);
143 | }
144 |
145 | public static function toLoadMoreMessages()
146 | {
147 | return static::to(['/mail/mail/load-more']);
148 | }
149 | }
150 |
--------------------------------------------------------------------------------