Skip to content

Commit fc530f3

Browse files
authored
Merge pull request #10 from soatok/admin-notices
Add front page news (called "notices" internally)
2 parents 7a5ec45 + 20e6a21 commit fc530f3

File tree

14 files changed

+471
-2
lines changed

14 files changed

+471
-2
lines changed

bin/upgrade/v0.2.0-to-v0.3.0.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
$files = [
99
APP_ROOT . '/sql/09-analytics.sql',
10+
APP_ROOT . '/sql/10-admin-notices.sql',
1011
APP_ROOT . '/sql/updates/01-collection-description.sql'
1112
];
1213
foreach ($files as $file) {

public/static/admin-notice.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
let requestPending = false;
2+
3+
function preview()
4+
{
5+
requestPending = true;
6+
$.post('/manage/ajax/preview', {
7+
"markdown": $("#notice-body").val()
8+
}, function (res) {
9+
requestPending = false;
10+
if (res['status'] !== 'SUCCESS') {
11+
console.log(res);
12+
return;
13+
}
14+
$("#contents-preview").html(res['preview']);
15+
});
16+
}
17+
18+
function previewKeyUp()
19+
{
20+
if (requestPending) {
21+
return;
22+
}
23+
requestPending = true;
24+
$.post('/manage/ajax/preview', {
25+
"markdown": $("#notice-body").val()
26+
}, function (res) {
27+
requestPending = false;
28+
if (res['status'] !== 'SUCCESS') {
29+
console.log(res);
30+
return;
31+
}
32+
$("#contents-preview").html(res['preview']);
33+
});
34+
}
35+
36+
$(document).ready(function() {
37+
let el = $("#notice-body");
38+
el.on('change', preview);
39+
el.on('keyup', previewKeyUp);
40+
preview();
41+
});

sql/10-admin-notices.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CREATE TABLE faqoff_frontpage_notices (
2+
noticeid BIGSERIAL PRIMARY KEY, -- OwO *notices*
3+
headline TEXT,
4+
body TEXT,
5+
account_id BIGINT REFERENCES faqoff_accounts (accountid),
6+
created TIMESTAMP DEFAULT NOW()
7+
);
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
declare(strict_types=1);
3+
namespace Soatok\FaqOff\Endpoints\Admin;
4+
5+
use Interop\Container\Exception\ContainerException;
6+
use Psr\Http\Message\RequestInterface;
7+
use Psr\Http\Message\ResponseInterface;
8+
use Slim\Container;
9+
use Soatok\AnthroKit\Endpoint;
10+
use Soatok\FaqOff\Filter\AdminCreateNoticeFilter;
11+
use Soatok\FaqOff\MessageOnceTrait;
12+
use Twig\Error\{
13+
LoaderError,
14+
RuntimeError,
15+
SyntaxError
16+
};
17+
18+
/**
19+
* Class Notices
20+
* @package Soatok\FaqOff\Endpoints\Admin
21+
*/
22+
class Notices extends Endpoint
23+
{
24+
use MessageOnceTrait;
25+
26+
/** @var \Soatok\FaqOff\Splices\Notices $notices */
27+
private $notices;
28+
29+
public function __construct(Container $container)
30+
{
31+
parent::__construct($container);
32+
$this->notices = $this->splice('Notices');
33+
}
34+
35+
/**
36+
* @param RequestInterface $request
37+
* @return ResponseInterface
38+
* @throws ContainerException
39+
* @throws LoaderError
40+
* @throws RuntimeError
41+
* @throws SyntaxError
42+
*/
43+
public function createNotice(RequestInterface $request): ResponseInterface
44+
{
45+
$filter = new AdminCreateNoticeFilter();
46+
$post = $this->post($request, self::TYPE_FORM, $filter);
47+
if ($post) {
48+
$id = $this->notices->create(
49+
$post['title'],
50+
$post['contents'],
51+
(int) $_SESSION['account_id']
52+
);
53+
if ($id) {
54+
$this->messageOnce('Notice posted to the public.', 'success');
55+
return $this->redirect('/admin/notices/' . $id);
56+
}
57+
}
58+
return $this->view('admin/notice-create.twig', [
59+
'notices' => $this->notices->getAll()
60+
]);
61+
}
62+
63+
/**
64+
* @param int $id
65+
* @param RequestInterface $request
66+
* @return ResponseInterface
67+
* @throws ContainerException
68+
* @throws LoaderError
69+
* @throws RuntimeError
70+
* @throws SyntaxError
71+
*/
72+
public function editNotice(int $id, RequestInterface $request): ResponseInterface
73+
{
74+
$filter = new AdminCreateNoticeFilter();
75+
$post = $this->post($request, self::TYPE_FORM, $filter);
76+
if ($post) {
77+
if ($this->notices->update(
78+
$id,
79+
$post['title'],
80+
$post['contents'],
81+
(int) $_SESSION['account_id']
82+
)) {
83+
$this->messageOnce('Notice updated successfully.', 'success');
84+
return $this->redirect('/admin/notices/' . $id);
85+
}
86+
}
87+
return $this->view('admin/notice-edit.twig', [
88+
'notice' => $this->notices->getById($id)
89+
]);
90+
}
91+
92+
/**
93+
* @param RequestInterface $request
94+
* @param ResponseInterface|null $response
95+
* @param array $routerParams
96+
* @return ResponseInterface
97+
* @throws ContainerException
98+
* @throws LoaderError
99+
* @throws RuntimeError
100+
* @throws SyntaxError
101+
*/
102+
public function __invoke(
103+
RequestInterface $request,
104+
?ResponseInterface $response = null,
105+
array $routerParams = []
106+
): ResponseInterface {
107+
$id = $routerParams['id'] ?? null;
108+
if ($id) {
109+
return $this->editNotice((int) $id, $request);
110+
}
111+
return $this->createNotice($request);
112+
}
113+
}

src/FaqOff/Endpoints/HomePage.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Soatok\AnthroKit\Endpoint;
1010
use Soatok\FaqOff\MessageOnceTrait;
1111
use Soatok\FaqOff\Splices\Authors;
12+
use Soatok\FaqOff\Splices\Notices;
1213
use Twig\Error\LoaderError;
1314
use Twig\Error\RuntimeError;
1415
use Twig\Error\SyntaxError;
@@ -30,12 +31,16 @@ class HomePage extends Endpoint
3031
/** @var \Soatok\FaqOff\Splices\Entry $entries */
3132
private $entries;
3233

34+
/** @var Notices $notices */
35+
private $notices;
36+
3337
public function __construct(Container $container)
3438
{
3539
parent::__construct($container);
3640
$this->authors = $this->splice('Authors');
3741
$this->collections = $this->splice('EntryCollection');
3842
$this->entries = $this->splice('Entry');
43+
$this->notices = $this->splice('Notices');
3944
}
4045

4146
/**
@@ -47,11 +52,15 @@ public function __construct(Container $container)
4752
* @throws RuntimeError
4853
* @throws SyntaxError
4954
*/
50-
protected function index(RequestInterface $request): ResponseInterface
55+
protected function index(): ResponseInterface
5156
{
57+
$config = $this->container['settings'];
5258
return $this->view('index.twig', [
5359
'popular_collections' => $this->collections->getMostPopular(),
5460
'popular_entries' => $this->entries->getMostPopular(),
61+
'notices' => $this->notices->getRecent(
62+
(int) ($config['front-news-limit'])
63+
)
5564
]);
5665
}
5766

@@ -73,7 +82,7 @@ public function __invoke(
7382
switch ($request->getUri()->getPath()) {
7483
case '/':
7584
case '':
76-
return $this->index($request);
85+
return $this->index();
7786
}
7887
return $this->redirect('/');
7988
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
declare(strict_types=1);
3+
namespace Soatok\FaqOff\Filter;
4+
5+
use ParagonIE\Ionizer\Filter\StringFilter;
6+
use ParagonIE\Ionizer\InputFilterContainer;
7+
8+
/**
9+
* Class AdminCreateNoticeFilter
10+
* @package Soatok\FaqOff\Filter
11+
*/
12+
class AdminCreateNoticeFilter extends InputFilterContainer
13+
{
14+
public function __construct()
15+
{
16+
$this->addFilter('title', new StringFilter())
17+
->addFilter('contents', new StringFilter());
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
declare(strict_types=1);
3+
namespace Soatok\FaqOff\Filter;
4+
5+
use ParagonIE\Ionizer\Filter\StringFilter;
6+
use ParagonIE\Ionizer\InputFilterContainer;
7+
8+
/**
9+
* Class AdminEditNoticeFilter
10+
* @package Soatok\FaqOff\Filter
11+
*/
12+
class AdminEditNoticeFilter extends InputFilterContainer
13+
{
14+
public function __construct()
15+
{
16+
$this->addFilter('title', new StringFilter())
17+
->addFilter('contents', new StringFilter());
18+
}
19+
}

0 commit comments

Comments
 (0)