Applied changes as suggested in https://github.com/engelsystem/engelsystem/pull/915
This commit is contained in:
parent
2c0d516578
commit
71d183df01
|
@ -52,8 +52,8 @@ $route->post('/questions/new', 'QuestionsController@save');
|
|||
|
||||
// Messages
|
||||
$route->get('/messages', 'MessagesController@index');
|
||||
$route->post('/messages', 'MessagesController@toConversation');
|
||||
$route->get('/messages/{user_id:\d+}', 'MessagesController@conversation');
|
||||
$route->post('/messages', 'MessagesController@redirectToConversation');
|
||||
$route->get('/messages/{user_id:\d+}', 'MessagesController@messagesOfConversation');
|
||||
$route->post('/messages/{user_id:\d+}', 'MessagesController@send');
|
||||
$route->post('/messages/{user_id:\d+}/{msg_id:\d+}', 'MessagesController@delete');
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ code {
|
|||
}
|
||||
|
||||
.conversation {
|
||||
height: 60vh;
|
||||
height: 55vh;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto
|
||||
}
|
||||
|
|
|
@ -155,5 +155,5 @@ msgstr "Eine Beschreibung findest du unter %2$s"
|
|||
msgid "user.edit.success"
|
||||
msgstr "Benutzer erfolgreich bearbeitet."
|
||||
|
||||
msgid "messages.delete.success"
|
||||
msgid "message.delete.success"
|
||||
msgstr "Nachricht erfolgreich gelöscht."
|
||||
|
|
|
@ -3031,17 +3031,20 @@ msgstr "Angekommen"
|
|||
msgid "user.got_shirt"
|
||||
msgstr "Shirt bekommen"
|
||||
|
||||
msgid "messages.title"
|
||||
msgid "message.title"
|
||||
msgstr "Nachrichten"
|
||||
|
||||
msgid "messages.choose.an.angel"
|
||||
msgid "message.choose_angel"
|
||||
msgstr "Wähle einen Engel"
|
||||
|
||||
msgid "messages.to.conversation"
|
||||
msgid "message.to_conversation"
|
||||
msgstr "Zur Konversation"
|
||||
|
||||
msgid "message.message"
|
||||
msgstr "Nachricht"
|
||||
|
||||
msgid "angel"
|
||||
msgstr "Engel"
|
||||
|
||||
msgid "message"
|
||||
msgstr "Nachricht"
|
||||
msgid "date"
|
||||
msgstr "Datum"
|
||||
|
|
|
@ -153,5 +153,5 @@ msgstr "You can find a description at %2$s"
|
|||
msgid "user.edit.success"
|
||||
msgstr "User edited successfully."
|
||||
|
||||
msgid "messages.delete.success"
|
||||
msgid "message.delete.success"
|
||||
msgstr "Message successfully deleted."
|
||||
|
|
|
@ -301,17 +301,20 @@ msgstr "Arrived"
|
|||
msgid "user.got_shirt"
|
||||
msgstr "Got shirt"
|
||||
|
||||
msgid "messages.title"
|
||||
msgid "message.title"
|
||||
msgstr "Messages"
|
||||
|
||||
msgid "messages.choose.an.angel"
|
||||
msgid "message.choose_angel"
|
||||
msgstr "Choose an Angel"
|
||||
|
||||
msgid "messages.to.conversation"
|
||||
msgid "message.to_conversation"
|
||||
msgstr "To Conversation"
|
||||
|
||||
msgid "message.message"
|
||||
msgstr "Message"
|
||||
|
||||
msgid "angel"
|
||||
msgstr "Angel"
|
||||
|
||||
msgid "message"
|
||||
msgstr "Message"
|
||||
msgid "date"
|
||||
msgstr "Date"
|
||||
|
|
|
@ -1063,11 +1063,6 @@ msgstr "Autor"
|
|||
msgid "Subject"
|
||||
msgstr "Assunto"
|
||||
|
||||
#: includes/pages/admin_news.php:33 includes/pages/user_messages.php:79
|
||||
#: includes/pages/user_news.php:106 includes/pages/user_news.php:162
|
||||
msgid "Message"
|
||||
msgstr "Mensagem"
|
||||
|
||||
#: includes/pages/admin_news.php:34 includes/pages/user_news.php:163
|
||||
msgid "Meeting"
|
||||
msgstr "Reunião"
|
||||
|
@ -1453,10 +1448,6 @@ msgstr "Por favor leia sobre as tarefas que pode realizar para nos ajudar."
|
|||
msgid "Please sign up, if you want to help us!"
|
||||
msgstr "Se você quer nos ajudar, por favor se registre!"
|
||||
|
||||
#: includes/pages/user_messages.php:4
|
||||
msgid "Messages"
|
||||
msgstr "Mensagens"
|
||||
|
||||
#: includes/pages/user_messages.php:26
|
||||
msgid "Select recipient..."
|
||||
msgstr "Selecionar recipiente..."
|
||||
|
|
|
@ -16,11 +16,15 @@
|
|||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro user(user) %}
|
||||
<a href="{{ url('users', {'action': 'view', 'user_id': user.id}) }}"
|
||||
{% macro user(user, opt) %}
|
||||
<a href="{{ opt.url|default(url('users', {'action': 'view', 'user_id': user.id})) }}"
|
||||
{%- if not user.state.arrived %} class="text-muted"{% endif -%}
|
||||
>
|
||||
{{ _self.angel() }} {{ user.name }}
|
||||
{%- if opt.show_pronoun_if_configured|default(false) and config('enable_pronoun')
|
||||
and user.personalData.pronoun %}
|
||||
({{ user.personalData.pronoun }})
|
||||
{% endif -%}
|
||||
</a>
|
||||
{% endmacro %}
|
||||
|
||||
|
|
|
@ -37,12 +37,17 @@
|
|||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro select(name, data, label, selected) %}
|
||||
{% macro select(name, data, label, selected, opt) %}
|
||||
<div class="mb-3">
|
||||
{% if label -%}
|
||||
<label class="form-label" for="{{ name }}">{{ label }}</label>
|
||||
{% endif %}
|
||||
<select id="{{ name }}" name="{{ name }}" class="form-control">
|
||||
<select id="{{ name }}" name="{{ name }}"
|
||||
class="form-control {%- if opt.class is defined %} {{ opt.class }}{% endif %}"
|
||||
{%- if opt.required|default(false) %}required{%- endif -%}>
|
||||
{%- if opt.default_option is defined %}
|
||||
<option value="">{{ opt.default_option }}</option>
|
||||
{% endif %}
|
||||
{% for value,decription in data -%}
|
||||
<option value="{{ value }}"{% if value == selected %} selected{% endif %}>{{ decription }}</option>
|
||||
{% endfor %}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
{% import 'macros/base.twig' as m %}
|
||||
{% import 'macros/form.twig' as f %}
|
||||
|
||||
{% block title %}{{ __('messages.title') }}: {{ other_user.nameWithPronoun() }}{% endblock %}
|
||||
{% block title %}{{ __('message.title') }}: {{ other_user.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
{{ __('messages.title') }}: <span class="icon-icon_angel"></span> {{ other_user.nameWithPronoun() }}
|
||||
{{ __('message.title') }}: {{ m.user(other_user, {'show_pronoun_if_configured': true}) }}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
@ -22,12 +22,12 @@
|
|||
<div class="message alert alert-secondary position-relative">
|
||||
<div>{{ msg.text | nl2br }}</div>
|
||||
<div class="text-end">
|
||||
<small class="opacity-75">{{ msg.created_at }}</small>
|
||||
<small
|
||||
class="opacity-75">{{ msg.created_at.format(__('Y-m-d H:i')) }}</small>
|
||||
</div>
|
||||
{% if msg.read == false %}
|
||||
<span class="position-absolute top-0 start-100 translate-middle-x p-2 bg-danger rounded-circle">
|
||||
<span class="visually-hidden">New alerts</span>
|
||||
</span>
|
||||
<span class="position-absolute top-0 start-100 translate-middle-x p-2
|
||||
bg-danger rounded-circle"></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -57,10 +57,11 @@
|
|||
{{ csrf() }}
|
||||
|
||||
<div class="input-group">
|
||||
<textarea class="form-control" id="text" name="text" required="" rows="1"></textarea>
|
||||
<textarea class="form-control" id="text" name="text" required="" rows="2"></textarea>
|
||||
{{ f.submit(m.icon('send-fill')) }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{% import 'macros/base.twig' as m %}
|
||||
{% import 'macros/form.twig' as f %}
|
||||
|
||||
{% block title %}{{ __('messages.title') }}{% endblock %}
|
||||
{% block title %}{{ __('message.title') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
|
@ -15,15 +15,11 @@
|
|||
{{ csrf() }}
|
||||
<div class="row gx-2 mb-3">
|
||||
<div class="col-auto">
|
||||
<select id="user_id" name="user_id" class="form-control pe-5" required>
|
||||
<option value="">{{ __('messages.choose.an.angel') }}</option>
|
||||
{% for value,decription in users -%}
|
||||
<option value="{{ value }}">{{ decription }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{{ f.select('user_id', users, null, null,
|
||||
{ 'class': 'pe-5', 'required': true, 'default_option': __('message.choose_angel') }) }}
|
||||
</div>
|
||||
<div class="col">
|
||||
{{ f.submit(__('messages.to.conversation'), {'btn_type': 'secondary'}) }}
|
||||
{{ f.submit(__('message.to_conversation'), {'btn_type': 'secondary'}) }}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -32,27 +28,27 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('angel') }}</th>
|
||||
<th>{{ __('message') }}</th>
|
||||
<th>{{ __('Date') }}</th>
|
||||
<th>{{ __('message.message') }}</th>
|
||||
<th>{{ __('date') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in conversations %}
|
||||
<tr>
|
||||
<td>
|
||||
<span class="icon-icon_angel"></span>
|
||||
{{ c.other_user.nameWithPronoun() }}
|
||||
{{ m.user(c.other_user, {'show_pronoun_if_configured': true, 'url': url('messages/' ~ c.other_user.id)}) }}
|
||||
|
||||
{% if c.unread_messages > 0 %}
|
||||
<span class="badge bg-danger">{{ c.unread_messages }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url('messages/' ~ c.other_user.id) }}">
|
||||
{{ c.latest_message.text|length > 100 ? c.latest_message.text|slice(0, 100) ~ '...' : c.latest_message.text }}
|
||||
{{ c.latest_message.text|length > 100 ? c.latest_message.text|slice(0, 100) ~ '…' : c.latest_message.text }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ c.latest_message.created_at }}
|
||||
{{ c.latest_message.created_at.format(__('Y-m-d H:i')) }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -10,7 +10,6 @@ use Engelsystem\Http\Response;
|
|||
use Engelsystem\Models\Message;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Query\Expression as QueryExpression;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Engelsystem\Http\Exceptions\HttpForbidden;
|
||||
|
||||
|
@ -19,9 +18,6 @@ class MessagesController extends BaseController
|
|||
/** @var Authenticator */
|
||||
protected $auth;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
protected $log;
|
||||
|
||||
/** @var Redirector */
|
||||
protected $redirect;
|
||||
|
||||
|
@ -47,7 +43,6 @@ class MessagesController extends BaseController
|
|||
|
||||
/**
|
||||
* @param Authenticator $auth
|
||||
* @param LoggerInterface $log
|
||||
* @param Redirector $redirect
|
||||
* @param Response $response
|
||||
* @param Request $request
|
||||
|
@ -57,7 +52,6 @@ class MessagesController extends BaseController
|
|||
*/
|
||||
public function __construct(
|
||||
Authenticator $auth,
|
||||
LoggerInterface $log,
|
||||
Redirector $redirect,
|
||||
Response $response,
|
||||
Request $request,
|
||||
|
@ -66,7 +60,6 @@ class MessagesController extends BaseController
|
|||
User $user
|
||||
) {
|
||||
$this->auth = $auth;
|
||||
$this->log = $log;
|
||||
$this->redirect = $redirect;
|
||||
$this->response = $response;
|
||||
$this->request = $request;
|
||||
|
@ -75,37 +68,41 @@ class MessagesController extends BaseController
|
|||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->listConversations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of conversations of the current user, each containing the other participant,
|
||||
* Returns a list of conversations of the current user, each containing the other user,
|
||||
* the most recent message, and the number of unread messages.
|
||||
*/
|
||||
public function listConversations(): Response
|
||||
{
|
||||
$current_user = $this->auth->user();
|
||||
$currentUser = $this->auth->user();
|
||||
|
||||
$latest_messages = $this->latestMessagePerConversation($current_user);
|
||||
$numberOfUnreadMessages = $this->numberOfUnreadMessagesPerConversation($current_user);
|
||||
$latestMessages = $this->latestMessagePerConversation($currentUser);
|
||||
$numberOfUnreadMessages = $this->numberOfUnreadMessagesPerConversation($currentUser);
|
||||
|
||||
$conversations = [];
|
||||
foreach ($latest_messages as $msg) {
|
||||
$other_user = $msg->user_id == $current_user->id ? $msg->receiver : $msg->sender;
|
||||
$unread_messages = $numberOfUnreadMessages[$other_user->id] ?? 0;
|
||||
array_push($conversations, [
|
||||
'other_user' => $other_user,
|
||||
foreach ($latestMessages as $msg) {
|
||||
$otherUser = $msg->user_id == $currentUser->id ? $msg->receiver : $msg->sender;
|
||||
$unreadMessages = $numberOfUnreadMessages[$otherUser->id] ?? 0;
|
||||
|
||||
$conversations[] = [
|
||||
'other_user' => $otherUser,
|
||||
'latest_message' => $msg,
|
||||
'unread_messages' => $unread_messages
|
||||
]);
|
||||
'unread_messages' => $unreadMessages,
|
||||
];
|
||||
}
|
||||
|
||||
$users = $this->user->orderBy('name')->get()
|
||||
->except($current_user->id)
|
||||
->except($currentUser->id)
|
||||
->mapWithKeys(function ($u) {
|
||||
return [ $u->id => $u->nameWithPronoun() ];
|
||||
return [ $u->id => $u->name ];
|
||||
});
|
||||
|
||||
return $this->response->withView(
|
||||
|
@ -118,45 +115,44 @@ class MessagesController extends BaseController
|
|||
}
|
||||
|
||||
/**
|
||||
* Forwards to the conversation with the user of the given id.
|
||||
* Redirects to the conversation with the user of the given id.
|
||||
*/
|
||||
public function toConversation(Request $request): Response
|
||||
public function redirectToConversation(Request $request): Response
|
||||
{
|
||||
$data = $this->validate($request, ['user_id' => 'required|int']);
|
||||
return $this->redirect->to('/messages/' . $data['user_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of messages between the current user and a user with the given id. The ids shall not be the same.
|
||||
* Unread messages will be marked as read during this call. Still, they will be shown as unread in the frontend to
|
||||
* highlight them to the user as new.
|
||||
* Returns a list of messages between the current user and a user with the given id. Unread messages will be marked
|
||||
* as read during this call. Still, they will be shown as unread in the frontend to highlight them to the user as new.
|
||||
*/
|
||||
public function conversation(Request $request): Response
|
||||
public function messagesOfConversation(Request $request): Response
|
||||
{
|
||||
$current_user = $this->auth->user();
|
||||
$other_user = $this->user->findOrFail($request->getAttribute('user_id'));
|
||||
$currentUser = $this->auth->user();
|
||||
$otherUser = $this->user->findOrFail($request->getAttribute('user_id'));
|
||||
|
||||
if ($current_user->id == $other_user->id) {
|
||||
if ($currentUser->id == $otherUser->id) {
|
||||
throw new HttpForbidden('You can not start a conversation with yourself.');
|
||||
}
|
||||
|
||||
$messages = $this->message
|
||||
->where(function ($q) use ($current_user, $other_user) {
|
||||
$q->whereUserId($current_user->id)
|
||||
->whereReceiverId($other_user->id);
|
||||
->where(function ($query) use ($currentUser, $otherUser) {
|
||||
$query->whereUserId($currentUser->id)
|
||||
->whereReceiverId($otherUser->id);
|
||||
})
|
||||
->orWhere(function ($q) use ($current_user, $other_user) {
|
||||
$q->whereUserId($other_user->id)
|
||||
->whereReceiverId($current_user->id);
|
||||
->orWhere(function ($query) use ($currentUser, $otherUser) {
|
||||
$query->whereUserId($otherUser->id)
|
||||
->whereReceiverId($currentUser->id);
|
||||
})
|
||||
->orderBy('created_at')
|
||||
->get();
|
||||
|
||||
$unread_messages = $messages->filter(function ($m) use ($other_user) {
|
||||
return $m->user_id == $other_user->id && !$m->read;
|
||||
$unreadMessages = $messages->filter(function ($m) use ($otherUser) {
|
||||
return $m->user_id == $otherUser->id && !$m->read;
|
||||
});
|
||||
|
||||
foreach ($unread_messages as $msg) {
|
||||
foreach ($unreadMessages as $msg) {
|
||||
$msg->read = true;
|
||||
$msg->save();
|
||||
$msg->read = false; // change back to true to display it to the frontend one more time.
|
||||
|
@ -164,7 +160,7 @@ class MessagesController extends BaseController
|
|||
|
||||
return $this->response->withView(
|
||||
'pages/messages/conversation.twig',
|
||||
['messages' => $messages, 'other_user' => $other_user]
|
||||
['messages' => $messages, 'other_user' => $otherUser]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -173,72 +169,50 @@ class MessagesController extends BaseController
|
|||
*/
|
||||
public function send(Request $request): Response
|
||||
{
|
||||
$current_user = $this->auth->user();
|
||||
$currentUser = $this->auth->user();
|
||||
|
||||
$data = $this->validate($request, ['text' => 'required']);
|
||||
|
||||
$other_user = $this->user->findOrFail($request->getAttribute('user_id'));
|
||||
$otherUser = $this->user->findOrFail($request->getAttribute('user_id'));
|
||||
|
||||
if ($other_user->id == $current_user->id) {
|
||||
if ($otherUser->id == $currentUser->id) {
|
||||
throw new HttpForbidden('You can not send a message to yourself.');
|
||||
}
|
||||
|
||||
$new_message = new Message();
|
||||
$new_message->sender()->associate($current_user);
|
||||
$new_message->receiver()->associate($other_user);
|
||||
$new_message->text = $data['text'];
|
||||
$new_message->read = false;
|
||||
$new_message->save();
|
||||
$newMessage = new Message();
|
||||
$newMessage->sender()->associate($currentUser);
|
||||
$newMessage->receiver()->associate($otherUser);
|
||||
$newMessage->text = $data['text'];
|
||||
$newMessage->read = false;
|
||||
$newMessage->save();
|
||||
|
||||
$this->log->info(
|
||||
'User {from} has written a message to user {to}',
|
||||
[
|
||||
'from' => $current_user->id,
|
||||
'to' => $other_user->id
|
||||
]
|
||||
);
|
||||
return $this->redirect->to('/messages/' . $other_user->id);
|
||||
return $this->redirect->to('/messages/' . $otherUser->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a message from a given id, as long as this message was send by the current user. The given user_id
|
||||
* The given user_id is used to redirect back to the conversation with that user.
|
||||
* Deletes a message with a given id, as long as this message was send by the current user.
|
||||
* The given user id is used to redirect back to the conversation with that user.
|
||||
*/
|
||||
public function delete(Request $request): Response
|
||||
{
|
||||
$current_user = $this->auth->user();
|
||||
$other_user_id = $request->getAttribute('user_id');
|
||||
$msg_id = $request->getAttribute('msg_id');
|
||||
$msg = $this->message->findOrFail($msg_id);
|
||||
$currentUser = $this->auth->user();
|
||||
$otherUserId = $request->getAttribute('user_id');
|
||||
$msgId = $request->getAttribute('msg_id');
|
||||
$msg = $this->message->findOrFail($msgId);
|
||||
|
||||
if ($msg->user_id == $current_user->id) {
|
||||
if ($msg->user_id == $currentUser->id) {
|
||||
$msg->delete();
|
||||
|
||||
$this->log->info(
|
||||
'User {from} deleted message {msg} in a conversation with user {to}',
|
||||
[
|
||||
'from' => $current_user->id,
|
||||
'to' => $other_user_id,
|
||||
'msg' => $msg_id
|
||||
]
|
||||
);
|
||||
} else {
|
||||
$this->log->warning(
|
||||
'User {from} tried to delete message {msg} which was not written by them, ' .
|
||||
'in a conversation with user {to}',
|
||||
[
|
||||
'from' => $current_user->id,
|
||||
'to' => $other_user_id,
|
||||
'msg' => $msg_id
|
||||
]
|
||||
);
|
||||
|
||||
throw new HttpForbidden('You can not delete a message you haven\'t send');
|
||||
}
|
||||
|
||||
return $this->redirect->to('/messages/' . $other_user_id);
|
||||
return $this->redirect->to('/messages/' . $otherUserId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overall unread messages of the current user.
|
||||
*/
|
||||
public function numberOfUnreadMessages(): int
|
||||
{
|
||||
return $this->auth->user()
|
||||
|
@ -247,9 +221,13 @@ class MessagesController extends BaseController
|
|||
->count();
|
||||
}
|
||||
|
||||
protected function numberOfUnreadMessagesPerConversation($current_user): Collection
|
||||
/**
|
||||
* The number of unread messages per conversation of the current user.
|
||||
* @return Collection of unread message amounts. Each object with key=other user, value=amount of unread messages
|
||||
*/
|
||||
protected function numberOfUnreadMessagesPerConversation($currentUser): Collection
|
||||
{
|
||||
return $current_user->messagesReceived()
|
||||
return $currentUser->messagesReceived()
|
||||
->select('user_id', $this->raw('count(*) as amount'))
|
||||
->where('read', false)
|
||||
->groupBy('user_id')
|
||||
|
@ -259,25 +237,38 @@ class MessagesController extends BaseController
|
|||
});
|
||||
}
|
||||
|
||||
protected function latestMessagePerConversation($current_user): Collection
|
||||
/**
|
||||
* Returns the latest message for each conversation,
|
||||
* which were either send by or addressed to the current user.
|
||||
* @return Collection of messages
|
||||
*/
|
||||
protected function latestMessagePerConversation($currentUser): Collection
|
||||
{
|
||||
$latest_message_ids = $this->message
|
||||
/* requesting the IDs first, grouped by "conversation".
|
||||
The more complex grouping is required for associating the messages to the correct conversations.
|
||||
Without this, a database change might have been needed to realize the "conversations" concept. */
|
||||
$latestMessageIds = $this->message
|
||||
->select($this->raw('max(id) as last_id'))
|
||||
->where('user_id', "=", $current_user->id)
|
||||
->orWhere('receiver_id', "=", $current_user->id)
|
||||
->where('user_id', '=', $currentUser->id)
|
||||
->orWhere('receiver_id', '=', $currentUser->id)
|
||||
->groupBy($this->raw(
|
||||
'(CASE WHEN user_id = ' . $current_user->id .
|
||||
'(CASE WHEN user_id = ' . (int) $currentUser->id .
|
||||
' THEN receiver_id ELSE user_id END)'
|
||||
));
|
||||
|
||||
// then getting the full message objects for each ID.
|
||||
return $this->message
|
||||
->joinSub($latest_message_ids, 'conversations', function ($join) {
|
||||
->joinSub($latestMessageIds, 'conversations', function ($join) {
|
||||
$join->on('messages.id', '=', 'conversations.last_id');
|
||||
})
|
||||
->orderBy('created_at', 'DESC')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return QueryExpression
|
||||
*/
|
||||
protected function raw($value): QueryExpression
|
||||
{
|
||||
return $this->db->getConnection()->raw($value);
|
||||
|
|
|
@ -225,18 +225,4 @@ class User extends BaseModel
|
|||
->orderBy('read')
|
||||
->orderBy('id', 'DESC');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return either just the user name or the name alongside with the pronoun.
|
||||
* @return string
|
||||
*/
|
||||
public function nameWithPronoun(): string
|
||||
{
|
||||
if (config('enable_pronoun')) {
|
||||
$pronoun = $this->personalData->pronoun;
|
||||
return $pronoun ? $this->name . ' (' . $pronoun . ')' : $this->name;
|
||||
} else {
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,6 @@ use Engelsystem\Http\UrlGenerator;
|
|||
use Engelsystem\Http\UrlGeneratorInterface;
|
||||
use Engelsystem\Http\Validation\Validator;
|
||||
use Engelsystem\Models\Message;
|
||||
use Engelsystem\Models\Question;
|
||||
use Engelsystem\Models\User\PersonalData;
|
||||
use Engelsystem\Models\User\Settings;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Test\Unit\HasDatabase;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
@ -44,6 +41,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox index: underNormalConditions -> returnsCorrectViewAndData
|
||||
* @covers \Engelsystem\Controllers\MessagesController::index
|
||||
*/
|
||||
public function testIndexUnderNormalConditionsReturnsCorrectViewAndData()
|
||||
{
|
||||
|
@ -63,6 +61,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox index: otherUsersExist -> returnsUsersWithoutMeOrderedByName
|
||||
* @covers \Engelsystem\Controllers\MessagesController::index
|
||||
*/
|
||||
public function testIndexOtherUsersExistReturnsUsersWithoutMeOrderedByName()
|
||||
{
|
||||
|
@ -80,56 +79,9 @@ class MessagesControllerTest extends ControllerTest
|
|||
$this->controller->index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox index: pronounsDeactivated -> userListHasNoPronouns
|
||||
*/
|
||||
public function testIndexPronounsDeactivatedUserListHasNoPronouns()
|
||||
{
|
||||
$this->user_with_pronoun = User::factory(['name' => 'x'])
|
||||
->has(PersonalData::factory(['pronoun' => 'X']))->create();
|
||||
$this->user_without_pronoun = $this->user_b;
|
||||
|
||||
$this->response->expects($this->once())
|
||||
->method('withView')
|
||||
->willReturnCallback(function (string $view, array $data) {
|
||||
$users = $data['users'];
|
||||
|
||||
$this->assertEquals('x', $users[$this->user_with_pronoun->id]);
|
||||
$this->assertEquals('b', $users[$this->user_without_pronoun->id]);
|
||||
|
||||
return $this->response;
|
||||
});
|
||||
|
||||
$this->controller->index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox index: pronounsActivated -> userListHasPronouns
|
||||
*/
|
||||
public function testIndexPronounsActivatedUserListHasPronouns()
|
||||
{
|
||||
config(['enable_pronoun' => true]);
|
||||
|
||||
$this->user_with_pronoun = User::factory(['name' => 'x'])
|
||||
->has(PersonalData::factory(['pronoun' => 'X']))->create();
|
||||
$this->user_without_pronoun = $this->user_b;
|
||||
|
||||
$this->response->expects($this->once())
|
||||
->method('withView')
|
||||
->willReturnCallback(function (string $view, array $data) {
|
||||
$users = $data['users'];
|
||||
|
||||
$this->assertEquals('x (X)', $users[$this->user_with_pronoun->id]);
|
||||
$this->assertEquals('b', $users[$this->user_without_pronoun->id]);
|
||||
|
||||
return $this->response;
|
||||
});
|
||||
|
||||
$this->controller->index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox index: withNoConversation -> returnsEmptyConversationList
|
||||
* @covers \Engelsystem\Controllers\MessagesController::index
|
||||
*/
|
||||
public function testIndexWithNoConversationReturnsEmptyConversationList()
|
||||
{
|
||||
|
@ -145,6 +97,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox index: withConversation -> conversationContainsCorrectData
|
||||
* @covers \Engelsystem\Controllers\MessagesController::index
|
||||
*/
|
||||
public function testIndexWithConversationConversationContainsCorrectData()
|
||||
{
|
||||
|
@ -181,6 +134,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox index: withConversations -> onlyContainsConversationsWithMe
|
||||
* @covers \Engelsystem\Controllers\MessagesController::index
|
||||
*/
|
||||
public function testIndexWithConversationsOnlyContainsConversationsWithMe()
|
||||
{
|
||||
|
@ -209,6 +163,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox index: withConversations -> conversationsOrderedByDate
|
||||
* @covers \Engelsystem\Controllers\MessagesController::index
|
||||
*/
|
||||
public function testIndexWithConversationsConversationsOrderedByDate()
|
||||
{
|
||||
|
@ -235,18 +190,20 @@ class MessagesControllerTest extends ControllerTest
|
|||
}
|
||||
|
||||
/**
|
||||
* @testdox ToConversation: withNoUserIdGiven -> throwsException
|
||||
* @testdox redirectToConversation: withNoUserIdGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::redirectToConversation
|
||||
*/
|
||||
public function testToConversationWithNoUserIdGivenThrowsException()
|
||||
public function testRedirectToConversationWithNoUserIdGivenThrowsException()
|
||||
{
|
||||
$this->expectException(ValidationException::class);
|
||||
$this->controller->toConversation($this->request);
|
||||
$this->controller->redirectToConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox ToConversation: withUserIdGiven -> redirect
|
||||
* @testdox redirectToConversation: withUserIdGiven -> redirect
|
||||
* @covers \Engelsystem\Controllers\MessagesController::redirectToConversation
|
||||
*/
|
||||
public function testToConversationWithUserIdGivenRedirect()
|
||||
public function testRedirectToConversationWithUserIdGivenRedirect()
|
||||
{
|
||||
$this->request = $this->request->withParsedBody([
|
||||
'user_id' => '1',
|
||||
|
@ -256,42 +213,47 @@ class MessagesControllerTest extends ControllerTest
|
|||
->with('http://localhost/messages/1')
|
||||
->willReturn($this->response);
|
||||
|
||||
$this->controller->toConversation($this->request);
|
||||
$this->controller->redirectToConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox conversation: withNoUserIdGiven -> throwsException
|
||||
* @testdox messagesOfConversation: withNoUserIdGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::messagesOfConversation
|
||||
*/
|
||||
public function testConversationWithNoUserIdGivenThrowsException()
|
||||
public function testMessagesOfConversationWithNoUserIdGivenThrowsException()
|
||||
{
|
||||
$this->expectException(ModelNotFoundException::class);
|
||||
$this->controller->conversation($this->request);
|
||||
$this->controller->messagesOfConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox conversation: withMyUserIdGiven -> throwsException
|
||||
* @testdox messagesOfConversation: withMyUserIdGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::messagesOfConversation
|
||||
*/
|
||||
public function testConversationWithMyUserIdGivenThrowsException()
|
||||
public function testMessagesOfConversationWithMyUserIdGivenThrowsException()
|
||||
{
|
||||
$this->request->attributes->set('user_id', $this->user_a->id);
|
||||
$this->expectException(HttpForbidden::class);
|
||||
$this->controller->conversation($this->request);
|
||||
|
||||
$this->controller->messagesOfConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox conversation: withUnknownUserIdGiven -> throwsException
|
||||
* @testdox messagesOfConversation: withUnknownUserIdGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::messagesOfConversation
|
||||
*/
|
||||
public function testConversationWithUnknownUserIdGivenThrowsException()
|
||||
public function testMessagesOfConversationWithUnknownUserIdGivenThrowsException()
|
||||
{
|
||||
$this->request->attributes->set('user_id', '1234');
|
||||
$this->expectException(ModelNotFoundException::class);
|
||||
$this->controller->conversation($this->request);
|
||||
$this->controller->messagesOfConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox conversation: underNormalConditions -> returnsCorrectViewAndData
|
||||
* @testdox messagesOfConversation: underNormalConditions -> returnsCorrectViewAndData
|
||||
* @covers \Engelsystem\Controllers\MessagesController::messagesOfConversation
|
||||
*/
|
||||
public function testConversationUnderNormalConditionsReturnsCorrectViewAndData()
|
||||
public function testMessagesOfConversationUnderNormalConditionsReturnsCorrectViewAndData()
|
||||
{
|
||||
$this->request->attributes->set('user_id', $this->user_b->id);
|
||||
|
||||
|
@ -306,13 +268,14 @@ class MessagesControllerTest extends ControllerTest
|
|||
return $this->response;
|
||||
});
|
||||
|
||||
$this->controller->conversation($this->request);
|
||||
$this->controller->messagesOfConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox conversation: withNoMessages -> returnsEmptyMessageList
|
||||
* @testdox messagesOfConversation: withNoMessages -> returnsEmptyMessageList
|
||||
* @covers \Engelsystem\Controllers\MessagesController::messagesOfConversation
|
||||
*/
|
||||
public function testConversationWithNoMessagesReturnsEmptyMessageList()
|
||||
public function testMessagesOfConversationWithNoMessagesReturnsEmptyMessageList()
|
||||
{
|
||||
$this->request->attributes->set('user_id', $this->user_b->id);
|
||||
|
||||
|
@ -323,13 +286,14 @@ class MessagesControllerTest extends ControllerTest
|
|||
return $this->response;
|
||||
});
|
||||
|
||||
$this->controller->conversation($this->request);
|
||||
$this->controller->messagesOfConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox conversation: withMessages -> messagesOnlyWithThatUserOrderedByDate
|
||||
* @testdox messagesOfConversation: withMessages -> messagesOnlyWithThatUserOrderedByDate
|
||||
* @covers \Engelsystem\Controllers\MessagesController::messagesOfConversation
|
||||
*/
|
||||
public function testConversationWithMessagesMessagesOnlyWithThatUserOrderedByDate()
|
||||
public function testMessagesOfConversationWithMessagesMessagesOnlyWithThatUserOrderedByDate()
|
||||
{
|
||||
$this->request->attributes->set('user_id', $this->user_b->id);
|
||||
|
||||
|
@ -356,13 +320,14 @@ class MessagesControllerTest extends ControllerTest
|
|||
return $this->response;
|
||||
});
|
||||
|
||||
$this->controller->conversation($this->request);
|
||||
$this->controller->messagesOfConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox conversation: withUnreadMessages -> messagesToMeWillStillBeReturnedAsUnread
|
||||
* @testdox messagesOfConversation: withUnreadMessages -> messagesToMeWillStillBeReturnedAsUnread
|
||||
* @covers \Engelsystem\Controllers\MessagesController::messagesOfConversation
|
||||
*/
|
||||
public function testConversationWithUnreadMessagesMessagesToMeWillStillBeReturnedAsUnread()
|
||||
public function testMessagesOfConversationWithUnreadMessagesMessagesToMeWillStillBeReturnedAsUnread()
|
||||
{
|
||||
$this->request->attributes->set('user_id', $this->user_b->id);
|
||||
$this->createMessage($this->user_b, $this->user_a, 'b>a', $this->now);
|
||||
|
@ -373,13 +338,14 @@ class MessagesControllerTest extends ControllerTest
|
|||
$this->assertFalse($data['messages'][0]->read);
|
||||
return $this->response;
|
||||
});
|
||||
$this->controller->conversation($this->request);
|
||||
$this->controller->messagesOfConversation($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox conversation: withUnreadMessages -> messagesToMeWillBeMarkedAsRead
|
||||
* @testdox messagesOfConversation: withUnreadMessages -> messagesToMeWillBeMarkedAsRead
|
||||
* @covers \Engelsystem\Controllers\MessagesController::messagesOfConversation
|
||||
*/
|
||||
public function testConversationWithUnreadMessagesMessagesToMeWillBeMarkedAsRead()
|
||||
public function testMessagesOfConversationWithUnreadMessagesMessagesToMeWillBeMarkedAsRead()
|
||||
{
|
||||
$this->request->attributes->set('user_id', $this->user_b->id);
|
||||
$this->response->expects($this->once())
|
||||
|
@ -389,12 +355,13 @@ class MessagesControllerTest extends ControllerTest
|
|||
});
|
||||
|
||||
$msg = $this->createMessage($this->user_b, $this->user_a, 'b>a', $this->now);
|
||||
$this->controller->conversation($this->request);
|
||||
$this->controller->messagesOfConversation($this->request);
|
||||
$this->assertTrue(Message::whereId($msg->id)->first()->read);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox send: withNoTextGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::send
|
||||
*/
|
||||
public function testSendWithNoTextGivenThrowsException()
|
||||
{
|
||||
|
@ -404,6 +371,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox send: withNoUserIdGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::send
|
||||
*/
|
||||
public function testSendWithNoUserIdGivenThrowsException()
|
||||
{
|
||||
|
@ -416,6 +384,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox send: withMyUserIdGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::send
|
||||
*/
|
||||
public function testSendWithMyUserIdGivenThrowsException()
|
||||
{
|
||||
|
@ -424,11 +393,13 @@ class MessagesControllerTest extends ControllerTest
|
|||
]);
|
||||
$this->request->attributes->set('user_id', $this->user_a->id);
|
||||
$this->expectException(HttpForbidden::class);
|
||||
|
||||
$this->controller->send($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox send: withUnknownUserIdGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::send
|
||||
*/
|
||||
public function testSendWithUnknownUserIdGivenThrowsException()
|
||||
{
|
||||
|
@ -442,6 +413,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox send: withUserAndTextGiven -> savesMessage
|
||||
* @covers \Engelsystem\Controllers\MessagesController::send
|
||||
*/
|
||||
public function testSendWithUserAndTextGivenSavesMessage()
|
||||
{
|
||||
|
@ -465,6 +437,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox delete: withNoMsgIdGiven -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::delete
|
||||
*/
|
||||
public function testDeleteWithNoMsgIdGivenThrowsException()
|
||||
{
|
||||
|
@ -474,19 +447,20 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox delete: tryingToDeleteSomeonesMessage -> throwsException
|
||||
* @covers \Engelsystem\Controllers\MessagesController::delete
|
||||
*/
|
||||
public function testDeleteTryingToDeleteSomeonesMessageThrowsException()
|
||||
{
|
||||
$this->expectException(HttpForbidden::class);
|
||||
|
||||
$msg = $this->createMessage($this->user_b, $this->user_a, 'a>b', $this->now);
|
||||
$this->request->attributes->set('msg_id', $msg->id);
|
||||
$this->expectException(HttpForbidden::class);
|
||||
|
||||
$this->controller->delete($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox delete: tryingToDeleteMyMessage -> deletesItAndRedirect
|
||||
* @covers \Engelsystem\Controllers\MessagesController::delete
|
||||
*/
|
||||
public function testDeleteTryingToDeleteMyMessageDeletesItAndRedirect()
|
||||
{
|
||||
|
@ -506,6 +480,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox NumberOfUnreadMessages: withNoMessages -> returns0
|
||||
* @covers \Engelsystem\Controllers\MessagesController::numberOfUnreadMessages
|
||||
*/
|
||||
public function testNumberOfUnreadMessagesWithNoMessagesReturns0()
|
||||
{
|
||||
|
@ -514,6 +489,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox NumberOfUnreadMessages: withMessagesNotToMe -> messagesNotToMeAreIgnored
|
||||
* @covers \Engelsystem\Controllers\MessagesController::numberOfUnreadMessages
|
||||
*/
|
||||
public function testNumberOfUnreadMessagesWithMessagesNotToMeMessagesNotToMeAreIgnored()
|
||||
{
|
||||
|
@ -526,6 +502,7 @@ class MessagesControllerTest extends ControllerTest
|
|||
|
||||
/**
|
||||
* @testdox NumberOfUnreadMessages: withMessages -> returnsSumOfUnreadMessagesSentToMe
|
||||
* @covers \Engelsystem\Controllers\MessagesController::numberOfUnreadMessages
|
||||
*/
|
||||
public function testNumberOfUnreadMessagesWithMessagesReturnsSumOfUnreadMessagesSentToMe()
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace Engelsystem\Test\Unit\Models\User;
|
|||
|
||||
use Carbon\Carbon;
|
||||
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
|
||||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Models\BaseModel;
|
||||
use Engelsystem\Models\News;
|
||||
use Engelsystem\Models\NewsComment;
|
||||
|
@ -277,45 +276,4 @@ class UserTest extends ModelTest
|
|||
$this->assertContains($question1->id, $answers);
|
||||
$this->assertContains($question2->id, $answers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox nameWithPronoun: pronounsDeactivated -> returnNameOnly
|
||||
*/
|
||||
public function testNameWithPronounPronounsDeactivatedReturnNameOnly()
|
||||
{
|
||||
$user_with_pronoun = User::factory(['name' => 'x'])
|
||||
->has(PersonalData::factory(['pronoun' => 'X']))->create();
|
||||
$user_without_pronoun = User::factory(['name' => 'y'])->create();
|
||||
|
||||
$this->assertEquals('x', $user_with_pronoun->nameWithPronoun());
|
||||
$this->assertEquals('y', $user_without_pronoun->nameWithPronoun());
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox nameWithPronoun: pronounsActivated -> returnNameAndPronoun
|
||||
*/
|
||||
public function testNameWithPronounPronounsActivatedReturnNameAndPronoun()
|
||||
{
|
||||
config(['enable_pronoun' => true]);
|
||||
|
||||
$user_with_pronoun = User::factory(['name' => 'x'])
|
||||
->has(PersonalData::factory(['pronoun' => 'X']))->create();
|
||||
$user_without_pronoun = User::factory(['name' => 'y'])->create();
|
||||
|
||||
$this->assertEquals('x (X)', $user_with_pronoun->nameWithPronoun());
|
||||
$this->assertEquals('y', $user_without_pronoun->nameWithPronoun());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare test
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// config needed for checking if pronouns are activated.
|
||||
$config = new Config();
|
||||
$this->app->instance('config', $config);
|
||||
$this->app->instance(Config::class, $config);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue