Skip to content

Commit

Permalink
Edit static pages commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrlcctrlv authored and czaks committed May 6, 2016
1 parent 7911c37 commit 95b1e10
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
@@ -1,3 +1,9 @@
[submodule "js/wPaint"]
path = js/wPaint
url = https://github.com/vichan-devel/wPaint.git
branch = master

[submodule "inc/lib/parsedown"]
path = inc/lib/parsedown
url = https://github.com/vichan-devel/parsedown
branch = master
6 changes: 6 additions & 0 deletions inc/config.php
Expand Up @@ -1498,6 +1498,9 @@
$config['mod']['ban_appeals'] = MOD;
// View the recent posts page
$config['mod']['recent'] = MOD;
// Create pages
$config['mod']['edit_pages'] = MOD;
$config['pages_max'] = 10;

// Config editor permissions
$config['mod']['config'] = array();
Expand Down Expand Up @@ -1702,3 +1705,6 @@

// Use CAPTCHA for reports?
$config['report_captcha'] = false;

// Allowed HTML tags in ?/edit_pages.
$config['allowed_html'] = 'a[href|title],p,br,li,ol,ul,strong,em,u,h2,b,i,tt,div,img[src|alt|title],hr';
43 changes: 43 additions & 0 deletions inc/functions.php
Expand Up @@ -20,6 +20,7 @@
require_once 'inc/api.php';
require_once 'inc/mod/auth.php';
require_once 'inc/polyfill.php';
//require_once 'inc/lib/parsedown/Parsedown.php'; // we don't need that right now, do we?
if (!extension_loaded('gettext')) {
require_once 'inc/lib/gettext/gettext.inc';
Expand Down Expand Up @@ -2739,3 +2740,45 @@ function link_for($post, $page50 = false, $foreignlink = false, $thread = false)

return sprintf($tpl, $id, $slug);
}

function prettify_textarea($s){
return str_replace("\t", '	', str_replace("\n", '
', htmlentities($s)));
}

class HTMLPurifier_URIFilter_NoExternalImages extends HTMLPurifier_URIFilter {
public $name = 'NoExternalImages';
public function filter(&$uri, $c, $context) {
global $config;
$ct = $context->get('CurrentToken');

if (!$ct || $ct->name !== 'img') return true;

if (!isset($uri->host) && !isset($uri->scheme)) return true;

if (!in_array($uri->scheme . '://' . $uri->host . '/', $config['allowed_offsite_urls'])) {
error('No off-site links in board announcement images.');
}

return true;
}
}

function purify_html($s) {
global $config;

$c = HTMLPurifier_Config::createDefault();
$c->set('HTML.Allowed', $config['allowed_html']);
$uri = $c->getDefinition('URI');
$uri->addFilter(new HTMLPurifier_URIFilter_NoExternalImages(), $c);
$purifier = new HTMLPurifier($c);
$clean_html = $purifier->purify($s);
return $clean_html;
}

function markdown($s) {
$pd = new Parsedown();
$pd->setMarkupEscaped(true);
$pd->setimagesEnabled(false);

return $pd->text($s);
}
162 changes: 162 additions & 0 deletions inc/mod/pages.php
Expand Up @@ -2628,6 +2628,167 @@ function mod_theme_rebuild($theme_name) {
));
}

// This needs to be done for `secure` CSRF prevention compatibility, otherwise the $board will be read in as the token if editing global pages.
function delete_page_base($page = '', $board = false) {
global $config, $mod;

if (empty($board))
$board = false;

if (!$board && $mod['boards'][0] !== '*')
error($config['error']['noaccess']);

if (!hasPermission($config['mod']['edit_pages'], $board))
error($config['error']['noaccess']);

if ($board !== FALSE && !openBoard($board))
error($config['error']['noboard']);

if ($board) {
$query = prepare('DELETE FROM ``pages`` WHERE `board` = :board AND `name` = :name');
$query->bindValue(':board', ($board ? $board : NULL));
} else {
$query = prepare('DELETE FROM ``pages`` WHERE `board` IS NULL AND `name` = :name');
}
$query->bindValue(':name', $page);
$query->execute() or error(db_error($query));

header('Location: ?/edit_pages' . ($board ? ('/' . $board) : ''), true, $config['redirect_http']);
}

function mod_delete_page($page = '') {
delete_page_base($page);
}

function mod_delete_page_board($page = '', $board = false) {
delete_page_base($page, $board);
}

function mod_edit_page($id) {
global $config, $mod, $board;

$query = prepare('SELECT * FROM ``pages`` WHERE `id` = :id');
$query->bindValue(':id', $id);
$query->execute() or error(db_error($query));
$page = $query->fetch();

if (!$page)
error(_('Could not find the page you are trying to edit.'));

if (!$page['board'] && $mod['boards'][0] !== '*')
error($config['error']['noaccess']);

if (!hasPermission($config['mod']['edit_pages'], $page['board']))
error($config['error']['noaccess']);

if ($page['board'] && !openBoard($page['board']))
error($config['error']['noboard']);

if (isset($_POST['method'], $_POST['content'])) {
$content = $_POST['content'];
$method = $_POST['method'];
$page['type'] = $method;

if (!in_array($method, array('markdown', 'html', 'infinity')))
error(_('Unrecognized page markup method.'));

switch ($method) {
case 'markdown':
$write = markdown($content);
break;
case 'html':
if (hasPermission($config['mod']['rawhtml'])) {
$write = $content;
} else {
$write = purify_html($content);
}
break;
case 'infinity':
$c = $content;
markup($content);
$write = $content;
$content = $c;
}

if (!isset($write) or !$write)
error(_('Failed to mark up your input for some reason...'));

$query = prepare('UPDATE ``pages`` SET `type` = :method, `content` = :content WHERE `id` = :id');
$query->bindValue(':method', $method);
$query->bindValue(':content', $content);
$query->bindValue(':id', $id);
$query->execute() or error(db_error($query));

$fn = ($board['uri'] ? ($board['uri'] . '/') : '') . $page['name'] . '.html';
$body = "<div class='ban'>$write</div>";
$html = Element('page.html', array('config' => $config, 'body' => $body, 'title' => utf8tohtml($page['title'])));
file_write($fn, $html);
}

if (!isset($content)) {
$query = prepare('SELECT `content` FROM ``pages`` WHERE `id` = :id');
$query->bindValue(':id', $id);
$query->execute() or error(db_error($query));
$content = $query->fetchColumn();
}

mod_page(sprintf(_('Editing static page: %s'), $page['name']), 'mod/edit_page.html', array('page' => $page, 'token' => make_secure_link_token("edit_page/$id"), 'content' => prettify_textarea($content), 'board' => $board));
}

function mod_pages($board = false) {
global $config, $mod, $pdo;

if (empty($board))
$board = false;

if (!$board && $mod['boards'][0] !== '*')
error($config['error']['noaccess']);

if (!hasPermission($config['mod']['edit_pages'], $board))
error($config['error']['noaccess']);

if ($board !== FALSE && !openBoard($board))
error($config['error']['noboard']);

if ($board) {
$query = prepare('SELECT * FROM ``pages`` WHERE `board` = :board');
$query->bindValue(':board', $board);
} else {
$query = query('SELECT * FROM ``pages`` WHERE `board` IS NULL');
}
$query->execute() or error(db_error($query));
$pages = $query->fetchAll(PDO::FETCH_ASSOC);

if (isset($_POST['page'])) {
if ($board and sizeof($pages) > $config['pages_max'])
error(sprintf(_('Sorry, this site only allows %d pages per board.'), $config['pages_max']));

if (!preg_match('/^[a-z0-9]{1,255}$/', $_POST['page']))
error(_('Page names must be < 255 chars and may only contain lowercase letters A-Z and digits 1-9.'));

foreach ($pages as $i => $p) {
if ($_POST['page'] === $p['name'])
error(_('Refusing to create a new page with the same name as an existing one.'));
}

$title = ($_POST['title'] ? $_POST['title'] : NULL);

$query = prepare('INSERT INTO ``pages``(board, title, name) VALUES(:board, :title, :name)');
$query->bindValue(':board', ($board ? $board : NULL));
$query->bindValue(':title', $title);
$query->bindValue(':name', $_POST['page']);
$query->execute() or error(db_error($query));

$pages[] = array('id' => $pdo->lastInsertId(), 'name' => $_POST['page'], 'board' => $board, 'title' => $title);
}

foreach ($pages as $i => &$p) {
$p['delete_token'] = make_secure_link_token('edit_pages/delete/' . $p['name'] . ($board ? ('/' . $board) : ''));
}

mod_page(_('Pages'), 'mod/pages.html', array('pages' => $pages, 'token' => make_secure_link_token('edit_pages' . ($board ? ('/' . $board) : '')), 'board' => $board));
}

function mod_debug_antispam() {
global $pdo, $config;

Expand Down Expand Up @@ -2744,3 +2905,4 @@ function mod_debug_apc() {

mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars));
}

20 changes: 19 additions & 1 deletion install.sql
Expand Up @@ -245,7 +245,7 @@ CREATE TABLE IF NOT EXISTS `search_queries` (
`ip` varchar(39) NOT NULL,
`time` int(11) NOT NULL,
`query` text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

-- --------------------------------------------------------

Expand Down Expand Up @@ -297,6 +297,24 @@ CREATE TABLE IF NOT EXISTS `ban_appeals` (
KEY `ban_id` (`ban_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ;

-- --------------------------------------------------------

--
-- Table structure for table `pages`
--

CREATE TABLE `pages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`board` varchar(255) DEFAULT NULL,
`name` varchar(255) NOT NULL,
`title` varchar(255) DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`content` text,
PRIMARY KEY (`id`),
UNIQUE KEY `u_pages` (`name`,`board`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;

>>>>>>> 12fa8ec... Edit static pages commit
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
18 changes: 13 additions & 5 deletions mod.php
Expand Up @@ -33,11 +33,19 @@

'/log' => 'log', // modlog
'/log/(\d+)' => 'log', // modlog
'/log:([^/]+)' => 'user_log', // modlog
'/log:([^/]+)/(\d+)' => 'user_log', // modlog
'/news' => 'secure_POST news', // view news
'/news/(\d+)' => 'secure_POST news', // view news
'/news/delete/(\d+)' => 'secure news_delete', // delete from news
'/log:([^/:]+)' => 'user_log', // modlog
'/log:([^/:]+)/(\d+)' => 'user_log', // modlog
'/log:b:([^/]+)' => 'board_log', // modlog
'/log:b:([^/]+)/(\d+)' => 'board_log', // modlog

'/edit_news' => 'secure_POST news', // view news
'/edit_news/(\d+)' => 'secure_POST news', // view news
'/edit_news/delete/(\d+)' => 'secure news_delete', // delete from news

'/edit_pages(?:/?(\%b)?)' => 'secure_POST pages',
'/edit_page/(\d+)' => 'secure_POST edit_page',
'/edit_pages/delete/([a-z0-9]+)' => 'secure delete_page',
'/edit_pages/delete/([a-z0-9]+)/(\%b)' => 'secure delete_page_board',

'/noticeboard' => 'secure_POST noticeboard', // view noticeboard
'/noticeboard/(\d+)' => 'secure_POST noticeboard', // view noticeboard
Expand Down
29 changes: 29 additions & 0 deletions templates/mod/edit_page.html
@@ -0,0 +1,29 @@
<div style="text-align:center">
<form method="POST">
<input name="token" value="{{ token }}" type="hidden">
<table>
<tr>
<th>{% trans %}Markup method{% endtrans %}
{% set allowed_html = config.allowed_html %}
{% trans %}<p class="unimportant">"markdown" is provided by <a href="http://parsedown.org/">parsedown</a>. Note: images disabled.</p>
<p class="unimportant">"html" allows the following tags:<br/>{{ allowed_html }}</p>
<p class="unimportant">"infinity" is the same as what is used in posts.</p>
<p class="unimportant">This page will not convert between formats,<br/>choose it once or do the conversion yourself!</p>{% endtrans %}
</th>
<td>
<select name="method">
{% for markup in ['markdown', 'html', 'infinity'] %}
<option value="{{ markup }}" {% if page.type == markup %}selected{% endif %}>{{ markup }}</option>
{% endfor %}
</select>
</td></tr>
<tr><th>{% trans %}Page content{% endtrans %}
<br/>
<span class="unimportant">{% trans %}Page will appear at:{% endtrans %}
{% if board %} <a href="/{{ board.uri }}/{{ page.name }}.html">{{ config.domain }}/{{ board.uri }}/{{ page.name }}.html</a>
{% else %} <a href="/{{ page.name }}.html">{{ config.site }}/{{ page.name }}.html</a>
{% endif %}</span></th><td><textarea name="content" style="height:500px;width:500px">{{content}}</textarea></td><tr>
</table>
<input type="submit" value="Save page">
</form>
</div>
34 changes: 34 additions & 0 deletions templates/mod/pages.html
@@ -0,0 +1,34 @@
<script type="text/javascript" src="js/jquery.min.js"></script>
<div style="text-align:center">
<p class="unimportant">
{% if board %}
{% set page_max = config.pages_max %}
{% trans %}This page allows you to create static pages for your board. The limit is {{ page_max }} pages per board. You will still have to link to your pages somewhere in your board, for example in a sticky or in the board's announcement. To make links in the board's announcement, use &lt;a&gt; HTML tags.{% endtrans %}
{% else %}
{% trans %}This page allows you to create static pages for your imageboard.{% endtrans %}
{% endif %}
<h2>{% trans %}Existing pages{% endtrans %}</h2>
{% if pages %}
<form>
<table style="margin:auto">
<tr><th>{% trans %}URL{% endtrans %}</th><th>{% trans %}Title{% endtrans %}</th><th>{% trans %}Edit{% endtrans %}</th><th>{% trans %}Delete{% endtrans %}</tr>
{% for page in pages %}
<tr><td>{{ page.name }}</td><td>{{ page.title }}</td><td><a href="?/edit_page/{{ page.id }}">{% trans %}Edit{% endtrans %}</a></td><td><a href="?/edit_pages/delete/{{ page.name }}{% if board %}/{{ board }}{% endif %}/{{ page.delete_token }}">{% trans %}Delete{% endtrans %}</a></td>
{% endfor %}
{% else %}
<em>No pages yet!</em>
{% endif %}
</table>
</form>
<hr/>
<h2>{% trans %}Create a new page{% endtrans %}</h2>
<form method="POST">
<input type="hidden" name="token" value="{{ token }}">
<table>
<tr><th>{% trans %}URL{% endtrans %}</th><th>{% trans %}Title{% endtrans %}</th></tr>
<tr><td><input type="text" name="page"></td><td><input type="text" name="title"></td>
</table>
<input type="submit" value="{% trans %}Create{% endtrans %}">
</form>

</div>
16 changes: 16 additions & 0 deletions tools/import_rules.php
@@ -0,0 +1,16 @@
<?php
// This script imports rules.txt files from the old system into the new ``pages`` table.

require dirname(__FILE__) . '/inc/cli.php';

$boards = listBoards(TRUE);

foreach ($boards as $i => $b) {
$rules = @file_get_contents($b.'/rules.txt');
if ($rules && !empty(trim($rules))) {
$query = prepare('INSERT INTO ``pages``(name, title, type, board, content) VALUES("rules", "Rules", "html", :board, :content)');
$query->bindValue(':board', $b);
$query->bindValue(':content', $rules);
$query->execute() or error(db_error($query));
}
}

0 comments on commit 95b1e10

Please sign in to comment.