News: Rewrite
parent
72f4839130
commit
d323b75501
@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Engelsystem\Models\News;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function admin_news()
|
|
||||||
{
|
|
||||||
$request = request();
|
|
||||||
|
|
||||||
if (!$request->has('action')) {
|
|
||||||
throw_redirect(page_link_to('news'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$html = '<div class="col-md-12"><h1>' . __('Edit news entry') . '</h1>' . msg();
|
|
||||||
if ($request->has('id') && preg_match('/^\d{1,11}$/', $request->input('id'))) {
|
|
||||||
$news_id = $request->input('id');
|
|
||||||
} else {
|
|
||||||
return error('Incomplete call, missing News ID.', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$news = News::find($news_id);
|
|
||||||
if (empty($news)) {
|
|
||||||
return error('No News found.', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($request->input('action')) {
|
|
||||||
case 'edit':
|
|
||||||
$user_source = $news->user;
|
|
||||||
if (
|
|
||||||
!auth()->can('admin_news_html')
|
|
||||||
&& strip_tags($news->text) != $news->text
|
|
||||||
) {
|
|
||||||
$html .= warning(
|
|
||||||
__('This message contains HTML. After saving the post some formatting will be lost!'),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$html .= form(
|
|
||||||
[
|
|
||||||
form_info(__('Date'), $news->created_at->format(__('Y-m-d H:i'))),
|
|
||||||
form_info(__('Author'), User_Nick_render($user_source)),
|
|
||||||
form_text('eBetreff', __('Subject'), $news->title),
|
|
||||||
form_textarea('eText', __('Message'), $news->text),
|
|
||||||
form_checkbox('eTreffen', __('Meeting'), $news->is_meeting, 1),
|
|
||||||
form_submit('submit', __('Save'))
|
|
||||||
],
|
|
||||||
page_link_to('admin_news', ['action' => 'save', 'id' => $news_id])
|
|
||||||
);
|
|
||||||
|
|
||||||
$html .= '<a class="btn btn-danger" href="'
|
|
||||||
. page_link_to('admin_news', ['action' => 'delete', 'id' => $news_id])
|
|
||||||
. '">'
|
|
||||||
. '<span class="glyphicon glyphicon-trash"></span> ' . __('Delete')
|
|
||||||
. '</a>';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'save':
|
|
||||||
$text = $request->postData('eText');
|
|
||||||
if (!auth()->can('admin_news_html')) {
|
|
||||||
$text = strip_tags($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
$news->title = strip_tags($request->postData('eBetreff'));
|
|
||||||
$news->text = $text;
|
|
||||||
$news->is_meeting = $request->has('eTreffen');
|
|
||||||
$news->save();
|
|
||||||
|
|
||||||
engelsystem_log('News updated: ' . $request->postData('eBetreff'));
|
|
||||||
success(__('News entry updated.'));
|
|
||||||
throw_redirect(page_link_to('news'));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'delete':
|
|
||||||
$news->delete();
|
|
||||||
engelsystem_log('News deleted: ' . $news->title);
|
|
||||||
success(__('News entry deleted.'));
|
|
||||||
throw_redirect(page_link_to('news'));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw_redirect(page_link_to('news'));
|
|
||||||
}
|
|
||||||
return $html . '</div>';
|
|
||||||
}
|
|
@ -1,247 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Engelsystem\Models\News;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function user_news_comments_title()
|
|
||||||
{
|
|
||||||
return __('News comments');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function news_title()
|
|
||||||
{
|
|
||||||
return __('News');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function meetings_title()
|
|
||||||
{
|
|
||||||
return __('Meetings');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function user_meetings()
|
|
||||||
{
|
|
||||||
$display_news = config('display_news');
|
|
||||||
$html = '<div class="container">';
|
|
||||||
$html .= '<h1>' . meetings_title() . '</h1>' . msg();
|
|
||||||
$request = request();
|
|
||||||
|
|
||||||
if (preg_match('/^\d{1,}$/', $request->input('page', 0))) {
|
|
||||||
$page = $request->input('page', 0);
|
|
||||||
} else {
|
|
||||||
$page = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$news = News::whereIsMeeting(true)
|
|
||||||
->orderBy('created_at', 'DESC')
|
|
||||||
->limit($display_news)
|
|
||||||
->offset($page * $display_news)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
foreach ($news as $entry) {
|
|
||||||
$html .= display_news($entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
$dis_rows = ceil(News::whereIsMeeting(true)->count() / $display_news);
|
|
||||||
$html .= '<div class="text-center">' . '<ul class="pagination">';
|
|
||||||
for ($i = 0; $i < $dis_rows; $i++) {
|
|
||||||
if ($request->has('page') && $i == $request->input('page', 0)) {
|
|
||||||
$html .= '<li class="active">';
|
|
||||||
} elseif (!$request->has('page') && $i == 0) {
|
|
||||||
$html .= '<li class="active">';
|
|
||||||
} else {
|
|
||||||
$html .= '<li>';
|
|
||||||
}
|
|
||||||
$html .= '<a href="' . page_link_to('user_meetings', ['page' => $i]) . '">' . ($i + 1) . '</a></li>';
|
|
||||||
}
|
|
||||||
$html .= '</ul></div></div>';
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the text content of a news entry
|
|
||||||
*
|
|
||||||
* @param News $news
|
|
||||||
* @return string HTML
|
|
||||||
*/
|
|
||||||
function news_text(News $news): string
|
|
||||||
{
|
|
||||||
$text = preg_replace("/\r\n\r\n/m", '<br><br>', $news->text);
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param News $news
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function display_news(News $news): string
|
|
||||||
{
|
|
||||||
$html = '';
|
|
||||||
$html .= '<div class="panel' . ($news->is_meeting ? ' panel-info' : ' panel-default') . '">';
|
|
||||||
$html .= '<div class="panel-heading">';
|
|
||||||
$html .= '<h3 class="panel-title">' . ($news->is_meeting ? '[Meeting] ' : '') . $news->title . '</h3>';
|
|
||||||
$html .= '</div>';
|
|
||||||
$html .= '<div class="panel-body">' . news_text($news) . '</div>';
|
|
||||||
|
|
||||||
$html .= '<div class="panel-footer text-muted">';
|
|
||||||
if (auth()->can('admin_news')) {
|
|
||||||
$html .= '<div class="pull-right">'
|
|
||||||
. button_glyph(
|
|
||||||
page_link_to('admin_news', ['action' => 'edit', 'id' => $news->id]),
|
|
||||||
'edit',
|
|
||||||
'btn-xs'
|
|
||||||
)
|
|
||||||
. '</div>';
|
|
||||||
}
|
|
||||||
$html .= '<span class="glyphicon glyphicon-time"></span> ' . $news->created_at->format(__('Y-m-d H:i')) . ' ';
|
|
||||||
|
|
||||||
$html .= User_Nick_render($news->user);
|
|
||||||
if (current_page() != 'news_comments') {
|
|
||||||
$html .= ' <a href="' . page_link_to('news_comments', ['nid' => $news->id]) . '">'
|
|
||||||
. '<span class="glyphicon glyphicon-comment"></span> '
|
|
||||||
. __('Comments') . ' »</a> '
|
|
||||||
. '<span class="badge">'
|
|
||||||
. $news->comments()->count()
|
|
||||||
. '</span>';
|
|
||||||
}
|
|
||||||
$html .= '</div>';
|
|
||||||
$html .= '</div>';
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function user_news_comments()
|
|
||||||
{
|
|
||||||
$user = auth()->user();
|
|
||||||
$request = request();
|
|
||||||
|
|
||||||
$html = '<div class="container">';
|
|
||||||
$html .= '<h1>' . user_news_comments_title() . '</h1>';
|
|
||||||
$nid = $request->input('nid');
|
|
||||||
if (
|
|
||||||
$request->has('nid')
|
|
||||||
&& preg_match('/^\d{1,}$/', $nid)
|
|
||||||
&& $news = News::find($nid)
|
|
||||||
) {
|
|
||||||
if ($request->hasPostData('submit') && $request->has('text')) {
|
|
||||||
$text = $request->input('text');
|
|
||||||
$news->comments()->create([
|
|
||||||
'text' => $text,
|
|
||||||
'user_id' => $user->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
engelsystem_log('Created news_comment: ' . $text);
|
|
||||||
$html .= success(__('Entry saved.'), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$html .= display_news($news);
|
|
||||||
|
|
||||||
foreach ($news->comments as $comment) {
|
|
||||||
$html .= '<div class="panel panel-default">';
|
|
||||||
$html .= '<div class="panel-body">' . nl2br(htmlspecialchars($comment->text)) . '</div>';
|
|
||||||
$html .= '<div class="panel-footer text-muted">';
|
|
||||||
$html .= '<span class="glyphicon glyphicon-time"></span> ' . $comment->created_at->format(__('Y-m-d H:i')) . ' ';
|
|
||||||
$html .= User_Nick_render($comment->user);
|
|
||||||
$html .= '</div>';
|
|
||||||
$html .= '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$html .= '<hr /><h2>' . __('New Comment:') . '</h2>';
|
|
||||||
$html .= form([
|
|
||||||
form_textarea('text', __('Message'), ''),
|
|
||||||
form_submit('submit', __('Save'))
|
|
||||||
], page_link_to('news_comments', ['nid' => $news->id]));
|
|
||||||
} else {
|
|
||||||
$html .= __('Invalid request.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $html . '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function user_news()
|
|
||||||
{
|
|
||||||
$user = auth()->user();
|
|
||||||
$display_news = config('display_news');
|
|
||||||
$request = request();
|
|
||||||
|
|
||||||
$html = '<div class="container">';
|
|
||||||
$html .= '<h1>' . news_title() . '</h1>' . msg();
|
|
||||||
|
|
||||||
$isMeeting = $request->postData('treffen', false);
|
|
||||||
if ($request->has('text') && $request->has('betreff') && auth()->can('admin_news')) {
|
|
||||||
$text = $request->postData('text');
|
|
||||||
if (!auth()->can('admin_news_html')) {
|
|
||||||
$text = strip_tags($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
$news = News::create([
|
|
||||||
'title' => strip_tags($request->postData('betreff')),
|
|
||||||
'text' => $text,
|
|
||||||
'user_id' => $user->id,
|
|
||||||
'is_meeting' => (bool)$isMeeting,
|
|
||||||
]);
|
|
||||||
|
|
||||||
engelsystem_log('Created news: ' . $news->title . ', is meeting: ' . ($news->is_meeting ? 'yes' : 'no'));
|
|
||||||
success(__('Entry saved.'));
|
|
||||||
throw_redirect(page_link_to('news'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preg_match('/^\d{1,}$/', $request->input('page', 0))) {
|
|
||||||
$page = $request->input('page', 0);
|
|
||||||
} else {
|
|
||||||
$page = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$news = News::query()
|
|
||||||
->orderBy('created_at', 'DESC')
|
|
||||||
->limit($display_news)
|
|
||||||
->offset($page * $display_news)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
foreach ($news as $entry) {
|
|
||||||
$html .= display_news($entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
$dis_rows = ceil(News::query()->count() / $display_news);
|
|
||||||
$html .= '<div class="text-center">' . '<ul class="pagination">';
|
|
||||||
for ($i = 0; $i < $dis_rows; $i++) {
|
|
||||||
if ($request->has('page') && $i == $request->input('page', 0)) {
|
|
||||||
$html .= '<li class="active">';
|
|
||||||
} elseif (!$request->has('page') && $i == 0) {
|
|
||||||
$html .= '<li class="active">';
|
|
||||||
} else {
|
|
||||||
$html .= '<li>';
|
|
||||||
}
|
|
||||||
$html .= '<a href="' . page_link_to('news', ['page' => $i]) . '">' . ($i + 1) . '</a></li>';
|
|
||||||
}
|
|
||||||
$html .= '</ul></div>';
|
|
||||||
|
|
||||||
if (auth()->can('admin_news')) {
|
|
||||||
$html .= '<hr />';
|
|
||||||
$html .= '<h2>' . __('Create news:') . '</h2>';
|
|
||||||
|
|
||||||
$html .= form([
|
|
||||||
form_text('betreff', __('Subject'), ''),
|
|
||||||
form_textarea('text', __('Message'), ''),
|
|
||||||
form_checkbox('treffen', __('Meeting'), false, 1),
|
|
||||||
form_submit('submit', __('Save'))
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
return $html . '</div>';
|
|
||||||
}
|
|
@ -0,0 +1,62 @@
|
|||||||
|
{% extends 'layouts/app.twig' %}
|
||||||
|
{% import 'macros/base.twig' as m %}
|
||||||
|
{% import 'macros/form.twig' as f %}
|
||||||
|
|
||||||
|
{% block title %}{{ news ? __('news.edit.edit') : __('news.edit.add') }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<h1>{{ block('title') }}</h1>
|
||||||
|
|
||||||
|
{% include 'layouts/parts/messages.twig' %}
|
||||||
|
|
||||||
|
{% if news %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<p>
|
||||||
|
{{ m.glyphicon('time') }} {{ news.updated_at.format(__('Y-m-d H:i')) }}
|
||||||
|
|
||||||
|
{% if news.updated_at != news.created_at %}
|
||||||
|
 {{ __('news.updated') }}
|
||||||
|
<br>
|
||||||
|
{{ m.glyphicon('time') }} {{ news.created_at.format(__('Y-m-d H:i')) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
 {{ m.user(news.user) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="" enctype="multipart/form-data" method="post">
|
||||||
|
{{ csrf() }}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{{ f.input(
|
||||||
|
'title',
|
||||||
|
__('news.edit.subject'),
|
||||||
|
null,
|
||||||
|
{'required': true, 'value': news ? news.title : ''}
|
||||||
|
) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{{ f.checkbox('is_meeting', __('news.edit.is_meeting'), news ? news.is_meeting : false) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{{ f.textarea('text', __('news.edit.message'), {'required': true, 'rows': 10, 'value': news ? news.text : ''}) }}
|
||||||
|
|
||||||
|
{{ f.submit() }}
|
||||||
|
|
||||||
|
{% if news %}
|
||||||
|
{{ f.submit(m.glyphicon('trash'), {'name': 'delete', 'btn_type': 'danger'}) }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,45 @@
|
|||||||
|
{% extends 'pages/news/overview.twig' %}
|
||||||
|
{% import 'macros/base.twig' as m %}
|
||||||
|
{% import 'macros/form.twig' as f %}
|
||||||
|
|
||||||
|
{% block title %}{{ news.title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block news %}
|
||||||
|
{{ _self.news(news) }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block comments %}
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h2>{{ __('news.comments') }}</h2>
|
||||||
|
|
||||||
|
{% for comment in news.comments %}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ comment.text|nl2br }}
|
||||||
|
</div>
|
||||||
|
<div class="panel-footer text-muted">
|
||||||
|
{{ m.glyphicon('time') }}
|
||||||
|
{{ comment.created_at.format(__('Y-m-d H:i')) }}
|
||||||
|
|
||||||
|
{{ m.user(comment.user) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block write_comment %}
|
||||||
|
{% if has_permission_to('news_comments') %}
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h3>{{ __('news.comments.new') }}</h3>
|
||||||
|
|
||||||
|
<form action="" enctype="multipart/form-data" method="post">
|
||||||
|
{{ csrf() }}
|
||||||
|
|
||||||
|
{{ f.textarea('comment', __('news.comments.message'), {'required': true}) }}
|
||||||
|
|
||||||
|
{{ f.submit() }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,93 @@
|
|||||||
|
{% extends 'layouts/app.twig' %}
|
||||||
|
{% import 'macros/base.twig' as m %}
|
||||||
|
|
||||||
|
{% block title %}{{ not only_meetings|default(false) ? __('news.title') : __('news.title.meetings') }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<h1>
|
||||||
|
{{ block('title') }}
|
||||||
|
{%- if has_permission_to('admin_news') and is_overview|default(false) -%}
|
||||||
|
{{ m.button(__('news.add'), url('admin/news')) }}
|
||||||
|
{%- endif %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{% include 'layouts/parts/messages.twig' %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{% block news %}
|
||||||
|
{% for news in news %}
|
||||||
|
{{ _self.news(news, true, is_overview) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block comments %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block pagination %}
|
||||||
|
{% if pages|default(0) > 1 %}
|
||||||
|
<div class="col-md-12 text-center">
|
||||||
|
<ul class="pagination">
|
||||||
|
{% for p in range(1, pages) %}
|
||||||
|
<li{% if p == page %} class="active"{% endif %}>
|
||||||
|
<a href="{{ url('news', p == 1 ? {} : {'page': p}) }}">{{ p }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block write_comment %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% macro news(news, show_comments_link, is_overview) %}
|
||||||
|
<div class="panel {% if not news.is_meeting %}panel-default{% else %}panel-info{% endif %}">
|
||||||
|
{% if is_overview|default(false) %}
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">
|
||||||
|
<a href="{{ url('news/' ~ news.id) }}">
|
||||||
|
{% if news.is_meeting %}{{ __('news.is_meeting') }}{% endif %}
|
||||||
|
{{ news.title }}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ news.text|raw|nl2br }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-footer text-muted">
|
||||||
|
{{ m.glyphicon('time') }} {{ news.updated_at.format(__('Y-m-d H:i')) }}
|
||||||
|
|
||||||
|
{% if news.updated_at != news.created_at and not is_overview %}
|
||||||
|
 {{ __('news.updated') }}
|
||||||
|
|
||||||
|
<br>
|
||||||
|
{{ m.glyphicon('time') }} {{ news.created_at.format(__('Y-m-d H:i')) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
 {{ m.user(news.user) }}
|
||||||
|
|
||||||
|
{% if show_comments_link|default(false) %}
|
||||||
|
 
|
||||||
|
<a href="{{ url('news/' ~ news.id) }}">
|
||||||
|
{{ m.glyphicon('comment') }} {{ __('news.comments') }} »
|
||||||
|
</a>
|
||||||
|
<span class="badge">{{ news.comments.count() }}</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if has_permission_to('admin_news') %}
|
||||||
|
<div class="pull-right">
|
||||||
|
{{ m.button(m.glyphicon('edit'), url('admin/news/' ~ news.id), null, 'xs') }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Controllers\Admin;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\BaseController;
|
||||||
|
use Engelsystem\Controllers\HasUserNotifications;
|
||||||
|
use Engelsystem\Helpers\Authenticator;
|
||||||
|
use Engelsystem\Http\Redirector;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Models\News;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class NewsController extends BaseController
|
||||||
|
{
|
||||||
|
use HasUserNotifications;
|
||||||
|
|
||||||
|
/** @var Authenticator */
|
||||||
|
protected $auth;
|
||||||
|
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
protected $log;
|
||||||
|
|
||||||
|
/** @var News */
|
||||||
|
protected $news;
|
||||||
|
|
||||||
|
/** @var Redirector */
|
||||||
|
protected $redirect;
|
||||||
|
|
||||||
|
/** @var Response */
|
||||||
|
protected $response;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $permissions = [
|
||||||
|
'admin_news',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Authenticator $auth
|
||||||
|
* @param LoggerInterface $log
|
||||||
|
* @param News $news
|
||||||
|
* @param Redirector $redirector
|
||||||
|
* @param Response $response
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Authenticator $auth,
|
||||||
|
LoggerInterface $log,
|
||||||
|
News $news,
|
||||||
|
Redirector $redirector,
|
||||||
|
Response $response
|
||||||
|
) {
|
||||||
|
$this->auth = $auth;
|
||||||
|
$this->log = $log;
|
||||||
|
$this->news = $news;
|
||||||
|
$this->redirect = $redirector;
|
||||||
|
$this->response = $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function edit(Request $request): Response
|
||||||
|
{
|
||||||
|
$id = $request->getAttribute('id');
|
||||||
|
$news = $this->news->find($id);
|
||||||
|
|
||||||
|
if (
|
||||||
|
$news
|
||||||
|
&& !$this->auth->can('admin_news_html')
|
||||||
|
&& strip_tags($news->text) != $news->text
|
||||||
|
) {
|
||||||
|
$this->addNotification('news.edit.contains-html', 'warnings');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response->withView(
|
||||||
|
'pages/news/edit.twig',
|
||||||
|
['news' => $news] + $this->getNotifications()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function save(Request $request): Response
|
||||||
|
{
|
||||||
|
$id = $request->getAttribute('id');
|
||||||
|
/** @var News $news */
|
||||||
|
$news = $this->news->findOrNew($id);
|
||||||
|
|
||||||
|
$data = $this->validate($request, [
|
||||||
|
'title' => 'required',
|
||||||
|
'text' => 'required',
|
||||||
|
'is_meeting' => 'optional|checked',
|
||||||
|
'delete' => 'optional|checked',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!is_null($data['delete'])) {
|
||||||
|
$news->delete();
|
||||||
|
|
||||||
|
$this->log->info(
|
||||||
|
'Deleted {type} "{news}"',
|
||||||
|
[
|
||||||
|
'type' => $news->is_meeting ? 'meeting' : 'news',
|
||||||
|
'news' => $news->title
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->addNotification('news.delete.success');
|
||||||
|
|
||||||
|
return $this->redirect->to('/news');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->auth->can('admin_news_html')) {
|
||||||
|
$data['text'] = strip_tags($data['text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$news->user) {
|
||||||
|
$news->user()->associate($this->auth->user());
|
||||||
|
}
|
||||||
|
$news->title = $data['title'];
|
||||||
|
$news->text = $data['text'];
|
||||||
|
$news->is_meeting = !is_null($data['is_meeting']);
|
||||||
|
$news->save();
|
||||||
|
|
||||||
|
$this->log->info(
|
||||||
|
'Updated {type} "{news}": {text}',
|
||||||
|
[
|
||||||
|
'type' => $news->is_meeting ? 'meeting' : 'news',
|
||||||
|
'news' => $news->title,
|
||||||
|
'text' => $news->text,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->addNotification('news.edit.success');
|
||||||
|
|
||||||
|
return $this->redirect->to('/news/' . $news->id);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Controllers;
|
||||||
|
|
||||||
|
use Engelsystem\Config\Config;
|
||||||
|
use Engelsystem\Helpers\Authenticator;
|
||||||
|
use Engelsystem\Http\Redirector;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Models\News;
|
||||||
|
use Engelsystem\Models\NewsComment;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class NewsController extends BaseController
|
||||||
|
{
|
||||||
|
use HasUserNotifications;
|
||||||
|
|
||||||
|
/** @var Authenticator */
|
||||||
|
protected $auth;
|
||||||
|
|
||||||
|
/** @var Config */
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
protected $log;
|
||||||
|
|
||||||
|
/** @var News */
|
||||||
|
protected $news;
|
||||||
|
|
||||||
|
/** @var Redirector */
|
||||||
|
protected $redirect;
|
||||||
|
|
||||||
|
/** @var Response */
|
||||||
|
protected $response;
|
||||||
|
|
||||||
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $permissions = [
|
||||||
|
'news',
|
||||||
|
'meetings' => 'user_meetings',
|
||||||
|
'comment' => 'news_comments',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Authenticator $auth
|
||||||
|
* @param Config $config
|
||||||
|
* @param LoggerInterface $log
|
||||||
|
* @param News $news
|
||||||
|
* @param Redirector $redirector
|
||||||
|
* @param Response $response
|
||||||
|
* @param Request $request
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Authenticator $auth,
|
||||||
|
Config $config,
|
||||||
|
LoggerInterface $log,
|
||||||
|
News $news,
|
||||||
|
Redirector $redirector,
|
||||||
|
Response $response,
|
||||||
|
Request $request
|
||||||
|
) {
|
||||||
|
$this->auth = $auth;
|
||||||
|
$this->config = $config;
|
||||||
|
$this->log = $log;
|
||||||
|
$this->news = $news;
|
||||||
|
$this->redirect = $redirector;
|
||||||
|
$this->response = $response;
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return $this->showOverview();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function meetings(): Response
|
||||||
|
{
|
||||||
|
return $this->showOverview(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function show(Request $request): Response
|
||||||
|
{
|
||||||
|
$news = $this->news
|
||||||
|
->with('user')
|
||||||
|
->with('comments')
|
||||||
|
->findOrFail($request->getAttribute('id'));
|
||||||
|
|
||||||
|
return $this->renderView('pages/news/news.twig', ['news' => $news]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function comment(Request $request): Response
|
||||||
|
{
|
||||||
|
$data = $this->validate($request, [
|
||||||
|
'comment' => 'required',
|
||||||
|
]);
|
||||||
|
$user = $this->auth->user();
|
||||||
|
$news = $this->news
|
||||||
|
->findOrFail($request->getAttribute('id'));
|
||||||
|
|
||||||
|
/** @var NewsComment $comment */
|
||||||
|
$comment = $news->comments()->create([
|
||||||
|
'text' => $data['comment'],
|
||||||
|
'user_id' => $user->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->log->info(
|
||||||
|
'Created news comment for "{news}": {comment}',
|
||||||
|
[
|
||||||
|
'news' => $news->title,
|
||||||
|
'comment' => $comment->text,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->addNotification('news.comment.success');
|
||||||
|
|
||||||
|
return $this->redirect->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $onlyMeetings
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
protected function showOverview(bool $onlyMeetings = false): Response
|
||||||
|
{
|
||||||
|
$query = $this->news;
|
||||||
|
$page = $this->request->get('page', 1);
|
||||||
|
$perPage = $this->config->get('display_news');
|
||||||
|
|
||||||
|
if ($onlyMeetings) {
|
||||||
|
$query = $query->where('is_meeting', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$news = $query
|
||||||
|
->with('user')
|
||||||
|
->withCount('comments')
|
||||||
|
->orderByDesc('updated_at')
|
||||||
|
->limit($perPage)
|
||||||
|
->offset(($page - 1) * $perPage)
|
||||||
|
->get();
|
||||||
|
$pagesCount = ceil($query->count() / $perPage);
|
||||||
|
|
||||||
|
return $this->renderView(
|
||||||
|
'pages/news/overview.twig',
|
||||||
|
[
|
||||||
|
'news' => $news,
|
||||||
|
'pages' => max(1, $pagesCount),
|
||||||
|
'page' => max(1, min($page, $pagesCount)),
|
||||||
|
'only_meetings' => $onlyMeetings,
|
||||||
|
'is_overview' => true,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $page
|
||||||
|
* @param array $data
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
protected function renderView(string $page, array $data): Response
|
||||||
|
{
|
||||||
|
$data += $this->getNotifications();
|
||||||
|
|
||||||
|
return $this->response->withView($page, $data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,265 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Controllers\Admin;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\Admin\NewsController;
|
||||||
|
use Engelsystem\Helpers\Authenticator;
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use Engelsystem\Models\News;
|
||||||
|
use Engelsystem\Models\User\User;
|
||||||
|
use Engelsystem\Test\Unit\HasDatabase;
|
||||||
|
use Engelsystem\Test\Unit\TestCase;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Psr\Log\Test\TestLogger;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Session;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||||
|
|
||||||
|
class NewsControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
use HasDatabase;
|
||||||
|
|
||||||
|
/** @var Authenticator|MockObject */
|
||||||
|
protected $auth;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $data = [
|
||||||
|
[
|
||||||
|
'title' => 'Foo',
|
||||||
|
'text' => '<b>foo</b>',
|
||||||
|
'is_meeting' => false,
|
||||||
|
'user_id' => 1,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var TestLogger */
|
||||||
|
protected $log;
|
||||||
|
|
||||||
|
/** @var Response|MockObject */
|
||||||
|
protected $response;
|
||||||
|
|
||||||
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\NewsController::edit
|
||||||
|
*/
|
||||||
|
public function testEditHtmlWarning()
|
||||||
|
{
|
||||||
|
$this->request->attributes->set('id', 1);
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('withView')
|
||||||
|
->willReturnCallback(function ($view, $data) {
|
||||||
|
$this->assertEquals('pages/news/edit.twig', $view);
|
||||||
|
|
||||||
|
/** @var Collection $warnings */
|
||||||
|
$warnings = $data['warnings'];
|
||||||
|
$this->assertNotEmpty($data['news']);
|
||||||
|
$this->assertTrue($warnings->isNotEmpty());
|
||||||
|
$this->assertEquals('news.edit.contains-html', $warnings->first());
|
||||||
|
|
||||||
|
return $this->response;
|
||||||
|
});
|
||||||
|
$this->addUser();
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
|
||||||
|
$controller->edit($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\NewsController::__construct
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\NewsController::edit
|
||||||
|
*/
|
||||||
|
public function testEdit()
|
||||||
|
{
|
||||||
|
$this->request->attributes->set('id', 1);
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('withView')
|
||||||
|
->willReturnCallback(function ($view, $data) {
|
||||||
|
$this->assertEquals('pages/news/edit.twig', $view);
|
||||||
|
|
||||||
|
/** @var Collection $warnings */
|
||||||
|
$warnings = $data['warnings'];
|
||||||
|
$this->assertNotEmpty($data['news']);
|
||||||
|
$this->assertTrue($warnings->isEmpty());
|
||||||
|
|
||||||
|
return $this->response;
|
||||||
|
});
|
||||||
|
$this->auth->expects($this->once())
|
||||||
|
->method('can')
|
||||||
|
->with('admin_news_html')
|
||||||
|
->willReturn(true);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
|
||||||
|
$controller->edit($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\NewsController::save
|
||||||
|
*/
|
||||||
|
public function testSaveCreateInvalid()
|
||||||
|
{
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
|
||||||
|
$this->expectException(ValidationException::class);
|
||||||
|
$controller->save($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function saveCreateEditProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Some <b>test</b>', true, true, 'Some <b>test</b>'],
|
||||||
|
['Some <b>test</b>', false, false, 'Some test'],
|
||||||
|
['Some <b>test</b>', false, true, 'Some <b>test</b>', 1],
|
||||||
|
['Some <b>test</b>', true, false, 'Some test', 1],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\NewsController::save
|
||||||
|
* @dataProvider saveCreateEditProvider
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param bool $isMeeting
|
||||||
|
* @param bool $canEditHtml
|
||||||
|
* @param string $result
|
||||||
|
* @param int|null $id
|
||||||
|
*/
|
||||||
|
public function testSaveCreateEdit(
|
||||||
|
string $text,
|
||||||
|
bool $isMeeting,
|
||||||
|
bool $canEditHtml,
|
||||||
|
string $result,
|
||||||
|
int $id = null
|
||||||
|
) {
|
||||||
|
$this->request->attributes->set('id', $id);
|
||||||
|
$id = $id ?: 2;
|
||||||
|
$this->request = $this->request->withParsedBody([
|
||||||
|
'title' => 'Some Title',
|
||||||
|
'text' => $text,
|
||||||
|
'is_meeting' => $isMeeting ? '1' : null,
|
||||||
|
]);
|
||||||
|
$this->addUser();
|
||||||
|
$this->auth->expects($this->once())
|
||||||
|
->method('can')
|
||||||
|
->with('admin_news_html')
|
||||||
|
->willReturn($canEditHtml);
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('redirectTo')
|
||||||
|
->with('/news/' . $id)
|
||||||
|
->willReturn($this->response);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
|
||||||
|
$controller->save($this->request);
|
||||||
|
|
||||||
|
$this->assertTrue($this->log->hasInfoThatContains('Updated'));
|
||||||
|
|
||||||
|
/** @var Session $session */
|
||||||
|
$session = $this->app->get('session');
|
||||||
|
$messages = $session->get('messages');
|
||||||
|
$this->assertEquals('news.edit.success', $messages[0]);
|
||||||
|
|
||||||
|
$news = (new News())->find($id);
|
||||||
|
$this->assertEquals($result, $news->text);
|
||||||
|
$this->assertEquals($isMeeting, (bool)$news->is_meeting);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\NewsController::save
|
||||||
|
*/
|
||||||
|
public function testSaveDelete()
|
||||||
|
{
|
||||||
|
$this->request->attributes->set('id', 1);
|
||||||
|
$this->request = $this->request->withParsedBody([
|
||||||
|
'title' => '.',
|
||||||
|
'text' => '.',
|
||||||
|
'delete' => '1',
|
||||||
|
]);
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('redirectTo')
|
||||||
|
->with('/news')
|
||||||
|
->willReturn($this->response);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
|
||||||
|
$controller->save($this->request);
|
||||||
|
|
||||||
|
$this->assertTrue($this->log->hasInfoThatContains('Deleted'));
|
||||||
|
|
||||||
|
/** @var Session $session */
|
||||||
|
$session = $this->app->get('session');
|
||||||
|
$messages = $session->get('messages');
|
||||||
|
$this->assertEquals('news.delete.success', $messages[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup environment
|
||||||
|
*/
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->initDatabase();
|
||||||
|
|
||||||
|
$this->request = new Request();
|
||||||
|
$this->app->instance(Request::class, $this->request);
|
||||||
|
$this->app->instance(ServerRequestInterface::class, $this->request);
|
||||||
|
|
||||||
|
$this->response = $this->createMock(Response::class);
|
||||||
|
$this->app->instance(Response::class, $this->response);
|
||||||
|
|
||||||
|
$this->log = new TestLogger();
|
||||||
|
$this->app->instance(LoggerInterface::class, $this->log);
|
||||||
|
|
||||||
|
$this->app->instance('session', new Session(new MockArraySessionStorage()));
|
||||||
|
|
||||||
|
$this->auth = $this->createMock(Authenticator::class);
|
||||||
|
$this->app->instance(Authenticator::class, $this->auth);
|
||||||
|
|
||||||
|
(new News([
|
||||||
|
'title' => 'Foo',
|
||||||
|
'text' => '<b>foo</b>',
|
||||||
|
'is_meeting' => false,
|
||||||
|
'user_id' => 1,
|
||||||
|
]))->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user
|
||||||
|
*/
|
||||||
|
protected function addUser()
|
||||||
|
{
|
||||||
|
$user = new User([
|
||||||
|
'name' => 'foo',
|
||||||
|
'password' => '',
|
||||||
|
'email' => '',
|
||||||
|
'api_key' => '',
|
||||||
|
'last_login_at' => null,
|
||||||
|
]);
|
||||||
|
$user->forceFill(['id' => 42]);
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$this->auth->expects($this->any())
|
||||||
|
->method('user')
|
||||||
|
->willReturn($user);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,274 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Controllers;
|
||||||
|
|
||||||
|
use Engelsystem\Config\Config;
|
||||||
|
use Engelsystem\Controllers\NewsController;
|
||||||
|
use Engelsystem\Helpers\Authenticator;
|
||||||
|
use Engelsystem\Http\Exceptions\ValidationException;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Http\Validation\Validator;
|
||||||
|
use Engelsystem\Models\News;
|
||||||
|
use Engelsystem\Models\NewsComment;
|
||||||
|
use Engelsystem\Models\User\User;
|
||||||
|
use Engelsystem\Test\Unit\HasDatabase;
|
||||||
|
use Engelsystem\Test\Unit\TestCase;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Psr\Log\Test\TestLogger;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Session;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||||
|
|
||||||
|
class NewsControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
use HasDatabase;
|
||||||
|
|
||||||
|
/** @var Authenticator|MockObject */
|
||||||
|
protected $auth;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $data = [
|
||||||
|
[
|
||||||
|
'title' => 'Foo',
|
||||||
|
'text' => 'foo',
|
||||||
|
'is_meeting' => false,
|
||||||
|
'user_id' => 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'Bar',
|
||||||
|
'text' => 'bar',
|
||||||
|
'is_meeting' => false,
|
||||||
|
'user_id' => 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'baz',
|
||||||
|
'text' => 'baz',
|
||||||
|
'is_meeting' => true,
|
||||||
|
'user_id' => 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'Lorem',
|
||||||
|
'text' => 'lorem',
|
||||||
|
'is_meeting' => false,
|
||||||
|
'user_id' => 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'Ipsum',
|
||||||
|
'text' => 'ipsum',
|
||||||
|
'is_meeting' => true,
|
||||||
|
'user_id' => 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'Dolor',
|
||||||
|
'text' => 'test',
|
||||||
|
'is_meeting' => true,
|
||||||
|
'user_id' => 1,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var TestLogger */
|
||||||
|
protected $log;
|
||||||
|
|
||||||
|
/** @var Response|MockObject */
|
||||||
|
protected $response;
|
||||||
|
|
||||||
|
/** @var Request */
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::__construct
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::index
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::meetings
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::showOverview
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::renderView
|
||||||
|
*/
|
||||||
|
public function testIndex()
|
||||||
|
{
|
||||||
|
$this->request->attributes->set('page', 2);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
|
||||||
|
$n = 1;
|
||||||
|
$this->response->expects($this->exactly(3))
|
||||||
|
->method('withView')
|
||||||
|
->willReturnCallback(
|
||||||
|
function (string $page, array $data) use (&$n) {
|
||||||
|
$this->assertEquals('pages/news/overview.twig', $page);
|
||||||
|
/** @var Collection $news */
|
||||||
|
$news = $data['news'];
|
||||||
|
|
||||||
|
switch ($n) {
|
||||||
|
case 1:
|
||||||
|
// Show everything
|
||||||
|
$this->assertFalse($data['only_meetings']);
|
||||||
|
$this->assertTrue($news->isNotEmpty());
|
||||||
|
$this->assertEquals(3, $data['pages']);
|
||||||
|
$this->assertEquals(2, $data['page']);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// Show meetings
|
||||||
|
$this->assertTrue($data['only_meetings']);
|
||||||
|
$this->assertTrue($news->isNotEmpty());
|
||||||
|
$this->assertEquals(1, $data['pages']);
|
||||||
|
$this->assertEquals(1, $data['page']);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// No news found
|
||||||
|
$this->assertTrue($news->isEmpty());
|
||||||
|
$this->assertEquals(1, $data['pages']);
|
||||||
|
$this->assertEquals(1, $data['page']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$n++;
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$controller->index();
|
||||||
|
$controller->meetings();
|
||||||
|
|
||||||
|
News::query()->truncate();
|
||||||
|
$controller->index();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::show
|
||||||
|
*/
|
||||||
|
public function testShow()
|
||||||
|
{
|
||||||
|
$this->request->attributes->set('id', 1);
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('withView')
|
||||||
|
->with('pages/news/news.twig')
|
||||||
|
->willReturn($this->response);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
|
||||||
|
$controller->show($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::show
|
||||||
|
*/
|
||||||
|
public function testShowNotFound()
|
||||||
|
{
|
||||||
|
$this->request->attributes->set('id', 42);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
|
||||||
|
$this->expectException(ModelNotFoundException::class);
|
||||||
|
$controller->show($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::comment
|
||||||
|
*/
|
||||||
|
public function testCommentInvalid()
|
||||||
|
{
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
|
||||||
|
$this->expectException(ValidationException::class);
|
||||||
|
$controller->comment($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::comment
|
||||||
|
*/
|
||||||
|
public function testCommentNewsNotFound()
|
||||||
|
{
|
||||||
|
$this->request->attributes->set('id', 42);
|
||||||
|
$this->request = $this->request->withParsedBody(['comment' => 'Foo bar!']);
|
||||||
|
$this->addUser();
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
|
||||||
|
$this->expectException(ModelNotFoundException::class);
|
||||||
|
$controller->comment($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::comment
|
||||||
|
*/
|
||||||
|
public function testComment()
|
||||||
|
{
|
||||||
|
$this->request->attributes->set('id', 1);
|
||||||
|
$this->request = $this->request->withParsedBody(['comment' => 'Foo bar!']);
|
||||||
|
$this->addUser();
|
||||||
|
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('redirectTo')
|
||||||
|
->willReturn($this->response);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->make(NewsController::class);
|
||||||
|
$controller->setValidator(new Validator());
|
||||||
|
|
||||||
|
$controller->comment($this->request);
|
||||||
|
$this->log->hasInfoThatContains('Created news comment');
|
||||||
|
|
||||||
|
/** @var NewsComment $comment */
|
||||||
|
$comment = NewsComment::whereNewsId(1)->first();
|
||||||
|
$this->assertEquals('Foo bar!', $comment->text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup environment
|
||||||
|
*/
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->initDatabase();
|
||||||
|
|
||||||
|
$this->request = new Request();
|
||||||
|
$this->app->instance(Request::class, $this->request);
|
||||||
|
$this->app->instance(ServerRequestInterface::class, $this->request);
|
||||||
|
|
||||||
|
$this->response = $this->createMock(Response::class);
|
||||||
|
$this->app->instance(Response::class, $this->response);
|
||||||
|
|
||||||
|
$this->app->instance(Config::class, new Config(['display_news' => 2]));
|
||||||
|
|
||||||
|
$this->log = new TestLogger();
|
||||||
|
$this->app->instance(LoggerInterface::class, $this->log);
|
||||||
|
|
||||||
|
$this->app->instance('session', new Session(new MockArraySessionStorage()));
|
||||||
|
|
||||||
|
$this->auth = $this->createMock(Authenticator::class);
|
||||||
|
$this->app->instance(Authenticator::class, $this->auth);
|
||||||
|
|
||||||
|
foreach ($this->data as $news) {
|
||||||
|
(new News($news))->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user
|
||||||
|
*/
|
||||||
|
protected function addUser()
|
||||||
|
{
|
||||||
|
$user = new User([
|
||||||
|
'name' => 'foo',
|
||||||
|
'password' => '',
|
||||||
|
'email' => '',
|
||||||
|
'api_key' => '',
|
||||||
|
'last_login_at' => null,
|
||||||
|
]);
|
||||||
|
$user->forceFill(['id' => 42]);
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$this->auth->expects($this->any())
|
||||||
|
->method('user')
|
||||||
|
->willReturn($user);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue