Added FAQ

main
Igor Scheller 4 years ago committed by msquare
parent 5cdf3889f9
commit 857ed23548

@ -35,12 +35,15 @@ return [
// Footer links // Footer links
'footer_items' => [ 'footer_items' => [
// URL to the angel faq and job description // URL to the angel faq and job description
'FAQ' => env('FAQ_URL', 'https://events.ccc.de/congress/2013/wiki/Static:Volunteers'), 'FAQ' => env('FAQ_URL', '/faq'),
// Contact email address, linked on every page // Contact email address, linked on every page
'Contact' => env('CONTACT_EMAIL', 'mailto:ticket@c3heaven.de'), 'Contact' => env('CONTACT_EMAIL', 'mailto:ticket@c3heaven.de'),
], ],
// Text displayed on the FAQ page, rendered as markdown
'faq_text' => env('FAQ_TEXT', null),
// Link to documentation/help // Link to documentation/help
'documentation_url' => 'https://engelsystem.de/doc/', 'documentation_url' => 'https://engelsystem.de/doc/',

@ -40,6 +40,9 @@ $route->get('/meetings', 'NewsController@meetings');
$route->get('/news/{id:\d+}', 'NewsController@show'); $route->get('/news/{id:\d+}', 'NewsController@show');
$route->post('/news/{id:\d+}', 'NewsController@comment'); $route->post('/news/{id:\d+}', 'NewsController@comment');
// FAQ
$route->get('/faq', 'FaqController@index');
// API // API
$route->get('/api[/{resource:.+}]', 'ApiController@index'); $route->get('/api[/{resource:.+}]', 'ApiController@index');
@ -50,6 +53,15 @@ $route->get('/design', 'DesignController@index');
$route->addGroup( $route->addGroup(
'/admin', '/admin',
function (RouteCollector $route) { function (RouteCollector $route) {
// FAQ
$route->addGroup(
'/faq',
function (RouteCollector $route) {
$route->get('[/{id:\d+}]', 'Admin\\FaqController@edit');
$route->post('[/{id:\d+}]', 'Admin\\FaqController@save');
}
);
// Log // Log
$route->get('/logs', 'Admin\\LogsController@index'); $route->get('/logs', 'Admin\\LogsController@index');
$route->post('/logs', 'Admin\\LogsController@index'); $route->post('/logs', 'Admin\\LogsController@index');

@ -0,0 +1,69 @@
<?php
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateFaqTableAndPermissions extends Migration
{
/**
* Run the migration
*/
public function up()
{
$this->schema->create('faq', function (Blueprint $table) {
$table->increments('id');
$table->string('question');
$table->text('text');
$table->timestamps();
});
if ($this->schema->hasTable('Privileges')) {
$db = $this->schema->getConnection();
$db->table('Privileges')->insert([
['name' => 'faq.view', 'desc' => 'View FAQ entries'],
['name' => 'faq.edit', 'desc' => 'Edit FAQ entries'],
]);
$guestGroup = -10;
$angelGroup = -20;
$shiftCoordinatorGroup = -40;
$viewId = $db->table('Privileges')->where('name', 'faq.view')->first()->id;
$editId = $db->table('Privileges')->where('name', 'faq.edit')->first()->id;
$db->table('GroupPrivileges')->insert([
['group_id' => $guestGroup, 'privilege_id' => $viewId],
['group_id' => $angelGroup, 'privilege_id' => $viewId],
['group_id' => $shiftCoordinatorGroup, 'privilege_id' => $editId],
]);
$db->table('Privileges')
->whereIn('name', ['admin_faq'])
->delete();
}
}
/**
* Reverse the migration
*/
public function down()
{
$this->schema->drop('faq');
if ($this->schema->hasTable('Privileges')) {
$db = $this->schema->getConnection();
$db->table('Privileges')
->whereIn('name', ['faq.view', 'faq.edit'])
->delete();
$db->table('Privileges')->insert([
['name' => 'admin_faq', 'desc' => 'Edit FAQs'],
]);
$bureaucratGroup = -60;
$adminFaqId = $db->table('Privileges')->where('name', 'admin_faq')->first()->id;
$db->table('GroupPrivileges')->insert([
['group_id' => $bureaucratGroup, 'privilege_id' => $adminFaqId],
]);
}
}
}

@ -108,3 +108,9 @@ msgstr "OAuth-Provider nicht gefunden"
msgid "settings.profile" msgid "settings.profile"
msgstr "Profil" msgstr "Profil"
msgid "faq.delete.success"
msgstr "FAQ Eintrag erfolgreich gelöscht."
msgid "faq.edit.success"
msgstr "FAQ Eintrag erfolgreich aktualisiert."

@ -2776,6 +2776,15 @@ msgstr "Bearbeiten"
msgid "form.save" msgid "form.save"
msgstr "Speichern" msgstr "Speichern"
msgid "form.preview"
msgstr "Vorschau"
msgid "form.delete"
msgstr "Löschen"
msgid "form.updated"
msgstr "Aktualisiert"
msgid "schedule.import" msgid "schedule.import"
msgstr "Programm importieren" msgstr "Programm importieren"
@ -2879,9 +2888,6 @@ msgstr "Treffen"
msgid "news.edit.message" msgid "news.edit.message"
msgstr "Nachricht" msgstr "Nachricht"
msgid "news.preview"
msgstr "Vorschau"
msgid "form.search" msgid "form.search"
msgstr "Suchen" msgstr "Suchen"
@ -2936,3 +2942,18 @@ msgstr "Verbinden"
msgid "form.disconnect" msgid "form.disconnect"
msgstr "Trennen" msgstr "Trennen"
msgid "faq.faq"
msgstr "FAQ"
msgid "faq.edit"
msgstr "FAQ Eintrag bearbeiten"
msgid "faq.add"
msgstr "FAQ Eintrag erstellen"
msgid "faq.question"
msgstr "Frage"
msgid "faq.message"
msgstr "Antwort"

@ -104,3 +104,9 @@ msgstr "Unable to find OAuth provider"
msgid "settings.profile" msgid "settings.profile"
msgstr "Profile" msgstr "Profile"
msgid "faq.delete.success"
msgstr "FAQ entry successfully deleted."
msgid "faq.edit.success"
msgstr "FAQ entry successfully updated."

@ -60,6 +60,15 @@ msgstr "Save"
msgid "form.edit" msgid "form.edit"
msgstr "Bearbeiten" msgstr "Bearbeiten"
msgid "form.preview"
msgstr "Preview"
msgid "form.delete"
msgstr "Delete"
msgid "form.updated"
msgstr "Updated"
msgid "schedule.import" msgid "schedule.import"
msgstr "Import schedule" msgstr "Import schedule"
@ -165,9 +174,6 @@ msgstr "Meeting"
msgid "news.edit.message" msgid "news.edit.message"
msgstr "Message" msgstr "Message"
msgid "news.preview"
msgstr "Preview"
msgid "form.search" msgid "form.search"
msgstr "Search" msgstr "Search"
@ -221,3 +227,18 @@ msgstr "Connect"
msgid "form.disconnect" msgid "form.disconnect"
msgstr "Disconnect" msgstr "Disconnect"
msgid "faq.faq"
msgstr "FAQ"
msgid "faq.edit"
msgstr "Edit FAQ entry"
msgid "faq.add"
msgstr "Add FAQ entry"
msgid "faq.question"
msgstr "Question"
msgid "faq.message"
msgstr "Answer"

@ -26,7 +26,7 @@
{% endblock %} {% endblock %}
{% for name,url in config('footer_items') %} {% for name,url in config('footer_items') %}
<a href="{{ url }}"> <a href="{% if url starts with '/' %}{{ url(url) }}{% else %}{{ url }}{% endif %}">
{% if '@' in url %}<span class="glyphicon glyphicon-envelope"></span>{% endif %} {% if '@' in url %}<span class="glyphicon glyphicon-envelope"></span>{% endif %}
{{ __(name) }} {{ __(name) }}
</a> · </a> ·

@ -69,6 +69,7 @@
<button class="btn btn-{{ opt.btn_type|default('primary') }} btn-{{ opt.btn_size|default('m') }}" <button class="btn btn-{{ opt.btn_type|default('primary') }} btn-{{ opt.btn_size|default('m') }}"
{%- if opt.type is defined %} type="{{ opt.type }}"{% endif %} {%- if opt.type is defined %} type="{{ opt.type }}"{% endif %}
{%- if opt.name is defined %} name="{{ opt.name }}"{% endif %} {%- if opt.name is defined %} name="{{ opt.name }}"{% endif %}
{%- if opt.title is defined %} title="{{ opt.title }}"{% endif %}
{%- if opt.value is defined or opt.name is defined %} value="{{ opt.value|default('1') }}"{% endif -%} {%- if opt.value is defined or opt.name is defined %} value="{{ opt.value|default('1') }}"{% endif -%}
> >
{{ label }} {{ label }}

@ -0,0 +1,69 @@
{% extends 'layouts/app.twig' %}
{% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %}
{% block title %}{{ faq and faq.id ? __('faq.edit') : __('faq.add') }}{% endblock %}
{% block content %}
<div class="container">
<h1>{{ block('title') }}</h1>
{% include 'layouts/parts/messages.twig' %}
{% if faq and faq.id %}
<div class="row">
<div class="col-md-6">
<p>
{{ m.glyphicon('time') }} {{ faq.updated_at.format(__('Y-m-d H:i')) }}
{% if faq.updated_at != faq.created_at %}
&emsp;{{ __('form.updated') }}
<br>
{{ m.glyphicon('time') }} {{ faq.created_at.format(__('Y-m-d H:i')) }}
{% endif %}
</p>
</div>
</div>
{% endif %}
<form action="" enctype="multipart/form-data" method="post">
{{ csrf() }}
<div class="row">
<div class="col-md-12">
{{ f.input('question', __('faq.question'), null, {'required': true, 'value': faq ? faq.question : ''}) }}
</div>
<div class="col-md-12">
{{ f.textarea('text', __('faq.message'), {'required': true, 'rows': 10, 'value': faq ? faq.text : ''}) }}
{{ f.submit() }}
{{ f.submit(m.glyphicon('eye-close'), {'name': 'preview', 'btn_type': 'info', 'title': __('form.preview')}) }}
{% if faq and faq.id %}
{{ f.submit(m.glyphicon('trash'), {'name': 'delete', 'btn_type': 'danger', 'title': __('form.delete')}) }}
{% endif %}
</div>
</div>
{% if faq %}
<div class="row">
<div class="col-md-12">
<h2>{{ __('form.preview') }}</h2>
<div class="panel panel-default">
<div class="panel-heading">
{{ faq.question }}
</div>
<div class="panel-body">
{{ faq.text|markdown }}
</div>
</div>
</div>
</div>
{% endif %}
</form>
</div>
{% endblock %}

@ -0,0 +1,56 @@
{% extends 'layouts/app.twig' %}
{% import 'macros/base.twig' as m %}
{% block title %}
{{ __('faq.faq') }}
{% endblock %}
{% block content %}
<div class="container">
<h1>
{{ block('title') }}
{%- if has_permission_to('faq.edit') -%}
{{ m.button(m.glyphicon('plus'), url('admin/faq')) }}
{%- endif %}
</h1>
{% include 'layouts/parts/messages.twig' %}
<div class="row">
{% block text %}
{% if text|default(null) %}
<div class="col-md-12">
{{ text|markdown }}
</div>
{% endif %}
{% endblock %}
{% block row %}
{% for item in items %}
<div class="col-md-12" id="faq-{{ item.id }}">
<div class="panel panel-default">
<div class="panel-heading">
{{ item.question }}
</div>
<div class="panel-body">
{{ item.text|markdown }}
</div>
<div class="panel-footer">
{{ m.glyphicon('time') }} {{ item.updated_at.format(__('Y-m-d H:i')) }}
{% if has_permission_to('faq.edit') %}
<span class="pull-right">
{{ m.button(m.glyphicon('edit'), url('admin/faq/' ~ item.id), null, 'xs') }}
</span>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% endblock %}
</div>
</div>
{% endblock %}

@ -2,7 +2,7 @@
{% import 'macros/base.twig' as m %} {% import 'macros/base.twig' as m %}
{% import 'macros/form.twig' as f %} {% import 'macros/form.twig' as f %}
{% block title %}{{ news ? __('news.edit.edit') : __('news.edit.add') }}{% endblock %} {% block title %}{{ news and news.id ? __('news.edit.edit') : __('news.edit.add') }}{% endblock %}
{% block content %} {% block content %}
<div class="container"> <div class="container">
@ -10,7 +10,7 @@
{% include 'layouts/parts/messages.twig' %} {% include 'layouts/parts/messages.twig' %}
{% if news %} {% if news and news.id %}
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<p> <p>
@ -51,10 +51,10 @@
{{ f.submit() }} {{ f.submit() }}
{{ f.submit(m.glyphicon('eye-close'), {'name': 'preview', 'btn_type': 'info'}) }} {{ f.submit(m.glyphicon('eye-close'), {'name': 'preview', 'btn_type': 'info', 'title': __('form.preview')}) }}
{% if news %} {% if news and news.id %}
{{ f.submit(m.glyphicon('trash'), {'name': 'delete', 'btn_type': 'danger'}) }} {{ f.submit(m.glyphicon('trash'), {'name': 'delete', 'btn_type': 'danger', 'title': __('form.delete')}) }}
{% endif %} {% endif %}
</div> </div>
</div> </div>
@ -62,7 +62,7 @@
{% if news %} {% if news %}
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h2>{{ __('news.preview') }}</h2> <h2>{{ __('form.preview') }}</h2>
<div class="panel {% if not news.is_meeting %}panel-default{% else %}panel-info{% endif %}"> <div class="panel {% if not news.is_meeting %}panel-default{% else %}panel-info{% endif %}">
<div class="panel-heading"> <div class="panel-heading">

@ -0,0 +1,126 @@
<?php
namespace Engelsystem\Controllers\Admin;
use Engelsystem\Controllers\BaseController;
use Engelsystem\Controllers\CleanupModel;
use Engelsystem\Controllers\HasUserNotifications;
use Engelsystem\Http\Redirector;
use Engelsystem\Http\Request;
use Engelsystem\Http\Response;
use Engelsystem\Models\Faq;
use Psr\Log\LoggerInterface;
class FaqController extends BaseController
{
use HasUserNotifications;
use CleanupModel;
/** @var LoggerInterface */
protected $log;
/** @var Faq */
protected $faq;
/** @var Redirector */
protected $redirect;
/** @var Response */
protected $response;
/** @var array */
protected $permissions = [
'faq.view',
'faq.edit',
];
/**
* @param LoggerInterface $log
* @param Faq $faq
* @param Redirector $redirector
* @param Response $response
*/
public function __construct(
LoggerInterface $log,
Faq $faq,
Redirector $redirector,
Response $response
) {
$this->log = $log;
$this->faq = $faq;
$this->redirect = $redirector;
$this->response = $response;
}
/**
* @param Request $request
*
* @return Response
*/
public function edit(Request $request): Response
{
$id = $request->getAttribute('id');
$faq = $this->faq->find($id);
return $this->showEdit($faq);
}
/**
* @param Request $request
*
* @return Response
*/
public function save(Request $request): Response
{
$id = $request->getAttribute('id');
/** @var Faq $faq */
$faq = $this->faq->findOrNew($id);
$data = $this->validate($request, [
'question' => 'required',
'text' => 'required',
'delete' => 'optional|checked',
'preview' => 'optional|checked',
]);
if (!is_null($data['delete'])) {
$faq->delete();
$this->log->info('Deleted faq "{question}"', ['question' => $faq->question]);
$this->addNotification('faq.delete.success');
return $this->redirect->to('/faq');
}
$faq->question = $data['question'];
$faq->text = $data['text'];
if (!is_null($data['preview'])) {
return $this->showEdit($faq);
}
$faq->save();
$this->log->info('Updated faq "{question}": {text}', ['question' => $faq->question, 'text' => $faq->text]);
$this->addNotification('faq.edit.success');
return $this->redirect->to('/faq#faq-' . $faq->id);
}
/**
* @param Faq|null $faq
*
* @return Response
*/
protected function showEdit(?Faq $faq): Response
{
$this->cleanupModelNullValues($faq);
return $this->response->withView(
'pages/faq/edit.twig',
['faq' => $faq] + $this->getNotifications()
);
}
}

@ -0,0 +1,56 @@
<?php
namespace Engelsystem\Controllers;
use Engelsystem\Config\Config;
use Engelsystem\Http\Response;
use Engelsystem\Models\Faq;
class FaqController extends BaseController
{
use HasUserNotifications;
/** @var Config */
protected $config;
/** @var Faq */
protected $faq;
/** @var Response */
protected $response;
/** @var string[] */
protected $permissions = [
'faq.view',
];
/**
* @param Config $config
* @param Faq $faq
* @param Response $response
*/
public function __construct(
Config $config,
Faq $faq,
Response $response
) {
$this->config = $config;
$this->faq = $faq;
$this->response = $response;
}
/**
* @return Response
*/
public function index(): Response
{
$text = $this->config->get('faq_text');
$faq = $this->faq->orderBy('question')->get();
return $this->response->withView(
'pages/faq/overview.twig',
['text' => $text, 'items' => $faq] + $this->getNotifications()
);
}
}

@ -172,6 +172,7 @@ class Controller extends BaseController
['labels' => ['state' => 'answered'], 'value' => $this->stats->questions(true)], ['labels' => ['state' => 'answered'], 'value' => $this->stats->questions(true)],
['labels' => ['state' => 'pending'], 'value' => $this->stats->questions(false)], ['labels' => ['state' => 'pending'], 'value' => $this->stats->questions(false)],
], ],
'faq' => ['type' => 'gauge', $this->stats->faq()],
'messages' => ['type' => 'gauge', $this->stats->messages()], 'messages' => ['type' => 'gauge', $this->stats->messages()],
'password_resets' => ['type' => 'gauge', $this->stats->passwordResets()], 'password_resets' => ['type' => 'gauge', $this->stats->passwordResets()],
'registration_enabled' => ['type' => 'gauge', $this->config->get('registration_enabled')], 'registration_enabled' => ['type' => 'gauge', $this->config->get('registration_enabled')],

@ -7,6 +7,7 @@ namespace Engelsystem\Controllers\Metrics;
use Carbon\Carbon; use Carbon\Carbon;
use Engelsystem\Database\Database; use Engelsystem\Database\Database;
use Engelsystem\Models\EventConfig; use Engelsystem\Models\EventConfig;
use Engelsystem\Models\Faq;
use Engelsystem\Models\LogEntry; use Engelsystem\Models\LogEntry;
use Engelsystem\Models\Message; use Engelsystem\Models\Message;
use Engelsystem\Models\News; use Engelsystem\Models\News;
@ -413,6 +414,14 @@ class Stats
return $query->count(); return $query->count();
} }
/**
* @return int
*/
public function faq(): int
{
return Faq::query()->count();
}
/** /**
* @return int * @return int
*/ */

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
/**
* @property int $id
* @property string $question
* @property string $text
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
*
* @method static Builder|Faq whereId($value)
* @method static Builder|Faq whereQuestion($value)
* @method static Builder|Faq whereText($value)
*/
class Faq extends BaseModel
{
/** @var bool Enable timestamps */
public $timestamps = true;
/** @var string The models table */
public $table = 'faq';
/** @var string[] */
protected $fillable = [
'question',
'text',
];
}

@ -0,0 +1,210 @@
<?php
namespace Engelsystem\Test\Unit\Controllers\Admin;
use Engelsystem\Config\Config;
use Engelsystem\Controllers\Admin\FaqController;
use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Request;
use Engelsystem\Http\Response;
use Engelsystem\Http\UrlGenerator;
use Engelsystem\Http\UrlGeneratorInterface;
use Engelsystem\Http\Validation\Validator;
use Engelsystem\Models\Faq;
use Engelsystem\Test\Unit\HasDatabase;
use Engelsystem\Test\Unit\TestCase;
use Illuminate\Support\Collection;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Psr\Log\Test\TestLogger;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
class FaqControllerTest extends TestCase
{
use HasDatabase;
/** @var array */
protected $data = [
'question' => 'Foo?',
'text' => 'Bar!',
];
/** @var TestLogger */
protected $log;
/** @var Response|MockObject */
protected $response;
/** @var Request */
protected $request;
/**
* @covers \Engelsystem\Controllers\Admin\FaqController::__construct
* @covers \Engelsystem\Controllers\Admin\FaqController::edit
* @covers \Engelsystem\Controllers\Admin\FaqController::showEdit
*/
public function testEdit()
{
$this->request->attributes->set('id', 1);
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function ($view, $data) {
$this->assertEquals('pages/faq/edit.twig', $view);
/** @var Collection $warnings */
$warnings = $data['messages'];
$this->assertNotEmpty($data['faq']);
$this->assertTrue($warnings->isEmpty());
return $this->response;
});
/** @var FaqController $controller */
$controller = $this->app->make(FaqController::class);
$controller->edit($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\FaqController::save
*/
public function testSaveCreateInvalid()
{
/** @var FaqController $controller */
$this->expectException(ValidationException::class);
$controller = $this->app->make(FaqController::class);
$controller->setValidator(new Validator());
$controller->save($this->request);
}
/**
* @covers \Engelsystem\Controllers\Admin\FaqController::save
*/
public function testSaveCreateEdit()
{
$this->request->attributes->set('id', 2);
$body = $this->data;
$this->request = $this->request->withParsedBody($body);
$this->response->expects($this->once())
->method('redirectTo')
->with('http://localhost/faq#faq-2')
->willReturn($this->response);
/** @var FaqController $controller */
$controller = $this->app->make(FaqController::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('faq.edit.success', $messages[0]);
$faq = (new Faq())->find(2);
$this->assertEquals('Foo?', $faq->question);
$this->assertEquals('Bar!', $faq->text);
}
/**
* @covers \Engelsystem\Controllers\Admin\FaqController::save
*/
public function testSavePreview()
{
$this->request->attributes->set('id', 1);
$this->request = $this->request->withParsedBody([
'question' => 'New question',
'text' => 'New text',
'preview' => '1',
]);
$this->response->expects($this->once())
->method('withView')
->willReturnCallback(function ($view, $data) {
$this->assertEquals('pages/faq/edit.twig', $view);
/** @var Faq $faq */
$faq = $data['faq'];
// Contains new text
$this->assertEquals('New question', $faq->question);
$this->assertEquals('New text', $faq->text);
return $this->response;
});
/** @var FaqController $controller */
$controller = $this->app->make(FaqController::class);
$controller->setValidator(new Validator());
$controller->save($this->request);
// Assert no changes
$faq = Faq::find(1);
$this->assertEquals('Lorem', $faq->question);
$this->assertEquals('Ipsum!', $faq->text);
}
/**
* @covers \Engelsystem\Controllers\Admin\FaqController::save
*/
public function testSaveDelete()
{
$this->request->attributes->set('id', 1);
$this->request = $this->request->withParsedBody([
'question' => '.',
'text' => '.',
'delete' => '1',
]);
$this->response->expects($this->once())
->method('redirectTo')
->with('http://localhost/faq')
->willReturn($this->response);
/** @var FaqController $controller */
$controller = $this->app->make(FaqController::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('faq.delete.success', $messages[0]);
}
/**
* Setup environment
*/
public function setUp(): void
{
parent::setUp();
$this->initDatabase();
$this->request = Request::create('http://localhost');
$this->app->instance('request', $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->app->bind(UrlGeneratorInterface::class, UrlGenerator::class);
$this->app->instance('config', new Config());
(new Faq([
'question' => 'Lorem',
'text' => 'Ipsum!',
]))->save();
}
}

@ -0,0 +1,46 @@
<?php
namespace Engelsystem\Test\Unit\Controllers;
use Engelsystem\Config\Config;
use Engelsystem\Controllers\FaqController;
use Engelsystem\Http\Response;
use Engelsystem\Models\Faq;
use Engelsystem\Test\Unit\HasDatabase;
use Engelsystem\Test\Unit\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
class FaqControllerTest extends TestCase
{
use HasDatabase;
/**
* @covers \Engelsystem\Controllers\FaqController::__construct
* @covers \Engelsystem\Controllers\FaqController::index
*/
public function testIndex()
{
$this->initDatabase();
(new Faq(['question' => 'Xyz', 'text' => 'Abc']))->save();
(new Faq(['question' => 'Something\'s wrong?', 'text' => 'Nah!']))->save();
$this->app->instance('session', new Session(new MockArraySessionStorage()));
$config = new Config(['faq_text' => 'Some Text']);
/** @var Response|MockObject $response */
$response = $this->createMock(Response::class);
$response->expects($this->once())
->method('withView')
->willReturnCallback(function (string $view, array $data) use ($response) {
$this->assertEquals('pages/faq/overview.twig', $view);
$this->assertEquals('Some Text', $data['text']);
$this->assertEquals('Nah!', $data['items'][0]->text);
return $response;
});
$controller = new FaqController($config, new Faq(), $response);
$controller->index();
}
}

@ -4,6 +4,7 @@ namespace Engelsystem\Test\Unit\Controllers\Metrics;
use Carbon\Carbon; use Carbon\Carbon;
use Engelsystem\Controllers\Metrics\Stats; use Engelsystem\Controllers\Metrics\Stats;
use Engelsystem\Models\Faq;
use Engelsystem\Models\LogEntry; use Engelsystem\Models\LogEntry;
use Engelsystem\Models\Message; use Engelsystem\Models\Message;
use Engelsystem\Models\News; use Engelsystem\Models\News;
@ -250,6 +251,18 @@ class StatsTest extends TestCase
$this->assertEquals(3, $stats->email('humans')); $this->assertEquals(3, $stats->email('humans'));
} }
/**
* @covers \Engelsystem\Controllers\Metrics\Stats::faq
*/
public function testFaq()
{
(new Faq(['question' => 'Foo?', 'text' => 'Bar!']))->save();
(new Faq(['question' => 'Lorem??', 'text' => 'Ipsum!!!']))->save();
$stats = new Stats($this->database);
$this->assertEquals(2, $stats->faq());
}
/** /**
* @covers \Engelsystem\Controllers\Metrics\Stats::messages * @covers \Engelsystem\Controllers\Metrics\Stats::messages
*/ */

Loading…
Cancel
Save