Make news comments deletable
This commit is contained in:
parent
950a865c0c
commit
a8e012be72
|
@ -39,6 +39,7 @@ $route->get('/news', 'NewsController@index');
|
||||||
$route->get('/meetings', 'NewsController@meetings');
|
$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');
|
||||||
|
$route->post('/news/comment/{id:\d+}', 'NewsController@deleteComment');
|
||||||
|
|
||||||
// FAQ
|
// FAQ
|
||||||
$route->get('/faq', 'FaqController@index');
|
$route->get('/faq', 'FaqController@index');
|
||||||
|
|
|
@ -74,6 +74,9 @@ msgstr "Die Minuten nach dem Talk müssen eine Zahl sein."
|
||||||
msgid "news.comment.success"
|
msgid "news.comment.success"
|
||||||
msgstr "Kommentar gespeichert."
|
msgstr "Kommentar gespeichert."
|
||||||
|
|
||||||
|
msgid "news.comment-delete.success"
|
||||||
|
msgstr "Kommentar erfolgreich gelöscht."
|
||||||
|
|
||||||
msgid "news.edit.success"
|
msgid "news.edit.success"
|
||||||
msgstr "News erfolgreich aktualisiert."
|
msgstr "News erfolgreich aktualisiert."
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,9 @@ msgstr "The minutes after the talk have to be an integer."
|
||||||
msgid "news.comment.success"
|
msgid "news.comment.success"
|
||||||
msgstr "Comment saved."
|
msgstr "Comment saved."
|
||||||
|
|
||||||
|
msgid "news.comment-delete.success"
|
||||||
|
msgstr "Comment successfully deleted."
|
||||||
|
|
||||||
msgid "news.edit.success"
|
msgid "news.edit.success"
|
||||||
msgstr "News successfully updated."
|
msgstr "News successfully updated."
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,17 @@
|
||||||
{{ comment.created_at.format(__('Y-m-d H:i')) }}
|
{{ comment.created_at.format(__('Y-m-d H:i')) }}
|
||||||
|
|
||||||
{{ m.user(comment.user) }}
|
{{ m.user(comment.user) }}
|
||||||
|
|
||||||
|
{% if comment.user.id == user.id or has_permission_to('admin_news') or has_permission_to('comment.delete') %}
|
||||||
|
<div class="pull-right">
|
||||||
|
<form
|
||||||
|
action="{{ url('/news/comment/' ~ comment.id) }}" enctype="multipart/form-data"
|
||||||
|
method="post">
|
||||||
|
{{ csrf() }}
|
||||||
|
{{ f.submit(m.glyphicon('trash'), {'name': 'delete', 'btn_type': 'danger', 'btn_size': 'xs', 'title': __('form.delete')}) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace Engelsystem\Controllers;
|
||||||
|
|
||||||
use Engelsystem\Config\Config;
|
use Engelsystem\Config\Config;
|
||||||
use Engelsystem\Helpers\Authenticator;
|
use Engelsystem\Helpers\Authenticator;
|
||||||
|
use Engelsystem\Http\Exceptions\HttpForbidden;
|
||||||
use Engelsystem\Http\Redirector;
|
use Engelsystem\Http\Redirector;
|
||||||
use Engelsystem\Http\Request;
|
use Engelsystem\Http\Request;
|
||||||
use Engelsystem\Http\Response;
|
use Engelsystem\Http\Response;
|
||||||
|
@ -18,6 +19,9 @@ class NewsController extends BaseController
|
||||||
/** @var Authenticator */
|
/** @var Authenticator */
|
||||||
protected $auth;
|
protected $auth;
|
||||||
|
|
||||||
|
/** @var NewsComment */
|
||||||
|
protected $comment;
|
||||||
|
|
||||||
/** @var Config */
|
/** @var Config */
|
||||||
protected $config;
|
protected $config;
|
||||||
|
|
||||||
|
@ -39,13 +43,15 @@ class NewsController extends BaseController
|
||||||
/** @var array */
|
/** @var array */
|
||||||
protected $permissions = [
|
protected $permissions = [
|
||||||
'news',
|
'news',
|
||||||
'meetings' => 'user_meetings',
|
'meetings' => 'user_meetings',
|
||||||
'comment' => 'news_comments',
|
'comment' => 'news_comments',
|
||||||
|
'deleteComment' => 'news_comments',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Authenticator $auth
|
* @param Authenticator $auth
|
||||||
* @param Config $config
|
* @param Config $config
|
||||||
|
* @param NewsComment $comment
|
||||||
* @param LoggerInterface $log
|
* @param LoggerInterface $log
|
||||||
* @param News $news
|
* @param News $news
|
||||||
* @param Redirector $redirector
|
* @param Redirector $redirector
|
||||||
|
@ -54,6 +60,7 @@ class NewsController extends BaseController
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Authenticator $auth,
|
Authenticator $auth,
|
||||||
|
NewsComment $comment,
|
||||||
Config $config,
|
Config $config,
|
||||||
LoggerInterface $log,
|
LoggerInterface $log,
|
||||||
News $news,
|
News $news,
|
||||||
|
@ -62,6 +69,7 @@ class NewsController extends BaseController
|
||||||
Request $request
|
Request $request
|
||||||
) {
|
) {
|
||||||
$this->auth = $auth;
|
$this->auth = $auth;
|
||||||
|
$this->comment = $comment;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->log = $log;
|
$this->log = $log;
|
||||||
$this->news = $news;
|
$this->news = $news;
|
||||||
|
@ -132,6 +140,41 @@ class NewsController extends BaseController
|
||||||
return $this->redirect->back();
|
return $this->redirect->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function deleteComment(Request $request): Response
|
||||||
|
{
|
||||||
|
$id = $request->getAttribute('id');
|
||||||
|
$this->validate(
|
||||||
|
$request,
|
||||||
|
[
|
||||||
|
'delete' => 'checked',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$comment = $this->comment->findOrFail($id);
|
||||||
|
if (
|
||||||
|
$comment->user->id != $this->auth->user()->id
|
||||||
|
&& !$this->auth->can('admin_news')
|
||||||
|
&& !$this->auth->can('comment.delete')
|
||||||
|
) {
|
||||||
|
throw new HttpForbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
$comment->delete();
|
||||||
|
|
||||||
|
$this->log->info(
|
||||||
|
'Deleted comment "{comment}" of news "{news}"',
|
||||||
|
['comment' => $comment->text, 'news' => $comment->news->title]
|
||||||
|
);
|
||||||
|
$this->addNotification('news.comment-delete.success');
|
||||||
|
|
||||||
|
return $this->redirect->to('/news/' . $comment->news->id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $onlyMeetings
|
* @param bool $onlyMeetings
|
||||||
* @return Response
|
* @return Response
|
||||||
|
|
|
@ -72,5 +72,6 @@ abstract class ControllerTest extends TestCase
|
||||||
|
|
||||||
$this->config = new Config();
|
$this->config = new Config();
|
||||||
$this->app->instance('config', $this->config);
|
$this->app->instance('config', $this->config);
|
||||||
|
$this->app->instance(Config::class, $this->config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,30 +2,20 @@
|
||||||
|
|
||||||
namespace Engelsystem\Test\Unit\Controllers;
|
namespace Engelsystem\Test\Unit\Controllers;
|
||||||
|
|
||||||
use Engelsystem\Config\Config;
|
|
||||||
use Engelsystem\Controllers\NewsController;
|
use Engelsystem\Controllers\NewsController;
|
||||||
use Engelsystem\Helpers\Authenticator;
|
use Engelsystem\Helpers\Authenticator;
|
||||||
|
use Engelsystem\Http\Exceptions\HttpForbidden;
|
||||||
use Engelsystem\Http\Exceptions\ValidationException;
|
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\Http\Validation\Validator;
|
||||||
use Engelsystem\Models\News;
|
use Engelsystem\Models\News;
|
||||||
use Engelsystem\Models\NewsComment;
|
use Engelsystem\Models\NewsComment;
|
||||||
use Engelsystem\Models\User\User;
|
use Engelsystem\Models\User\User;
|
||||||
use Engelsystem\Test\Unit\HasDatabase;
|
use Engelsystem\Test\Unit\HasDatabase;
|
||||||
use Engelsystem\Test\Unit\TestCase;
|
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
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
|
class NewsControllerTest extends ControllerTest
|
||||||
{
|
{
|
||||||
use HasDatabase;
|
use HasDatabase;
|
||||||
|
|
||||||
|
@ -75,15 +65,6 @@ class NewsControllerTest extends TestCase
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var TestLogger */
|
|
||||||
protected $log;
|
|
||||||
|
|
||||||
/** @var Response|MockObject */
|
|
||||||
protected $response;
|
|
||||||
|
|
||||||
/** @var Request */
|
|
||||||
protected $request;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers \Engelsystem\Controllers\NewsController::__construct
|
* @covers \Engelsystem\Controllers\NewsController::__construct
|
||||||
* @covers \Engelsystem\Controllers\NewsController::index
|
* @covers \Engelsystem\Controllers\NewsController::index
|
||||||
|
@ -225,51 +206,108 @@ class NewsControllerTest extends TestCase
|
||||||
$this->log->hasInfoThatContains('Created news comment');
|
$this->log->hasInfoThatContains('Created news comment');
|
||||||
|
|
||||||
/** @var NewsComment $comment */
|
/** @var NewsComment $comment */
|
||||||
$comment = NewsComment::whereNewsId(1)->first();
|
$comment = NewsComment::whereNewsId(1)->get()[2];
|
||||||
$this->assertEquals('Foo bar!', $comment->text);
|
$this->assertEquals('Foo bar!', $comment->text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::deleteComment
|
||||||
|
*/
|
||||||
|
public function testDeleteCommentInvalidRequest()
|
||||||
|
{
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->get(NewsController::class);
|
||||||
|
$controller->setValidator($this->app->get(Validator::class));
|
||||||
|
|
||||||
|
$this->expectException(ValidationException::class);
|
||||||
|
$controller->deleteComment($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::deleteComment
|
||||||
|
*/
|
||||||
|
public function testDeleteCommentNotFound()
|
||||||
|
{
|
||||||
|
$this->request = $this->request->withAttribute('id', 42)->withParsedBody(['delete' => '1']);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->get(NewsController::class);
|
||||||
|
$controller->setValidator($this->app->get(Validator::class));
|
||||||
|
|
||||||
|
$this->expectException(ModelNotFoundException::class);
|
||||||
|
$controller->deleteComment($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::deleteComment
|
||||||
|
*/
|
||||||
|
public function testDeleteCommentNotAllowed()
|
||||||
|
{
|
||||||
|
$this->request = $this->request->withAttribute('id', 2)->withParsedBody(['delete' => '1']);
|
||||||
|
|
||||||
|
$this->addUser(1);
|
||||||
|
$this->addUser(2);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->get(NewsController::class);
|
||||||
|
$controller->setValidator($this->app->get(Validator::class));
|
||||||
|
|
||||||
|
$this->expectException(HttpForbidden::class);
|
||||||
|
$controller->deleteComment($this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\NewsController::deleteComment
|
||||||
|
*/
|
||||||
|
public function testDeleteComment()
|
||||||
|
{
|
||||||
|
$this->request = $this->request->withAttribute('id', 1)->withParsedBody(['delete' => '1']);
|
||||||
|
$this->setExpects($this->response, 'redirectTo', ['http://localhost/news/1'], $this->response);
|
||||||
|
|
||||||
|
$this->addUser(1);
|
||||||
|
|
||||||
|
/** @var NewsController $controller */
|
||||||
|
$controller = $this->app->get(NewsController::class);
|
||||||
|
$controller->setValidator($this->app->get(Validator::class));
|
||||||
|
|
||||||
|
$controller->deleteComment($this->request);
|
||||||
|
|
||||||
|
$this->assertCount(1, NewsComment::all());
|
||||||
|
$this->assertTrue($this->log->hasInfoThatContains('Deleted comment'));
|
||||||
|
$this->assertHasNotification('news.comment-delete.success');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup environment
|
* Setup environment
|
||||||
*/
|
*/
|
||||||
public function setUp(): void
|
public function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->initDatabase();
|
|
||||||
|
|
||||||
$this->request = new Request();
|
$this->config->set(['display_news' => 2]);
|
||||||
$this->app->instance('request', $this->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->auth = $this->createMock(Authenticator::class);
|
||||||
$this->app->instance(Authenticator::class, $this->auth);
|
$this->app->instance(Authenticator::class, $this->auth);
|
||||||
|
|
||||||
$this->app->bind(UrlGeneratorInterface::class, UrlGenerator::class);
|
|
||||||
|
|
||||||
$this->app->instance('config', new Config());
|
|
||||||
|
|
||||||
foreach ($this->data as $news) {
|
foreach ($this->data as $news) {
|
||||||
(new News($news))->save();
|
(new News($news))->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ([1, 2] as $i) {
|
||||||
|
NewsComment::create([
|
||||||
|
'news_id' => 1,
|
||||||
|
'text' => 'test comment ' . $i,
|
||||||
|
'user_id' => $i,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new user
|
* Creates a new user
|
||||||
*/
|
*/
|
||||||
protected function addUser()
|
protected function addUser(int $id = 42)
|
||||||
{
|
{
|
||||||
$user = User::factory()->create(['id' => 42]);
|
$user = User::factory()->create(['id' => $id]);
|
||||||
|
|
||||||
$this->auth->expects($this->any())
|
$this->auth->expects($this->any())
|
||||||
->method('user')
|
->method('user')
|
||||||
|
|
Loading…
Reference in New Issue