This commit is contained in:
frischler 2022-06-04 17:55:26 +02:00 committed by Igor Scheller
parent 2c0d516578
commit 71d183df01
15 changed files with 214 additions and 299 deletions

View File

@ -52,8 +52,8 @@ $route->post('/questions/new', 'QuestionsController@save');
// Messages // Messages
$route->get('/messages', 'MessagesController@index'); $route->get('/messages', 'MessagesController@index');
$route->post('/messages', 'MessagesController@toConversation'); $route->post('/messages', 'MessagesController@redirectToConversation');
$route->get('/messages/{user_id:\d+}', 'MessagesController@conversation'); $route->get('/messages/{user_id:\d+}', 'MessagesController@messagesOfConversation');
$route->post('/messages/{user_id:\d+}', 'MessagesController@send'); $route->post('/messages/{user_id:\d+}', 'MessagesController@send');
$route->post('/messages/{user_id:\d+}/{msg_id:\d+}', 'MessagesController@delete'); $route->post('/messages/{user_id:\d+}/{msg_id:\d+}', 'MessagesController@delete');

View File

@ -350,7 +350,7 @@ code {
} }
.conversation { .conversation {
height: 60vh; height: 55vh;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto overflow-y: auto
} }

View File

@ -155,5 +155,5 @@ msgstr "Eine Beschreibung findest du unter %2$s"
msgid "user.edit.success" msgid "user.edit.success"
msgstr "Benutzer erfolgreich bearbeitet." msgstr "Benutzer erfolgreich bearbeitet."
msgid "messages.delete.success" msgid "message.delete.success"
msgstr "Nachricht erfolgreich gelöscht." msgstr "Nachricht erfolgreich gelöscht."

View File

@ -3031,17 +3031,20 @@ msgstr "Angekommen"
msgid "user.got_shirt" msgid "user.got_shirt"
msgstr "Shirt bekommen" msgstr "Shirt bekommen"
msgid "messages.title" msgid "message.title"
msgstr "Nachrichten" msgstr "Nachrichten"
msgid "messages.choose.an.angel" msgid "message.choose_angel"
msgstr "Wähle einen Engel" msgstr "Wähle einen Engel"
msgid "messages.to.conversation" msgid "message.to_conversation"
msgstr "Zur Konversation" msgstr "Zur Konversation"
msgid "message.message"
msgstr "Nachricht"
msgid "angel" msgid "angel"
msgstr "Engel" msgstr "Engel"
msgid "message" msgid "date"
msgstr "Nachricht" msgstr "Datum"

View File

@ -153,5 +153,5 @@ msgstr "You can find a description at %2$s"
msgid "user.edit.success" msgid "user.edit.success"
msgstr "User edited successfully." msgstr "User edited successfully."
msgid "messages.delete.success" msgid "message.delete.success"
msgstr "Message successfully deleted." msgstr "Message successfully deleted."

View File

@ -301,17 +301,20 @@ msgstr "Arrived"
msgid "user.got_shirt" msgid "user.got_shirt"
msgstr "Got shirt" msgstr "Got shirt"
msgid "messages.title" msgid "message.title"
msgstr "Messages" msgstr "Messages"
msgid "messages.choose.an.angel" msgid "message.choose_angel"
msgstr "Choose an Angel" msgstr "Choose an Angel"
msgid "messages.to.conversation" msgid "message.to_conversation"
msgstr "To Conversation" msgstr "To Conversation"
msgid "message.message"
msgstr "Message"
msgid "angel" msgid "angel"
msgstr "Angel" msgstr "Angel"
msgid "message" msgid "date"
msgstr "Message" msgstr "Date"

View File

@ -1063,11 +1063,6 @@ msgstr "Autor"
msgid "Subject" msgid "Subject"
msgstr "Assunto" 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 #: includes/pages/admin_news.php:34 includes/pages/user_news.php:163
msgid "Meeting" msgid "Meeting"
msgstr "Reunião" 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!" msgid "Please sign up, if you want to help us!"
msgstr "Se você quer nos ajudar, por favor se registre!" 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 #: includes/pages/user_messages.php:26
msgid "Select recipient..." msgid "Select recipient..."
msgstr "Selecionar recipiente..." msgstr "Selecionar recipiente..."

View File

@ -16,11 +16,15 @@
</div> </div>
{% endmacro %} {% endmacro %}
{% macro user(user) %} {% macro user(user, opt) %}
<a href="{{ url('users', {'action': 'view', 'user_id': user.id}) }}" <a href="{{ opt.url|default(url('users', {'action': 'view', 'user_id': user.id})) }}"
{%- if not user.state.arrived %} class="text-muted"{% endif -%} {%- if not user.state.arrived %} class="text-muted"{% endif -%}
> >
{{ _self.angel() }} {{ user.name }} {{ _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> </a>
{% endmacro %} {% endmacro %}

View File

@ -37,12 +37,17 @@
</div> </div>
{%- endmacro %} {%- endmacro %}
{% macro select(name, data, label, selected) %} {% macro select(name, data, label, selected, opt) %}
<div class="mb-3"> <div class="mb-3">
{% if label -%} {% if label -%}
<label class="form-label" for="{{ name }}">{{ label }}</label> <label class="form-label" for="{{ name }}">{{ label }}</label>
{% endif %} {% 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 -%} {% for value,decription in data -%}
<option value="{{ value }}"{% if value == selected %} selected{% endif %}>{{ decription }}</option> <option value="{{ value }}"{% if value == selected %} selected{% endif %}>{{ decription }}</option>
{% endfor %} {% endfor %}

View File

@ -2,13 +2,13 @@
{% import 'macros/base.twig' as m %} {% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %} {% import 'macros/form.twig' as f %}
{% block title %}{{ __('messages.title') }}: {{ other_user.nameWithPronoun() }}{% endblock %} {% block title %}{{ __('message.title') }}: {{ other_user.name }}{% endblock %}
{% block content %} {% block content %}
<div class="container"> <div class="container">
<div class="page-header"> <div class="page-header">
<h1> <h1>
{{ __('messages.title') }}: <span class="icon-icon_angel"></span> {{ other_user.nameWithPronoun() }} {{ __('message.title') }}: {{ m.user(other_user, {'show_pronoun_if_configured': true}) }}
</h1> </h1>
</div> </div>
@ -22,12 +22,12 @@
<div class="message alert alert-secondary position-relative"> <div class="message alert alert-secondary position-relative">
<div>{{ msg.text | nl2br }}</div> <div>{{ msg.text | nl2br }}</div>
<div class="text-end"> <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> </div>
{% if msg.read == false %} {% if msg.read == false %}
<span class="position-absolute top-0 start-100 translate-middle-x p-2 bg-danger rounded-circle"> <span class="position-absolute top-0 start-100 translate-middle-x p-2
<span class="visually-hidden">New alerts</span> bg-danger rounded-circle"></span>
</span>
{% endif %} {% endif %}
</div> </div>
</div> </div>
@ -57,10 +57,11 @@
{{ csrf() }} {{ csrf() }}
<div class="input-group"> <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')) }} {{ f.submit(m.icon('send-fill')) }}
</div> </div>
</form> </form>
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -2,7 +2,7 @@
{% import 'macros/base.twig' as m %} {% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %} {% import 'macros/form.twig' as f %}
{% block title %}{{ __('messages.title') }}{% endblock %} {% block title %}{{ __('message.title') }}{% endblock %}
{% block content %} {% block content %}
<div class="container"> <div class="container">
@ -15,15 +15,11 @@
{{ csrf() }} {{ csrf() }}
<div class="row gx-2 mb-3"> <div class="row gx-2 mb-3">
<div class="col-auto"> <div class="col-auto">
<select id="user_id" name="user_id" class="form-control pe-5" required> {{ f.select('user_id', users, null, null,
<option value="">{{ __('messages.choose.an.angel') }}</option> { 'class': 'pe-5', 'required': true, 'default_option': __('message.choose_angel') }) }}
{% for value,decription in users -%}
<option value="{{ value }}">{{ decription }}</option>
{% endfor %}
</select>
</div> </div>
<div class="col"> <div class="col">
{{ f.submit(__('messages.to.conversation'), {'btn_type': 'secondary'}) }} {{ f.submit(__('message.to_conversation'), {'btn_type': 'secondary'}) }}
</div> </div>
</div> </div>
</form> </form>
@ -32,27 +28,27 @@
<thead> <thead>
<tr> <tr>
<th>{{ __('angel') }}</th> <th>{{ __('angel') }}</th>
<th>{{ __('message') }}</th> <th>{{ __('message.message') }}</th>
<th>{{ __('Date') }}</th> <th>{{ __('date') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for c in conversations %} {% for c in conversations %}
<tr> <tr>
<td> <td>
<span class="icon-icon_angel"></span> {{ m.user(c.other_user, {'show_pronoun_if_configured': true, 'url': url('messages/' ~ c.other_user.id)}) }}
{{ c.other_user.nameWithPronoun() }}
{% if c.unread_messages > 0 %} {% if c.unread_messages > 0 %}
<span class="badge bg-danger">{{ c.unread_messages }}</span> <span class="badge bg-danger">{{ c.unread_messages }}</span>
{% endif %} {% endif %}
</td> </td>
<td> <td>
<a href="{{ url('messages/' ~ c.other_user.id) }}"> <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> </a>
</td> </td>
<td> <td>
{{ c.latest_message.created_at }} {{ c.latest_message.created_at.format(__('Y-m-d H:i')) }}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -10,7 +10,6 @@ use Engelsystem\Http\Response;
use Engelsystem\Models\Message; use Engelsystem\Models\Message;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Illuminate\Database\Query\Expression as QueryExpression; use Illuminate\Database\Query\Expression as QueryExpression;
use Psr\Log\LoggerInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Engelsystem\Http\Exceptions\HttpForbidden; use Engelsystem\Http\Exceptions\HttpForbidden;
@ -19,9 +18,6 @@ class MessagesController extends BaseController
/** @var Authenticator */ /** @var Authenticator */
protected $auth; protected $auth;
/** @var LoggerInterface */
protected $log;
/** @var Redirector */ /** @var Redirector */
protected $redirect; protected $redirect;
@ -47,7 +43,6 @@ class MessagesController extends BaseController
/** /**
* @param Authenticator $auth * @param Authenticator $auth
* @param LoggerInterface $log
* @param Redirector $redirect * @param Redirector $redirect
* @param Response $response * @param Response $response
* @param Request $request * @param Request $request
@ -57,7 +52,6 @@ class MessagesController extends BaseController
*/ */
public function __construct( public function __construct(
Authenticator $auth, Authenticator $auth,
LoggerInterface $log,
Redirector $redirect, Redirector $redirect,
Response $response, Response $response,
Request $request, Request $request,
@ -66,7 +60,6 @@ class MessagesController extends BaseController
User $user User $user
) { ) {
$this->auth = $auth; $this->auth = $auth;
$this->log = $log;
$this->redirect = $redirect; $this->redirect = $redirect;
$this->response = $response; $this->response = $response;
$this->request = $request; $this->request = $request;
@ -75,37 +68,41 @@ class MessagesController extends BaseController
$this->user = $user; $this->user = $user;
} }
/**
* @return Response
*/
public function index(): Response public function index(): Response
{ {
return $this->listConversations(); 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. * the most recent message, and the number of unread messages.
*/ */
public function listConversations(): Response public function listConversations(): Response
{ {
$current_user = $this->auth->user(); $currentUser = $this->auth->user();
$latest_messages = $this->latestMessagePerConversation($current_user); $latestMessages = $this->latestMessagePerConversation($currentUser);
$numberOfUnreadMessages = $this->numberOfUnreadMessagesPerConversation($current_user); $numberOfUnreadMessages = $this->numberOfUnreadMessagesPerConversation($currentUser);
$conversations = []; $conversations = [];
foreach ($latest_messages as $msg) { foreach ($latestMessages as $msg) {
$other_user = $msg->user_id == $current_user->id ? $msg->receiver : $msg->sender; $otherUser = $msg->user_id == $currentUser->id ? $msg->receiver : $msg->sender;
$unread_messages = $numberOfUnreadMessages[$other_user->id] ?? 0; $unreadMessages = $numberOfUnreadMessages[$otherUser->id] ?? 0;
array_push($conversations, [
'other_user' => $other_user, $conversations[] = [
'other_user' => $otherUser,
'latest_message' => $msg, 'latest_message' => $msg,
'unread_messages' => $unread_messages 'unread_messages' => $unreadMessages,
]); ];
} }
$users = $this->user->orderBy('name')->get() $users = $this->user->orderBy('name')->get()
->except($current_user->id) ->except($currentUser->id)
->mapWithKeys(function ($u) { ->mapWithKeys(function ($u) {
return [ $u->id => $u->nameWithPronoun() ]; return [ $u->id => $u->name ];
}); });
return $this->response->withView( 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']); $data = $this->validate($request, ['user_id' => 'required|int']);
return $this->redirect->to('/messages/' . $data['user_id']); 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. * Returns a list of messages between the current user and a user with the given id. Unread messages will be marked
* Unread messages will be marked as read during this call. Still, they will be shown as unread in the frontend to * as read during this call. Still, they will be shown as unread in the frontend to highlight them to the user as new.
* highlight them to the user as new.
*/ */
public function conversation(Request $request): Response public function messagesOfConversation(Request $request): Response
{ {
$current_user = $this->auth->user(); $currentUser = $this->auth->user();
$other_user = $this->user->findOrFail($request->getAttribute('user_id')); $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.'); throw new HttpForbidden('You can not start a conversation with yourself.');
} }
$messages = $this->message $messages = $this->message
->where(function ($q) use ($current_user, $other_user) { ->where(function ($query) use ($currentUser, $otherUser) {
$q->whereUserId($current_user->id) $query->whereUserId($currentUser->id)
->whereReceiverId($other_user->id); ->whereReceiverId($otherUser->id);
}) })
->orWhere(function ($q) use ($current_user, $other_user) { ->orWhere(function ($query) use ($currentUser, $otherUser) {
$q->whereUserId($other_user->id) $query->whereUserId($otherUser->id)
->whereReceiverId($current_user->id); ->whereReceiverId($currentUser->id);
}) })
->orderBy('created_at') ->orderBy('created_at')
->get(); ->get();
$unread_messages = $messages->filter(function ($m) use ($other_user) { $unreadMessages = $messages->filter(function ($m) use ($otherUser) {
return $m->user_id == $other_user->id && !$m->read; return $m->user_id == $otherUser->id && !$m->read;
}); });
foreach ($unread_messages as $msg) { foreach ($unreadMessages as $msg) {
$msg->read = true; $msg->read = true;
$msg->save(); $msg->save();
$msg->read = false; // change back to true to display it to the frontend one more time. $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( return $this->response->withView(
'pages/messages/conversation.twig', '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 public function send(Request $request): Response
{ {
$current_user = $this->auth->user(); $currentUser = $this->auth->user();
$data = $this->validate($request, ['text' => 'required']); $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.'); throw new HttpForbidden('You can not send a message to yourself.');
} }
$new_message = new Message(); $newMessage = new Message();
$new_message->sender()->associate($current_user); $newMessage->sender()->associate($currentUser);
$new_message->receiver()->associate($other_user); $newMessage->receiver()->associate($otherUser);
$new_message->text = $data['text']; $newMessage->text = $data['text'];
$new_message->read = false; $newMessage->read = false;
$new_message->save(); $newMessage->save();
$this->log->info( return $this->redirect->to('/messages/' . $otherUser->id);
'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);
} }
/** /**
* Deletes a message from a given id, as long as this message was send by the current user. The given user_id * 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. * The given user id is used to redirect back to the conversation with that user.
*/ */
public function delete(Request $request): Response public function delete(Request $request): Response
{ {
$current_user = $this->auth->user(); $currentUser = $this->auth->user();
$other_user_id = $request->getAttribute('user_id'); $otherUserId = $request->getAttribute('user_id');
$msg_id = $request->getAttribute('msg_id'); $msgId = $request->getAttribute('msg_id');
$msg = $this->message->findOrFail($msg_id); $msg = $this->message->findOrFail($msgId);
if ($msg->user_id == $current_user->id) { if ($msg->user_id == $currentUser->id) {
$msg->delete(); $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 { } 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'); 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 public function numberOfUnreadMessages(): int
{ {
return $this->auth->user() return $this->auth->user()
@ -247,9 +221,13 @@ class MessagesController extends BaseController
->count(); ->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')) ->select('user_id', $this->raw('count(*) as amount'))
->where('read', false) ->where('read', false)
->groupBy('user_id') ->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')) ->select($this->raw('max(id) as last_id'))
->where('user_id', "=", $current_user->id) ->where('user_id', '=', $currentUser->id)
->orWhere('receiver_id', "=", $current_user->id) ->orWhere('receiver_id', '=', $currentUser->id)
->groupBy($this->raw( ->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 receiver_id ELSE user_id END)'
)); ));
// then getting the full message objects for each ID.
return $this->message return $this->message
->joinSub($latest_message_ids, 'conversations', function ($join) { ->joinSub($latestMessageIds, 'conversations', function ($join) {
$join->on('messages.id', '=', 'conversations.last_id'); $join->on('messages.id', '=', 'conversations.last_id');
}) })
->orderBy('created_at', 'DESC') ->orderBy('created_at', 'DESC')
->get(); ->get();
} }
/**
* @param mixed $value
* @return QueryExpression
*/
protected function raw($value): QueryExpression protected function raw($value): QueryExpression
{ {
return $this->db->getConnection()->raw($value); return $this->db->getConnection()->raw($value);

View File

@ -225,18 +225,4 @@ class User extends BaseModel
->orderBy('read') ->orderBy('read')
->orderBy('id', 'DESC'); ->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;
}
}
} }

View File

@ -11,9 +11,6 @@ use Engelsystem\Http\UrlGenerator;
use Engelsystem\Http\UrlGeneratorInterface; use Engelsystem\Http\UrlGeneratorInterface;
use Engelsystem\Http\Validation\Validator; use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\Message; 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\Models\User\User;
use Engelsystem\Test\Unit\HasDatabase; use Engelsystem\Test\Unit\HasDatabase;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
@ -44,6 +41,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox index: underNormalConditions -> returnsCorrectViewAndData * @testdox index: underNormalConditions -> returnsCorrectViewAndData
* @covers \Engelsystem\Controllers\MessagesController::index
*/ */
public function testIndexUnderNormalConditionsReturnsCorrectViewAndData() public function testIndexUnderNormalConditionsReturnsCorrectViewAndData()
{ {
@ -63,6 +61,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox index: otherUsersExist -> returnsUsersWithoutMeOrderedByName * @testdox index: otherUsersExist -> returnsUsersWithoutMeOrderedByName
* @covers \Engelsystem\Controllers\MessagesController::index
*/ */
public function testIndexOtherUsersExistReturnsUsersWithoutMeOrderedByName() public function testIndexOtherUsersExistReturnsUsersWithoutMeOrderedByName()
{ {
@ -80,56 +79,9 @@ class MessagesControllerTest extends ControllerTest
$this->controller->index(); $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 * @testdox index: withNoConversation -> returnsEmptyConversationList
* @covers \Engelsystem\Controllers\MessagesController::index
*/ */
public function testIndexWithNoConversationReturnsEmptyConversationList() public function testIndexWithNoConversationReturnsEmptyConversationList()
{ {
@ -145,6 +97,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox index: withConversation -> conversationContainsCorrectData * @testdox index: withConversation -> conversationContainsCorrectData
* @covers \Engelsystem\Controllers\MessagesController::index
*/ */
public function testIndexWithConversationConversationContainsCorrectData() public function testIndexWithConversationConversationContainsCorrectData()
{ {
@ -181,6 +134,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox index: withConversations -> onlyContainsConversationsWithMe * @testdox index: withConversations -> onlyContainsConversationsWithMe
* @covers \Engelsystem\Controllers\MessagesController::index
*/ */
public function testIndexWithConversationsOnlyContainsConversationsWithMe() public function testIndexWithConversationsOnlyContainsConversationsWithMe()
{ {
@ -209,6 +163,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox index: withConversations -> conversationsOrderedByDate * @testdox index: withConversations -> conversationsOrderedByDate
* @covers \Engelsystem\Controllers\MessagesController::index
*/ */
public function testIndexWithConversationsConversationsOrderedByDate() 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->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([ $this->request = $this->request->withParsedBody([
'user_id' => '1', 'user_id' => '1',
@ -256,42 +213,47 @@ class MessagesControllerTest extends ControllerTest
->with('http://localhost/messages/1') ->with('http://localhost/messages/1')
->willReturn($this->response); ->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->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->request->attributes->set('user_id', $this->user_a->id);
$this->expectException(HttpForbidden::class); $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->request->attributes->set('user_id', '1234');
$this->expectException(ModelNotFoundException::class); $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); $this->request->attributes->set('user_id', $this->user_b->id);
@ -306,13 +268,14 @@ class MessagesControllerTest extends ControllerTest
return $this->response; 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); $this->request->attributes->set('user_id', $this->user_b->id);
@ -323,13 +286,14 @@ class MessagesControllerTest extends ControllerTest
return $this->response; 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); $this->request->attributes->set('user_id', $this->user_b->id);
@ -356,13 +320,14 @@ class MessagesControllerTest extends ControllerTest
return $this->response; 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->request->attributes->set('user_id', $this->user_b->id);
$this->createMessage($this->user_b, $this->user_a, 'b>a', $this->now); $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); $this->assertFalse($data['messages'][0]->read);
return $this->response; 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->request->attributes->set('user_id', $this->user_b->id);
$this->response->expects($this->once()) $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); $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); $this->assertTrue(Message::whereId($msg->id)->first()->read);
} }
/** /**
* @testdox send: withNoTextGiven -> throwsException * @testdox send: withNoTextGiven -> throwsException
* @covers \Engelsystem\Controllers\MessagesController::send
*/ */
public function testSendWithNoTextGivenThrowsException() public function testSendWithNoTextGivenThrowsException()
{ {
@ -404,6 +371,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox send: withNoUserIdGiven -> throwsException * @testdox send: withNoUserIdGiven -> throwsException
* @covers \Engelsystem\Controllers\MessagesController::send
*/ */
public function testSendWithNoUserIdGivenThrowsException() public function testSendWithNoUserIdGivenThrowsException()
{ {
@ -416,6 +384,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox send: withMyUserIdGiven -> throwsException * @testdox send: withMyUserIdGiven -> throwsException
* @covers \Engelsystem\Controllers\MessagesController::send
*/ */
public function testSendWithMyUserIdGivenThrowsException() public function testSendWithMyUserIdGivenThrowsException()
{ {
@ -424,11 +393,13 @@ class MessagesControllerTest extends ControllerTest
]); ]);
$this->request->attributes->set('user_id', $this->user_a->id); $this->request->attributes->set('user_id', $this->user_a->id);
$this->expectException(HttpForbidden::class); $this->expectException(HttpForbidden::class);
$this->controller->send($this->request); $this->controller->send($this->request);
} }
/** /**
* @testdox send: withUnknownUserIdGiven -> throwsException * @testdox send: withUnknownUserIdGiven -> throwsException
* @covers \Engelsystem\Controllers\MessagesController::send
*/ */
public function testSendWithUnknownUserIdGivenThrowsException() public function testSendWithUnknownUserIdGivenThrowsException()
{ {
@ -442,6 +413,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox send: withUserAndTextGiven -> savesMessage * @testdox send: withUserAndTextGiven -> savesMessage
* @covers \Engelsystem\Controllers\MessagesController::send
*/ */
public function testSendWithUserAndTextGivenSavesMessage() public function testSendWithUserAndTextGivenSavesMessage()
{ {
@ -465,6 +437,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox delete: withNoMsgIdGiven -> throwsException * @testdox delete: withNoMsgIdGiven -> throwsException
* @covers \Engelsystem\Controllers\MessagesController::delete
*/ */
public function testDeleteWithNoMsgIdGivenThrowsException() public function testDeleteWithNoMsgIdGivenThrowsException()
{ {
@ -474,19 +447,20 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox delete: tryingToDeleteSomeonesMessage -> throwsException * @testdox delete: tryingToDeleteSomeonesMessage -> throwsException
* @covers \Engelsystem\Controllers\MessagesController::delete
*/ */
public function testDeleteTryingToDeleteSomeonesMessageThrowsException() public function testDeleteTryingToDeleteSomeonesMessageThrowsException()
{ {
$this->expectException(HttpForbidden::class);
$msg = $this->createMessage($this->user_b, $this->user_a, 'a>b', $this->now); $msg = $this->createMessage($this->user_b, $this->user_a, 'a>b', $this->now);
$this->request->attributes->set('msg_id', $msg->id); $this->request->attributes->set('msg_id', $msg->id);
$this->expectException(HttpForbidden::class);
$this->controller->delete($this->request); $this->controller->delete($this->request);
} }
/** /**
* @testdox delete: tryingToDeleteMyMessage -> deletesItAndRedirect * @testdox delete: tryingToDeleteMyMessage -> deletesItAndRedirect
* @covers \Engelsystem\Controllers\MessagesController::delete
*/ */
public function testDeleteTryingToDeleteMyMessageDeletesItAndRedirect() public function testDeleteTryingToDeleteMyMessageDeletesItAndRedirect()
{ {
@ -506,6 +480,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox NumberOfUnreadMessages: withNoMessages -> returns0 * @testdox NumberOfUnreadMessages: withNoMessages -> returns0
* @covers \Engelsystem\Controllers\MessagesController::numberOfUnreadMessages
*/ */
public function testNumberOfUnreadMessagesWithNoMessagesReturns0() public function testNumberOfUnreadMessagesWithNoMessagesReturns0()
{ {
@ -514,6 +489,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox NumberOfUnreadMessages: withMessagesNotToMe -> messagesNotToMeAreIgnored * @testdox NumberOfUnreadMessages: withMessagesNotToMe -> messagesNotToMeAreIgnored
* @covers \Engelsystem\Controllers\MessagesController::numberOfUnreadMessages
*/ */
public function testNumberOfUnreadMessagesWithMessagesNotToMeMessagesNotToMeAreIgnored() public function testNumberOfUnreadMessagesWithMessagesNotToMeMessagesNotToMeAreIgnored()
{ {
@ -526,6 +502,7 @@ class MessagesControllerTest extends ControllerTest
/** /**
* @testdox NumberOfUnreadMessages: withMessages -> returnsSumOfUnreadMessagesSentToMe * @testdox NumberOfUnreadMessages: withMessages -> returnsSumOfUnreadMessagesSentToMe
* @covers \Engelsystem\Controllers\MessagesController::numberOfUnreadMessages
*/ */
public function testNumberOfUnreadMessagesWithMessagesReturnsSumOfUnreadMessagesSentToMe() public function testNumberOfUnreadMessagesWithMessagesReturnsSumOfUnreadMessagesSentToMe()
{ {

View File

@ -4,7 +4,6 @@ namespace Engelsystem\Test\Unit\Models\User;
use Carbon\Carbon; use Carbon\Carbon;
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
use Engelsystem\Config\Config;
use Engelsystem\Models\BaseModel; use Engelsystem\Models\BaseModel;
use Engelsystem\Models\News; use Engelsystem\Models\News;
use Engelsystem\Models\NewsComment; use Engelsystem\Models\NewsComment;
@ -277,45 +276,4 @@ class UserTest extends ModelTest
$this->assertContains($question1->id, $answers); $this->assertContains($question1->id, $answers);
$this->assertContains($question2->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);
}
} }