News: Rewrite
This commit is contained in:
parent
72f4839130
commit
d323b75501
|
@ -84,7 +84,7 @@ return [
|
||||||
'rewrite_urls' => true,
|
'rewrite_urls' => true,
|
||||||
|
|
||||||
// Redirect to this site after logging in or when pressing the top-left button
|
// Redirect to this site after logging in or when pressing the top-left button
|
||||||
// Must be one of news, user_meetings, user_shifts, angeltypes, user_questions
|
// Must be one of news, meetings, user_shifts, angeltypes, user_questions
|
||||||
'home_site' => 'news',
|
'home_site' => 'news',
|
||||||
|
|
||||||
// Number of News shown on one site
|
// Number of News shown on one site
|
||||||
|
|
|
@ -23,6 +23,12 @@ $route->post('/password/reset/{token:.+}', 'PasswordResetController@postResetPas
|
||||||
$route->get('/metrics', 'Metrics\\Controller@metrics');
|
$route->get('/metrics', 'Metrics\\Controller@metrics');
|
||||||
$route->get('/stats', 'Metrics\\Controller@stats');
|
$route->get('/stats', 'Metrics\\Controller@stats');
|
||||||
|
|
||||||
|
// News
|
||||||
|
$route->get('/news', 'NewsController@index');
|
||||||
|
$route->get('/meetings', 'NewsController@meetings');
|
||||||
|
$route->get('/news/{id:\d+}', 'NewsController@show');
|
||||||
|
$route->post('/news/{id:\d+}', 'NewsController@comment');
|
||||||
|
|
||||||
// API
|
// API
|
||||||
$route->get('/api[/{resource:.+}]', 'ApiController@index');
|
$route->get('/api[/{resource:.+}]', 'ApiController@index');
|
||||||
|
|
||||||
|
@ -39,5 +45,12 @@ $route->addGroup(
|
||||||
$route->post('-import', 'Admin\\Schedule\\ImportSchedule@importSchedule');
|
$route->post('-import', 'Admin\\Schedule\\ImportSchedule@importSchedule');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
$route->addGroup(
|
||||||
|
'/news',
|
||||||
|
function (RouteCollector $route) {
|
||||||
|
$route->get('[/{id:\d+}]', 'Admin\\NewsController@edit');
|
||||||
|
$route->post('[/{id:\d+}]', 'Admin\\NewsController@save');
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -76,7 +76,6 @@ $includeFiles = [
|
||||||
__DIR__ . '/../includes/pages/guest_login.php',
|
__DIR__ . '/../includes/pages/guest_login.php',
|
||||||
__DIR__ . '/../includes/pages/user_messages.php',
|
__DIR__ . '/../includes/pages/user_messages.php',
|
||||||
__DIR__ . '/../includes/pages/user_myshifts.php',
|
__DIR__ . '/../includes/pages/user_myshifts.php',
|
||||||
__DIR__ . '/../includes/pages/user_news.php',
|
|
||||||
__DIR__ . '/../includes/pages/user_questions.php',
|
__DIR__ . '/../includes/pages/user_questions.php',
|
||||||
__DIR__ . '/../includes/pages/user_settings.php',
|
__DIR__ . '/../includes/pages/user_settings.php',
|
||||||
__DIR__ . '/../includes/pages/user_shifts.php',
|
__DIR__ . '/../includes/pages/user_shifts.php',
|
||||||
|
|
|
@ -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>';
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@
|
||||||
use Engelsystem\Http\Exceptions\HttpForbidden;
|
use Engelsystem\Http\Exceptions\HttpForbidden;
|
||||||
use Engelsystem\Models\News;
|
use Engelsystem\Models\News;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Support\Collection as SupportCollection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publically available page to feed the news to feed readers
|
* Publically available page to feed the news to feed readers
|
||||||
|
@ -36,7 +37,7 @@ function user_atom()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param News[]|Collection $news_entries
|
* @param News[]|Collection|SupportCollection $news_entries
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function make_atom_entries_from_news($news_entries)
|
function make_atom_entries_from_news($news_entries)
|
||||||
|
@ -71,11 +72,11 @@ function make_atom_entry_from_news(News $news)
|
||||||
return '
|
return '
|
||||||
<entry>
|
<entry>
|
||||||
<title>' . htmlspecialchars($news->title) . '</title>
|
<title>' . htmlspecialchars($news->title) . '</title>
|
||||||
<link href="' . page_link_to('news_comments', ['nid' => $news->id]) . '"/>
|
<link href="' . page_link_to('news/' . $news->id) . '"/>
|
||||||
<id>' . preg_replace(
|
<id>' . preg_replace(
|
||||||
'#^https?://#',
|
'#^https?://#',
|
||||||
'',
|
'',
|
||||||
page_link_to('news_comments', ['nid' => $news->id])
|
page_link_to('news/' . $news->id)
|
||||||
) . '</id>
|
) . '</id>
|
||||||
<updated>' . $news->updated_at->format('Y-m-d\TH:i:sP') . '</updated>
|
<updated>' . $news->updated_at->format('Y-m-d\TH:i:sP') . '</updated>
|
||||||
<summary type="html">' . htmlspecialchars($news->text) . '</summary>
|
<summary type="html">' . htmlspecialchars($news->text) . '</summary>
|
||||||
|
|
|
@ -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>';
|
|
||||||
}
|
|
|
@ -92,14 +92,14 @@ function make_navigation()
|
||||||
$menu = [];
|
$menu = [];
|
||||||
$pages = [
|
$pages = [
|
||||||
'news' => __('News'),
|
'news' => __('News'),
|
||||||
'user_meetings' => __('Meetings'),
|
'meetings' => __('Meetings'),
|
||||||
'user_shifts' => __('Shifts'),
|
'user_shifts' => __('Shifts'),
|
||||||
'angeltypes' => __('Angeltypes'),
|
'angeltypes' => __('Angeltypes'),
|
||||||
'user_questions' => __('Ask the Heaven'),
|
'user_questions' => __('Ask the Heaven'),
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($pages as $menu_page => $title) {
|
foreach ($pages as $menu_page => $title) {
|
||||||
if (auth()->can($menu_page)) {
|
if (auth()->can($menu_page) || ($menu_page == 'meetings' && auth()->can('user_meetings'))) {
|
||||||
$menu[] = toolbar_item_link(page_link_to($menu_page), '', $title, $menu_page == $page);
|
$menu[] = toolbar_item_link(page_link_to($menu_page), '', $title, $menu_page == $page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,3 +67,17 @@ msgstr "Die Minuten vor dem Talk müssen eine Zahl sein."
|
||||||
|
|
||||||
msgid "validation.minutes-after.int"
|
msgid "validation.minutes-after.int"
|
||||||
msgstr "Die Minuten nach dem Talk müssen eine Zahl sein."
|
msgstr "Die Minuten nach dem Talk müssen eine Zahl sein."
|
||||||
|
|
||||||
|
msgid "news.comment.success"
|
||||||
|
msgstr "Kommentar gespeichert."
|
||||||
|
|
||||||
|
msgid "news.edit.success"
|
||||||
|
msgstr "News erfolgreich aktualisiert."
|
||||||
|
|
||||||
|
msgid "news.delete.success"
|
||||||
|
msgstr "News erfolgreich gelöscht."
|
||||||
|
|
||||||
|
msgid "news.edit.contains-html"
|
||||||
|
msgstr ""
|
||||||
|
"Diese Nachricht beinhaltet HTML. Wenn du sie speicherst gehen diese "
|
||||||
|
"Formatierungen verloren!"
|
||||||
|
|
|
@ -220,10 +220,8 @@ msgstr "Passwort wiederholen"
|
||||||
|
|
||||||
#: resources/views/pages/password/reset-form.twig:14
|
#: resources/views/pages/password/reset-form.twig:14
|
||||||
#: includes/controller/shifts_controller.php:194
|
#: includes/controller/shifts_controller.php:194
|
||||||
#: includes/pages/admin_groups.php:101 includes/pages/admin_news.php:48
|
|
||||||
#: includes/pages/admin_questions.php:55 includes/pages/admin_rooms.php:177
|
#: includes/pages/admin_questions.php:55 includes/pages/admin_rooms.php:177
|
||||||
#: includes/pages/admin_shifts.php:339 includes/pages/user_messages.php:78
|
#: includes/pages/admin_shifts.php:339 includes/pages/user_messages.php:78
|
||||||
#: includes/pages/user_news.php:164 includes/pages/user_news.php:241
|
|
||||||
#: includes/view/AngelTypes_view.php:120 includes/view/EventConfig_view.php:110
|
#: includes/view/AngelTypes_view.php:120 includes/view/EventConfig_view.php:110
|
||||||
#: includes/view/Questions_view.php:43 includes/view/ShiftEntry_view.php:93
|
#: includes/view/Questions_view.php:43 includes/view/ShiftEntry_view.php:93
|
||||||
#: includes/view/ShiftEntry_view.php:118 includes/view/ShiftEntry_view.php:141
|
#: includes/view/ShiftEntry_view.php:118 includes/view/ShiftEntry_view.php:141
|
||||||
|
@ -1089,7 +1087,7 @@ msgid "arrived sum"
|
||||||
msgstr "Summe angekommen"
|
msgstr "Summe angekommen"
|
||||||
|
|
||||||
#: includes/pages/admin_arrive.php:200 includes/pages/admin_arrive.php:215
|
#: includes/pages/admin_arrive.php:200 includes/pages/admin_arrive.php:215
|
||||||
#: includes/pages/admin_arrive.php:230 includes/pages/admin_news.php:43
|
#: includes/pages/admin_arrive.php:230
|
||||||
#: includes/pages/user_messages.php:118
|
#: includes/pages/user_messages.php:118
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Datum"
|
msgstr "Datum"
|
||||||
|
@ -1300,48 +1298,15 @@ msgstr "Erledigt!"
|
||||||
msgid "Log"
|
msgid "Log"
|
||||||
msgstr "Log"
|
msgstr "Log"
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:16
|
#: includes/pages/user_messages.php:121
|
||||||
msgid "Edit news entry"
|
|
||||||
msgstr "News-Eintrag bearbeiten"
|
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:36
|
|
||||||
msgid ""
|
|
||||||
"This message contains HTML. After saving the post some formatting will be "
|
|
||||||
"lost!"
|
|
||||||
msgstr ""
|
|
||||||
"Diese Nachricht beinhaltet HTML. Wenn du sie speicherst gehen diese "
|
|
||||||
"Formatierungen verloren!"
|
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:44
|
|
||||||
msgid "Author"
|
|
||||||
msgstr "Autor"
|
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:45 includes/pages/user_news.php:238
|
|
||||||
msgid "Subject"
|
|
||||||
msgstr "Betreff"
|
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:46 includes/pages/user_messages.php:121
|
|
||||||
#: includes/pages/user_news.php:163 includes/pages/user_news.php:239
|
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Nachricht"
|
msgstr "Nachricht"
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:47 includes/pages/user_news.php:240
|
#: includes/pages/admin_rooms.php:202
|
||||||
msgid "Meeting"
|
|
||||||
msgstr "Treffen"
|
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:56 includes/pages/admin_rooms.php:202
|
|
||||||
#: includes/view/User_view.php:129
|
#: includes/view/User_view.php:129
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "löschen"
|
msgstr "löschen"
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:72
|
|
||||||
msgid "News entry updated."
|
|
||||||
msgstr "News-Eintrag gespeichert."
|
|
||||||
|
|
||||||
#: includes/pages/admin_news.php:79
|
|
||||||
msgid "News entry deleted."
|
|
||||||
msgstr "News-Eintrag gelöscht."
|
|
||||||
|
|
||||||
#: includes/pages/admin_questions.php:11 includes/sys_menu.php:115
|
#: includes/pages/admin_questions.php:11 includes/sys_menu.php:115
|
||||||
msgid "Answer questions"
|
msgid "Answer questions"
|
||||||
msgstr "Fragen beantworten"
|
msgstr "Fragen beantworten"
|
||||||
|
@ -1778,38 +1743,14 @@ msgstr "Gib bitte einen Schwänz-Kommentar ein!"
|
||||||
msgid "Shift saved."
|
msgid "Shift saved."
|
||||||
msgstr "Schicht gespeichert."
|
msgstr "Schicht gespeichert."
|
||||||
|
|
||||||
#: includes/pages/user_news.php:10
|
#: includes/sys_menu.php:94
|
||||||
msgid "News comments"
|
|
||||||
msgstr "News Kommentare"
|
|
||||||
|
|
||||||
#: includes/pages/user_news.php:18 includes/sys_menu.php:94
|
|
||||||
msgid "News"
|
msgid "News"
|
||||||
msgstr "News"
|
msgstr "News"
|
||||||
|
|
||||||
#: includes/pages/user_news.php:26 includes/sys_menu.php:95
|
#: includes/sys_menu.php:95
|
||||||
msgid "Meetings"
|
msgid "Meetings"
|
||||||
msgstr "Treffen"
|
msgstr "Treffen"
|
||||||
|
|
||||||
#: includes/pages/user_news.php:113
|
|
||||||
msgid "Comments"
|
|
||||||
msgstr "Kommentare"
|
|
||||||
|
|
||||||
#: includes/pages/user_news.php:146 includes/pages/user_news.php:199
|
|
||||||
msgid "Entry saved."
|
|
||||||
msgstr "Eintrag gespeichert."
|
|
||||||
|
|
||||||
#: includes/pages/user_news.php:161
|
|
||||||
msgid "New Comment:"
|
|
||||||
msgstr "Neuer Kommentar:"
|
|
||||||
|
|
||||||
#: includes/pages/user_news.php:167
|
|
||||||
msgid "Invalid request."
|
|
||||||
msgstr "Ungültige Abfrage."
|
|
||||||
|
|
||||||
#: includes/pages/user_news.php:235
|
|
||||||
msgid "Create news:"
|
|
||||||
msgstr "News anlegen:"
|
|
||||||
|
|
||||||
#: includes/pages/user_questions.php:11 includes/sys_menu.php:98
|
#: includes/pages/user_questions.php:11 includes/sys_menu.php:98
|
||||||
#: includes/view/Questions_view.php:40
|
#: includes/view/Questions_view.php:40
|
||||||
msgid "Ask the Heaven"
|
msgid "Ask the Heaven"
|
||||||
|
@ -2886,3 +2827,42 @@ msgstr "Titel"
|
||||||
|
|
||||||
msgid "schedule.import.shift.room"
|
msgid "schedule.import.shift.room"
|
||||||
msgstr "Raum"
|
msgstr "Raum"
|
||||||
|
|
||||||
|
msgid "news.title"
|
||||||
|
msgstr "News"
|
||||||
|
|
||||||
|
msgid "news.title.meetings"
|
||||||
|
msgstr "Treffen"
|
||||||
|
|
||||||
|
msgid "news.add"
|
||||||
|
msgstr "+"
|
||||||
|
|
||||||
|
msgid "news.is_meeting"
|
||||||
|
msgstr "[Treffen]"
|
||||||
|
|
||||||
|
msgid "news.updated"
|
||||||
|
msgstr "Aktualisiert"
|
||||||
|
|
||||||
|
msgid "news.comments"
|
||||||
|
msgstr "Kommentare"
|
||||||
|
|
||||||
|
msgid "news.comments.new"
|
||||||
|
msgstr "Neuer Kommentar"
|
||||||
|
|
||||||
|
msgid "news.comments.message"
|
||||||
|
msgstr "Nachricht"
|
||||||
|
|
||||||
|
msgid "news.edit.edit"
|
||||||
|
msgstr "News bearbeiten"
|
||||||
|
|
||||||
|
msgid "news.edit.add"
|
||||||
|
msgstr "News erstellen"
|
||||||
|
|
||||||
|
msgid "news.edit.subject"
|
||||||
|
msgstr "Betreff"
|
||||||
|
|
||||||
|
msgid "news.edit.is_meeting"
|
||||||
|
msgstr "Treffen"
|
||||||
|
|
||||||
|
msgid "news.edit.message"
|
||||||
|
msgstr "Nachricht"
|
||||||
|
|
|
@ -65,3 +65,15 @@ msgstr "The minutes before the talk have to be an integer."
|
||||||
|
|
||||||
msgid "validation.minutes-after.int"
|
msgid "validation.minutes-after.int"
|
||||||
msgstr "The minutes after the talk have to be an integer."
|
msgstr "The minutes after the talk have to be an integer."
|
||||||
|
|
||||||
|
msgid "news.comment.success"
|
||||||
|
msgstr "Comment saved."
|
||||||
|
|
||||||
|
msgid "news.edit.success"
|
||||||
|
msgstr "News successfully updated."
|
||||||
|
|
||||||
|
msgid "news.delete.success"
|
||||||
|
msgstr "News successfully deleted."
|
||||||
|
|
||||||
|
msgid "news.edit.contains-html"
|
||||||
|
msgstr "This message contains HTML. After saving the post some formatting will be lost!"
|
||||||
|
|
|
@ -105,3 +105,42 @@ msgstr "Title"
|
||||||
|
|
||||||
msgid "schedule.import.shift.room"
|
msgid "schedule.import.shift.room"
|
||||||
msgstr "Room"
|
msgstr "Room"
|
||||||
|
|
||||||
|
msgid "news.title"
|
||||||
|
msgstr "News"
|
||||||
|
|
||||||
|
msgid "news.title.meetings"
|
||||||
|
msgstr "Meetings"
|
||||||
|
|
||||||
|
msgid "news.add"
|
||||||
|
msgstr "+"
|
||||||
|
|
||||||
|
msgid "news.is_meeting"
|
||||||
|
msgstr "[Meeting]"
|
||||||
|
|
||||||
|
msgid "news.updated"
|
||||||
|
msgstr "Updated"
|
||||||
|
|
||||||
|
msgid "news.comments"
|
||||||
|
msgstr "Comments"
|
||||||
|
|
||||||
|
msgid "news.comments.new"
|
||||||
|
msgstr "New comment"
|
||||||
|
|
||||||
|
msgid "news.comments.message"
|
||||||
|
msgstr "Message"
|
||||||
|
|
||||||
|
msgid "news.edit.edit"
|
||||||
|
msgstr "Edit news"
|
||||||
|
|
||||||
|
msgid "news.edit.add"
|
||||||
|
msgstr "Add news"
|
||||||
|
|
||||||
|
msgid "news.edit.subject"
|
||||||
|
msgstr "Subject"
|
||||||
|
|
||||||
|
msgid "news.edit.is_meeting"
|
||||||
|
msgstr "Meeting"
|
||||||
|
|
||||||
|
msgid "news.edit.message"
|
||||||
|
msgstr "Message"
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/theme' ~ theme ~ '.css') }}"/>
|
<link rel="stylesheet" type="text/css" href="{{ asset('assets/theme' ~ theme ~ '.css') }}"/>
|
||||||
<script type="text/javascript" src="{{ asset('assets/vendor.js') }}"></script>
|
<script type="text/javascript" src="{{ asset('assets/vendor.js') }}"></script>
|
||||||
|
|
||||||
{% if page() in ['news', 'user-meetings', '/'] and is_user() -%}
|
{% if page() in ['news', 'meetings'] and is_user() -%}
|
||||||
{% set parameters = {'key': user.api_key} -%}
|
{% set parameters = {'key': user.api_key} -%}
|
||||||
{% if page() == 'user-meetings' -%}
|
{% if page() == 'meetings' -%}
|
||||||
{% set parameters = parameters|merge({'meetings': 1}) -%}
|
{% set parameters = parameters|merge({'meetings': 1}) -%}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<link href="{{ url('atom', parameters) }}" type="application/atom+xml" rel="alternate" title="Atom Feed">
|
<link href="{{ url('atom', parameters) }}" type="application/atom+xml" rel="alternate" title="Atom Feed">
|
||||||
|
|
|
@ -9,3 +9,17 @@
|
||||||
{% macro alert(message, type) %}
|
{% macro alert(message, type) %}
|
||||||
<div class="alert alert-{{ type|default('info') }}">{{ message }}</div>
|
<div class="alert alert-{{ type|default('info') }}">{{ message }}</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro user(user) %}
|
||||||
|
<a href="{{ url('users', {'action': 'view', 'user_id': user.id}) }}"
|
||||||
|
{%- if not user.state.arrived %} class="text-muted"{% endif -%}
|
||||||
|
>
|
||||||
|
{{ _self.angel() }} {{ user.name }}
|
||||||
|
</a>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro button(label, url, type, size) %}
|
||||||
|
<a href="{{ url }}" class="btn btn-{{ type|default('default') }}{% if size %} btn-{{ size }}{% endif %}">
|
||||||
|
{{ label }}
|
||||||
|
</a>
|
||||||
|
{% endmacro %}
|
||||||
|
|
|
@ -13,6 +13,22 @@
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro textarea(name, label, opt) %}
|
||||||
|
<div class="form-group">
|
||||||
|
{% if label -%}
|
||||||
|
<label for="{{ name }}">{{ label }}</label>
|
||||||
|
{%- endif %}
|
||||||
|
<textarea class="form-control" id="{{ name }}" name="{{ name }}"
|
||||||
|
{%- if opt.required|default(false) %}
|
||||||
|
required="required"
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if opt.rows|default(0) %}
|
||||||
|
rows="{{ opt.rows }}"
|
||||||
|
{%- endif -%}
|
||||||
|
>{{ opt.value|default('') }}</textarea>
|
||||||
|
</div>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro select(name, data, label, selected) %}
|
{% macro select(name, data, label, selected) %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
{% if label -%}
|
{% if label -%}
|
||||||
|
@ -26,10 +42,30 @@
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro checkbox(name, label, checked, value) %}
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="{{ name }}" name="{{ name }}" value="{{ value|default('1') }}"
|
||||||
|
{%- if checked|default(false) %} checked="checked"{% endif %}>
|
||||||
|
{{ label }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro hidden(name, value) %}
|
{% macro hidden(name, value) %}
|
||||||
<input type="hidden" id="{{ name }}" name="{{ name }}" value="{{ value }}">
|
<input type="hidden" id="{{ name }}" name="{{ name }}" value="{{ value }}">
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro submit(label) %}
|
{% macro button(label, opt) %}
|
||||||
<button type="submit" class="btn btn-primary">{{ label|default(__('form.submit')) }}</button>
|
<button class="btn btn-{{ opt.btn_type|default('primary') }}"
|
||||||
|
{%- if opt.type is defined %} type="{{ opt.type }}"{% endif %}
|
||||||
|
{%- if opt.name is defined %} name="{{ opt.name }}"{% endif %}
|
||||||
|
{%- if opt.value is defined or opt.name is defined %} value="{{ opt.value|default('1') }}"{% endif -%}
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</button>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro submit(label, opt) %}
|
||||||
|
{{ _self.button(label|default(__('form.submit')), opt|default({})|merge({'type': 'submit'})) }}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,19 +95,15 @@ class LegacyMiddleware implements MiddlewareInterface
|
||||||
*/
|
*/
|
||||||
protected function loadPage($page)
|
protected function loadPage($page)
|
||||||
{
|
{
|
||||||
$title = ucfirst($page);
|
|
||||||
switch ($page) {
|
switch ($page) {
|
||||||
/** @noinspection PhpMissingBreakStatementInspection */
|
|
||||||
case 'ical':
|
case 'ical':
|
||||||
require_once realpath(__DIR__ . '/../../includes/pages/user_ical.php');
|
require_once realpath(__DIR__ . '/../../includes/pages/user_ical.php');
|
||||||
user_ical();
|
user_ical();
|
||||||
break;
|
break;
|
||||||
/** @noinspection PhpMissingBreakStatementInspection */
|
|
||||||
case 'atom':
|
case 'atom':
|
||||||
require_once realpath(__DIR__ . '/../../includes/pages/user_atom.php');
|
require_once realpath(__DIR__ . '/../../includes/pages/user_atom.php');
|
||||||
user_atom();
|
user_atom();
|
||||||
break;
|
break;
|
||||||
/** @noinspection PhpMissingBreakStatementInspection */
|
|
||||||
case 'shifts_json_export':
|
case 'shifts_json_export':
|
||||||
require_once realpath(__DIR__ . '/../../includes/controller/shifts_controller.php');
|
require_once realpath(__DIR__ . '/../../includes/controller/shifts_controller.php');
|
||||||
shifts_json_export_controller();
|
shifts_json_export_controller();
|
||||||
|
@ -134,19 +130,6 @@ class LegacyMiddleware implements MiddlewareInterface
|
||||||
return [$title, $content];
|
return [$title, $content];
|
||||||
case 'rooms':
|
case 'rooms':
|
||||||
return rooms_controller();
|
return rooms_controller();
|
||||||
case 'news':
|
|
||||||
$title = news_title();
|
|
||||||
$content = user_news();
|
|
||||||
return [$title, $content];
|
|
||||||
case 'news_comments':
|
|
||||||
require_once realpath(__DIR__ . '/../../includes/pages/user_news.php');
|
|
||||||
$title = user_news_comments_title();
|
|
||||||
$content = user_news_comments();
|
|
||||||
return [$title, $content];
|
|
||||||
case 'user_meetings':
|
|
||||||
$title = meetings_title();
|
|
||||||
$content = user_meetings();
|
|
||||||
return [$title, $content];
|
|
||||||
case 'user_myshifts':
|
case 'user_myshifts':
|
||||||
$title = myshifts_title();
|
$title = myshifts_title();
|
||||||
$content = user_myshifts();
|
$content = user_myshifts();
|
||||||
|
@ -193,10 +176,6 @@ class LegacyMiddleware implements MiddlewareInterface
|
||||||
$title = admin_free_title();
|
$title = admin_free_title();
|
||||||
$content = admin_free();
|
$content = admin_free();
|
||||||
return [$title, $content];
|
return [$title, $content];
|
||||||
case 'admin_news':
|
|
||||||
require_once realpath(__DIR__ . '/../../includes/pages/admin_news.php');
|
|
||||||
$content = admin_news();
|
|
||||||
return [$title, $content];
|
|
||||||
case 'admin_rooms':
|
case 'admin_rooms':
|
||||||
$title = admin_rooms_title();
|
$title = admin_rooms_title();
|
||||||
$content = admin_rooms();
|
$content = admin_rooms();
|
||||||
|
|
|
@ -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