News: Rewrite
This commit is contained in:
parent
72f4839130
commit
d323b75501
|
@ -84,7 +84,7 @@ return [
|
|||
'rewrite_urls' => true,
|
||||
|
||||
// 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',
|
||||
|
||||
// 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('/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
|
||||
$route->get('/api[/{resource:.+}]', 'ApiController@index');
|
||||
|
||||
|
@ -39,5 +45,12 @@ $route->addGroup(
|
|||
$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/user_messages.php',
|
||||
__DIR__ . '/../includes/pages/user_myshifts.php',
|
||||
__DIR__ . '/../includes/pages/user_news.php',
|
||||
__DIR__ . '/../includes/pages/user_questions.php',
|
||||
__DIR__ . '/../includes/pages/user_settings.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\Models\News;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Collection as SupportCollection;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
function make_atom_entries_from_news($news_entries)
|
||||
|
@ -71,11 +72,11 @@ function make_atom_entry_from_news(News $news)
|
|||
return '
|
||||
<entry>
|
||||
<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(
|
||||
'#^https?://#',
|
||||
'',
|
||||
page_link_to('news_comments', ['nid' => $news->id])
|
||||
page_link_to('news/' . $news->id)
|
||||
) . '</id>
|
||||
<updated>' . $news->updated_at->format('Y-m-d\TH:i:sP') . '</updated>
|
||||
<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 = [];
|
||||
$pages = [
|
||||
'news' => __('News'),
|
||||
'user_meetings' => __('Meetings'),
|
||||
'meetings' => __('Meetings'),
|
||||
'user_shifts' => __('Shifts'),
|
||||
'angeltypes' => __('Angeltypes'),
|
||||
'user_questions' => __('Ask the Heaven'),
|
||||
];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,3 +67,17 @@ msgstr "Die Minuten vor dem Talk müssen eine Zahl sein."
|
|||
|
||||
msgid "validation.minutes-after.int"
|
||||
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
|
||||
#: 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_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/Questions_view.php:43 includes/view/ShiftEntry_view.php:93
|
||||
#: includes/view/ShiftEntry_view.php:118 includes/view/ShiftEntry_view.php:141
|
||||
|
@ -1089,7 +1087,7 @@ msgid "arrived sum"
|
|||
msgstr "Summe angekommen"
|
||||
|
||||
#: 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
|
||||
msgid "Date"
|
||||
msgstr "Datum"
|
||||
|
@ -1300,48 +1298,15 @@ msgstr "Erledigt!"
|
|||
msgid "Log"
|
||||
msgstr "Log"
|
||||
|
||||
#: includes/pages/admin_news.php:16
|
||||
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
|
||||
#: includes/pages/user_messages.php:121
|
||||
msgid "Message"
|
||||
msgstr "Nachricht"
|
||||
|
||||
#: includes/pages/admin_news.php:47 includes/pages/user_news.php:240
|
||||
msgid "Meeting"
|
||||
msgstr "Treffen"
|
||||
|
||||
#: includes/pages/admin_news.php:56 includes/pages/admin_rooms.php:202
|
||||
#: includes/pages/admin_rooms.php:202
|
||||
#: includes/view/User_view.php:129
|
||||
msgid "Delete"
|
||||
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
|
||||
msgid "Answer questions"
|
||||
msgstr "Fragen beantworten"
|
||||
|
@ -1778,38 +1743,14 @@ msgstr "Gib bitte einen Schwänz-Kommentar ein!"
|
|||
msgid "Shift saved."
|
||||
msgstr "Schicht gespeichert."
|
||||
|
||||
#: includes/pages/user_news.php:10
|
||||
msgid "News comments"
|
||||
msgstr "News Kommentare"
|
||||
|
||||
#: includes/pages/user_news.php:18 includes/sys_menu.php:94
|
||||
#: includes/sys_menu.php:94
|
||||
msgid "News"
|
||||
msgstr "News"
|
||||
|
||||
#: includes/pages/user_news.php:26 includes/sys_menu.php:95
|
||||
#: includes/sys_menu.php:95
|
||||
msgid "Meetings"
|
||||
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/view/Questions_view.php:40
|
||||
msgid "Ask the Heaven"
|
||||
|
@ -2886,3 +2827,42 @@ msgstr "Titel"
|
|||
|
||||
msgid "schedule.import.shift.room"
|
||||
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"
|
||||
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"
|
||||
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') }}"/>
|
||||
<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} -%}
|
||||
{% if page() == 'user-meetings' -%}
|
||||
{% if page() == 'meetings' -%}
|
||||
{% set parameters = parameters|merge({'meetings': 1}) -%}
|
||||
{% endif %}
|
||||
<link href="{{ url('atom', parameters) }}" type="application/atom+xml" rel="alternate" title="Atom Feed">
|
||||
|
|
|
@ -9,3 +9,17 @@
|
|||
{% macro alert(message, type) %}
|
||||
<div class="alert alert-{{ type|default('info') }}">{{ message }}</div>
|
||||
{% 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>
|
||||
{%- 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) %}
|
||||
<div class="form-group">
|
||||
{% if label -%}
|
||||
|
@ -26,10 +42,30 @@
|
|||
</div>
|
||||
{%- 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) %}
|
||||
<input type="hidden" id="{{ name }}" name="{{ name }}" value="{{ value }}">
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro submit(label) %}
|
||||
<button type="submit" class="btn btn-primary">{{ label|default(__('form.submit')) }}</button>
|
||||
{% macro button(label, opt) %}
|
||||
<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 %}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
$title = ucfirst($page);
|
||||
switch ($page) {
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 'ical':
|
||||
require_once realpath(__DIR__ . '/../../includes/pages/user_ical.php');
|
||||
user_ical();
|
||||
break;
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 'atom':
|
||||
require_once realpath(__DIR__ . '/../../includes/pages/user_atom.php');
|
||||
user_atom();
|
||||
break;
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 'shifts_json_export':
|
||||
require_once realpath(__DIR__ . '/../../includes/controller/shifts_controller.php');
|
||||
shifts_json_export_controller();
|
||||
|
@ -134,19 +130,6 @@ class LegacyMiddleware implements MiddlewareInterface
|
|||
return [$title, $content];
|
||||
case 'rooms':
|
||||
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':
|
||||
$title = myshifts_title();
|
||||
$content = user_myshifts();
|
||||
|
@ -193,10 +176,6 @@ class LegacyMiddleware implements MiddlewareInterface
|
|||
$title = admin_free_title();
|
||||
$content = admin_free();
|
||||
return [$title, $content];
|
||||
case 'admin_news':
|
||||
require_once realpath(__DIR__ . '/../../includes/pages/admin_news.php');
|
||||
$content = admin_news();
|
||||
return [$title, $content];
|
||||
case 'admin_rooms':
|
||||
$title = admin_rooms_title();
|
||||
$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