Forum and ...

This commit is contained in:
Visman 2017-03-21 23:16:15 +07:00
parent 3101e4c1fe
commit 6290aad378
27 changed files with 504 additions and 150 deletions

View file

@ -31,7 +31,7 @@ class Primary
{
if ($this->c->config['o_maintenance'] && ! $this->c->MAINTENANCE_OFF) {
if (! in_array($this->c->UserCookie->id(), $this->c->admins)
|| ! in_array($this->c->user['id'], $this->c->admins)
|| ! in_array($this->c->user->id, $this->c->admins)
) {
return $this->c->Maintenance;
}

View file

@ -34,20 +34,20 @@ class Routing
// регистрация/вход/выход
if ($user->isGuest) {
// вход
$r->add('GET', '/login', 'Auth:login', 'Login');
$r->add('GET', '/login', 'Auth:login', 'Login');
$r->add('POST', '/login', 'Auth:loginPost');
// забыли пароль
$r->add('GET', '/login/forget', 'Auth:forget', 'Forget');
// забыли кодовую фразу
$r->add('GET', '/login/forget', 'Auth:forget', 'Forget');
$r->add('POST', '/login/forget', 'Auth:forgetPost');
// смена пароля
$r->add('GET', '/login/{email}/{key}/{hash}', 'Auth:changePass', 'ChangePassword');
// смена кодовой фразы
$r->add('GET', '/login/{email}/{key}/{hash}', 'Auth:changePass', 'ChangePassword');
$r->add('POST', '/login/{email}/{key}/{hash}', 'Auth:changePassPost');
// регистрация
if ($config['o_regs_allow'] == '1') {
$r->add('GET', '/registration', 'Rules:confirmation', 'Register');
$r->add('GET', '/registration', 'Rules:confirmation', 'Register');
$r->add('POST', '/registration/agree', 'Register:reg', 'RegisterForm');
$r->add('GET', '/registration/activate/{id:\d+}/{key}/{hash}', 'Register:activate', 'RegActivate');
$r->add('GET', '/registration/activate/{id:\d+}/{key}/{hash}', 'Register:activate', 'RegActivate');
}
} else {
// выход
@ -72,15 +72,15 @@ class Routing
// юзеры
if ($user->gViewUsers == '1') {
// список пользователей
$r->add('GET', '/userlist[/page/{page}]', 'Userlist:view', 'Userlist');
$r->add('GET', '/userlist[/page/{page:[1-9]\d*}]', 'Userlist:view', 'Userlist');
// юзеры
$r->add('GET', '/user/{id:\d+}[/{name}]', 'Profile:view', 'User'); //????
$r->add('GET', '/user/{id:[1-9]\d*}[/{name}]', 'Profile:view', 'User'); //????
}
// разделы
$r->add('GET', '/forum/{id:\d+}[/{name}][/page/{page:\d+}]', 'Forum:view', 'Forum');
$r->add('GET', '/forum/{id:[1-9]\d*}[/{name}][/page/{page:[1-9]\d*}]', 'Forum:view', 'Forum');
// темы
$r->add('GET', '/post/{id:\d+}#p{id}', 'Topic:viewpost', 'viewPost');
$r->add('GET', '/post/{id:[1-9]\d*}#p{id}', 'Topic:viewpost', 'viewPost');
}
// админ и модератор

View file

@ -67,7 +67,7 @@ class Container
if (is_array($service)) {
return $this->fromArray($service, $tree);
} elseif (is_object($service)) {
return $service->$tree;
return $service->$tree[0];
} else {
return null;
}

View file

@ -1,9 +1,8 @@
<?php
namespace ForkBB\Models;
namespace ForkBB\Core;
use ForkBB\Core\Secury;
use ForkBB\Models\User;
class Csrf
{
@ -22,10 +21,10 @@ class Csrf
* @param Secury $secury
* @param User $user
*/
public function __construct(Secury $secury, User $user)
public function __construct(Secury $secury, $key)
{
$this->secury = $secury;
$this->key = sha1($user->password . $user->ip . $user->id);
$this->key = sha1($key);
}
/**

View file

@ -41,7 +41,7 @@ class DB extends PDO
{
$type = strstr($dsn, ':', true);
if (! $type || ! file_exists(__DIR__ . '/DB/' . ucfirst($type) . '.php')) {
throw new PDOException("For '$type' the driver isn't found.");
throw new PDOException("Driver isn't found for '$type'");
}
$this->dbType = $type;

View file

@ -1,6 +1,6 @@
<?php
namespace ForkBB\Models;
namespace ForkBB\Core;
use ForkBB\Core\Container;
use RuntimeException;

View file

@ -99,7 +99,7 @@ class CacheGenerator
$tree = $desc = $asc = [];
if ($read) {
$stmt = $this->c->DB->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url, f.parent_forum_id, f.disp_position FROM ::categories AS c INNER JOIN ::forums AS f ON c.id=f.cat_id LEFT JOIN ::forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=?i:id) WHERE fp.read_forum IS NULL OR fp.read_forum=1 ORDER BY c.disp_position, c.id, f.disp_position', [':id' => $user->gId]);
$stmt = $this->c->DB->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url, f.parent_forum_id, f.disp_position, fp.post_topics, fp.post_replies FROM ::categories AS c INNER JOIN ::forums AS f ON c.id=f.cat_id LEFT JOIN ::forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=?i:gid) WHERE fp.read_forum IS NULL OR fp.read_forum=1 ORDER BY c.disp_position, c.id, f.disp_position', [':gid' => $user->groupId]);
while ($f = $stmt->fetch()) {
$tree[$f['parent_forum_id']][$f['fid']] = $f;
}

View file

@ -2,9 +2,9 @@
namespace ForkBB\Models\Pages;
use ForkBB\Core\Validator;
use ForkBB\Core\Exceptions\MailException;
use ForkBB\Models\User;
use ForkBB\Models\Validator;
class Auth extends Page
{
@ -235,7 +235,7 @@ class Auth extends Page
->setLanguage($this->tmpUser->language)
->setTo($v->email, $this->tmpUser->username)
->setFrom($this->config['o_webmaster_email'], __('Mailer', $this->config['o_board_title']))
->setTpl('password_reset.tpl', $tplData)
->setTpl('passphrase_reset.tpl', $tplData)
->send();
} catch (MailException $e) {
$isSent = false;
@ -341,7 +341,7 @@ class Auth extends Page
$v = $this->c->Validator;
$v->setRules([
'token' => 'token:ChangePassword',
'password' => ['required|string|min:8|password', __('New pass')],
'password' => ['required|string|min:16|password', __('New pass')],
'password2' => ['required|same:password', __('Confirm new pass')],
])->setArguments([
'token' => $args,

305
app/Models/Pages/Forum.php Normal file
View file

@ -0,0 +1,305 @@
<?php
namespace ForkBB\Models\Pages;
class Forum extends Page
{
/**
* Имя шаблона
* @var string
*/
protected $nameTpl = 'forum';
/**
* Позиция для таблицы онлайн текущего пользователя
* @var null|string
*/
protected $onlinePos = 'forum';
/**
* Подготовка данных для шаблона
* @param array $args
* @return Page
*/
public function view(array $args)
{
$this->c->Lang->load('index');
$this->c->Lang->load('subforums');
list($fTree, $fDesc, $fAsc) = $this->c->forums;
// раздел отсутствует в доступных
if (empty($fDesc[$args['id']])) {
return $this->c->Message->message('Bad request');
}
$parent = isset($fDesc[$args['id']][0]) ? $fDesc[$args['id']][0] : 0;
$perm = $fTree[$parent][$args['id']];
// редирект, если раздел это ссылка
if (! empty($perm['redirect_url'])) {
return $this->c->Redirect->setUrl($perm['redirect_url']);
}
$user = $this->c->user;
$vars = [
':fid' => $args['id'],
':uid' => $user->id,
':gid' => $user->groupId,
];
if ($user->isGuest) {
$sql = 'SELECT f.forum_name, f.moderators, f.num_topics, f.sort_by, 0 AS is_subscribed FROM ::forums AS f WHERE f.id=?i:fid';
} else {
$sql = 'SELECT f.forum_name, f.moderators, f.num_topics, f.sort_by, s.user_id AS is_subscribed, mof.mf_upper, mof.mf_lower FROM ::forums AS f LEFT JOIN ::forum_subscriptions AS s ON (f.id=s.forum_id AND s.user_id=?i:uid) LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:uid AND f.id=mof.fid) WHERE f.id=?i:fid';
}
$curForum = $this->c->DB->query($sql, $vars)->fetch();
// нет данных по данному разделу
if (! isset($curForum['forum_name'])) {
return $this->c->Message->message('Bad request'); //???? может в лог ошибок?
}
$page = isset($args['page']) ? (int) $args['page'] : 1;
if (empty($curForum['num_topics'])) {
// попытка открыть страницу которой нет
if ($page !== 1) {
return $this->c->Message->message('Bad request');
}
$pages = 1;
$offset = 0;
$topics = null;
} else {
$pages = ceil($curForum['num_topics'] / $user->dispTopics);
// попытка открыть страницу которой нет
if ($page < 1 || $page > $pages) {
return $this->c->Message->message('Bad request');
}
$offset = $user->dispTopics * ($page - 1);
switch ($curForum['sort_by']) {
case 1:
$sortBy = 'posted DESC';
break;
case 2:
$sortBy = 'subject ASC';
break;
case 0:
default:
$sortBy = 'last_post DESC';
break;
}
$vars = [
':fid' => $args['id'],
':offset' => $offset,
':rows' => $user->dispTopics,
];
$topics = $this->c->DB
->query("SELECT id FROM ::topics WHERE forum_id=?i:fid ORDER BY sticky DESC, {$sortBy}, id DESC LIMIT ?i:offset, ?i:rows", $vars)
->fetchAll(\PDO::FETCH_COLUMN);
}
$dotTopics = [];
if (! empty($topics)) {
$vars = [
':uid' => $user->id,
':topics' => $topics,
];
if (! $user->isGuest && $this->config['o_show_dot'] == '1') {
$dotTopics = $this->c->DB
->query('SELECT topic_id FROM ::posts WHERE topic_id IN (?ai:topics) AND poster_id=?i:uid GROUP BY topic_id', $vars)
->fetchAll(\PDO::FETCH_COLUMN);
}
if ($user->isGuest) {
$sql = "SELECT id, poster, subject, posted, last_post, last_post_id, last_poster, num_views, num_replies, closed, sticky, moved_to, poll_type FROM ::topics WHERE id IN(?ai:topics) ORDER BY sticky DESC, {$sortBy}, id DESC";
} else {
$sql = "SELECT t.id, t.poster, t.subject, t.posted, t.last_post, t.last_post_id, t.last_poster, t.num_views, t.num_replies, t.closed, t.sticky, t.moved_to, t.poll_type, mot.mt_upper, mot.mt_lower FROM ::topics AS t LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:uid AND t.id=mot.tid) WHERE t.id IN (?ai:topics) ORDER BY t.sticky DESC, t.{$sortBy}, t.id DESC";
}
$topics = $this->c->DB->query($sql, $vars)->fetchAll();
}
$moders = empty($curForum['moderators']) ? [] : array_flip(unserialize($curForum['moderators']));
$this->onlinePos = 'forum' . $args['id'];
// хлебные крошки и титул
$this->titles = [];
$crumbs = [];
$id = $args['id'];
$activ = true;
while (true) {
$name = $fDesc[$id]['forum_name'];
array_unshift($this->titles, $name);
$crumbs[] = [
$this->c->Router->link('Forum', ['id' => $id, 'name' => $name]),
$name,
$activ,
];
$activ = null;
if (! isset($fDesc[$id][0])) {
break;
}
$id = $fDesc[$id][0];
}
$crumbs[] = [
$this->c->Router->link('Index'),
__('Index'),
null,
];
$this->data = [
'forums' => $this->getForumsData($args['id']),
'topics' => $topics,
'dots' => array_flip($dotTopics),
'crumbs' => array_reverse($crumbs),
];
return $this;
}
/**
* Получение данных по разделам
* @param int $parent
* @return array
*/
protected function getForumsData($parent = 0)
{
list($fTree, $fDesc, $fAsc) = $this->c->forums;
// раздел $parent не имеет подразделов для вывода или они не доступны
if (empty($fTree[$parent])) {
return [];
}
$user = $this->c->user;
// текущие данные по подразделам
$vars = [
':id' => $user->id,
':forums' => array_slice($fAsc[$parent], 1),
];
if ($user->isGuest) {
$stmt = $this->c->DB->query('SELECT id, forum_desc, moderators, num_topics, num_posts, last_post, last_post_id, last_poster, last_topic FROM ::forums WHERE id IN (?ai:forums)', $vars);
} else {
$stmt = $this->c->DB->query('SELECT f.id, f.forum_desc, f.moderators, f.num_topics, f.num_posts, f.last_post, f.last_post_id, f.last_poster, f.last_topic, mof.mf_upper FROM ::forums AS f LEFT JOIN ::mark_of_forum AS mof ON (mof.uid=?i:id AND f.id=mof.fid) WHERE f.id IN (?ai:forums)', $vars);
}
$forums = [];
while ($cur = $stmt->fetch()) {
$forums[$cur['id']] = $cur;
}
// поиск новых
$new = [];
if (! $user->isGuest) {
// предварительная проверка разделов
$max = max((int) $user->lastVisit, (int) $user->uMarkAllRead);
foreach ($forums as $id => $cur) {
$t = max($max, (int) $cur['mf_upper']);
if ($cur['last_post'] > $t) {
$new[$id] = $t;
}
}
// проверка по темам
if (! empty($new)) {
$vars = [
':id' => $user->id,
':forums' => $new,
':max' => $max,
];
$stmt = $this->c->DB->query('SELECT t.forum_id, t.id, t.last_post FROM ::topics AS t LEFT JOIN ::mark_of_topic AS mot ON (mot.uid=?i:id AND mot.tid=t.id) WHERE t.forum_id IN(?ai:forums) AND t.last_post>?i:max AND t.moved_to IS NULL AND (mot.mt_upper IS NULL OR t.last_post>mot.mt_upper)', $vars);
$tmp = [];
while ($cur = $stmt->fetch()) {
if ($cur['last_post']>$new[$cur['forum_id']]) {
$tmp[$cur['forum_id']] = true;
}
}
$new = $tmp;
}
}
$r = $this->c->Router;
// формированием таблицы разделов
$result = [];
foreach ($fTree[$parent] as $fId => $cur) {
// список подразделов
$subForums = [];
if (isset($fTree[$fId])) {
foreach ($fTree[$fId] as $f) {
$subForums[] = [
$r->link('Forum', [
'id' => $f['fid'],
'name' => $f['forum_name']
]),
$f['forum_name']
];
}
}
// модераторы
$moderators = [];
if (!empty($forums[$fId]['moderators'])) {
$mods = unserialize($forums[$fId]['moderators']);
foreach ($mods as $name => $id) {
if ($user->gViewUsers == '1') {
$moderators[] = [
$r->link('User', [
'id' => $id,
'name' => $name,
]),
$name
];
} else {
$moderators[] = $name;
}
}
}
// статистика по разделам
$numT = 0;
$numP = 0;
$time = 0;
$postId = 0;
$poster = '';
$topic = '';
$fnew = false;
foreach ($fAsc[$fId] as $id) {
$fnew = $fnew || isset($new[$id]);
$numT += $forums[$id]['num_topics'];
$numP += $forums[$id]['num_posts'];
if ($forums[$id]['last_post'] > $time) {
$time = $forums[$id]['last_post'];
$postId = $forums[$id]['last_post_id'];
$poster = $forums[$id]['last_poster'];
$topic = $forums[$id]['last_topic'];
}
}
$result[$cur['cid']]['name'] = $cur['cat_name'];
$result[$cur['cid']]['forums'][] = [
'fid' => $fId,
'forum_name' => $cur['forum_name'],
'forum_desc' => $forums[$fId]['forum_desc'],
'forum_link' => $r->link('Forum', [
'id' => $fId,
'name' => $cur['forum_name']
]),
'redirect_url' => $cur['redirect_url'],
'subforums' => $subForums,
'moderators' => $moderators,
'num_topics' => $numT,
'num_posts' => $numP,
'topics' => $this->number($numT),
'posts' => $this->number($numP),
'last_post' => $this->time($time),
'last_post_id' => $postId > 0 ? $r->link('viewPost', ['id' => $postId]) : null,
'last_poster' => $poster,
'last_topic' => $topic,
'new' => $fnew,
];
}
return $result;
}
}

View file

@ -39,9 +39,6 @@ class Index extends Page
$this->c->Lang->load('index');
$this->c->Lang->load('subforums');
$user = $this->c->user;
$r = $this->c->Router;
$stats = $this->c->users_info;
$stmt = $this->c->DB->query('SELECT SUM(num_topics), SUM(num_posts) FROM ::forums');
@ -49,9 +46,9 @@ class Index extends Page
$stats['total_users'] = $this->number($stats['total_users']);
if ($user->gViewUsers == '1') {
if ($this->c->user->gViewUsers == '1') {
$stats['newest_user'] = [
$r->link('User', [
$this->c->Router->link('User', [
'id' => $stats['last_user']['id'],
'name' => $stats['last_user']['username'],
]),
@ -72,10 +69,10 @@ class Index extends Page
list($users, $guests, $bots) = $this->c->Online->handle($this);
$list = [];
if ($user->gViewUsers == '1') {
if ($this->c->user->gViewUsers == '1') {
foreach ($users as $id => $cur) {
$list[] = [
$r->link('User', [
$this->c->Router->link('User', [
'id' => $id,
'name' => $cur['name'],
]),

View file

@ -3,7 +3,7 @@
namespace ForkBB\Models\Pages;
use ForkBB\Core\Container;
use ForkBB\Models\Validator;
use ForkBB\Core\Validator;
use PDO;
use PDOException;
use RuntimeException;
@ -217,7 +217,7 @@ class Install extends Page
'dbpass' => ['string:trim', __('Database password')],
'dbprefix' => ['string:trim|max:40|check_prefix', __('Table prefix')],
'username' => ['required|string:trim|min:2|max:25', __('Administrator username')],
'password' => ['required|string|min:8|password', __('Administrator passphrase')],
'password' => ['required|string|min:16|password', __('Administrator passphrase')],
'email' => 'required|string:trim,lower|email',
'title' => ['required|string:trim', __('Board title')],
'descr' => ['required|string:trim', __('Board description')],

View file

@ -51,7 +51,7 @@ class Maintenance extends Page
__('Maintenance'),
];
$this->data = [
'MaintenanceMessage' => $this->config['o_maintenance_message'],
'maintenanceMessage' => $this->config['o_maintenance_message'],
];
return parent::getData();
}

View file

@ -25,8 +25,8 @@ class Message extends Page
__('Info'),
];
$this->data = [
'Message' => __($message),
'Back' => $back,
'message' => __($message),
'back' => $back,
];
return $this;
}

View file

@ -2,9 +2,9 @@
namespace ForkBB\Models\Pages;
use ForkBB\Core\Validator;
use ForkBB\Core\Exceptions\MailException;
use ForkBB\Models\User;
use ForkBB\Models\Validator;
class Register extends Page
{
@ -43,7 +43,7 @@ class Register extends Page
'on' => 'integer',
'email' => ['required_with:on|string:trim,lower|email|check_email', __('Email')],
'username' => ['required_with:on|string:trim|min:2|max:25|login|check_username', __('Username')],
'password' => ['required_with:on|string|min:8|password', __('Passphrase')],
'password' => ['required_with:on|string|min:16|password', __('Passphrase')],
])->setMessages([
'agree.required' => ['cancel', 'cancel'],
'agree.token' => [__('Bad agree', $this->c->Router->link('Register')), 'w'],
@ -113,7 +113,9 @@ class Register extends Page
if (preg_match('%^(guest|' . preg_quote(__('Guest'), '%') . ')$%iu', $username)) {
$error = __('Username guest');
// цензура
} elseif ($this->config['o_censoring'] == '1' && censor_words($username) !== $username) {
} elseif ($this->config['o_censoring'] == '1'
&& preg_replace($this->c->censoring[0], $this->c->censoring[1], $username) !== $username
) {
$error = __('Username censor');
// username забанен
} elseif ($this->c->CheckBans->isBanned($username) > 0) {

View file

@ -64,7 +64,7 @@ return [
'class' => \ForkBB\Core\Secury::class,
'hmac' => '%HMAC%',
],
'Validator' => \ForkBB\Models\Validator::class,
'Validator' => \ForkBB\Core\Validator::class,
],
'multiple' => [
'PrimaryController' => \ForkBB\Controllers\Install::class,

View file

@ -56,6 +56,7 @@ return [
'class' => \ForkBB\Core\Cache::class,
'provider' => '@FileCache',
],
'Validator' => \ForkBB\Core\Validator::class,
'View' => [
'class' => \ForkBB\Core\View::class,
'cache_dir' => '%DIR_CACHE%',
@ -122,13 +123,12 @@ return [
'max' => '%TIME_REMEMBER%',
],
'Csrf' => [
'class' => \ForkBB\Models\Csrf::class,
'class' => \ForkBB\Core\Csrf::class,
'Secury' => '@Secury',
'user' => '@user',
'key' => '%user.password%%user.ip%%user.id%',
],
'Online' => \ForkBB\Models\Online::class,
'UserMapper' => \ForkBB\Models\UserMapper::class,
'Validator' => \ForkBB\Models\Validator::class,
'Message' => \ForkBB\Models\Pages\Message::class,
],

View file

@ -0,0 +1,12 @@
Subject: New passphrase requested
Hello <username>,
You have requested to have a new passphrase assigned to your account in the discussion forum at <fRootLink>
To change your passphrase, please visit the following page:
<link>
--
<fMailer> Mailer
(Do not reply to this message)

View file

@ -1,12 +0,0 @@
Subject: New password requested
Hello <username>,
You have requested to have a new password assigned to your account in the discussion forum at <fRootLink>
To change your password, please visit the following page:
<link>
--
<fMailer> Mailer
(Do not reply to this message)

View file

@ -0,0 +1,12 @@
Subject: Запрос на смену кодовой фразы
Здравствуйте, <username>.
Кто-то, возможно вы, сделал запрос на смену кодовой фразы аккаунта на форуме <fRootLink>
Чтобы сменить кодовую фразу, вам нужно перейти по ссылке:
<link>
--
Отправитель <fMailer>
(Не отвечайте на это сообщение)

View file

@ -1,12 +0,0 @@
Subject: Запрос на смену пароля
Здравствуйте, <username>.
Кто-то, возможно вы, сделал запрос на смену пароля аккаунта на форуме <fRootLink>
Чтобы сменить пароль, вам нужно перейти по ссылке:
<link>
--
Отправитель <fMailer>
(Не отвечайте на это сообщение)

View file

@ -6,11 +6,11 @@
<input type="hidden" name="token" value="{!! $formToken !!}">
<div>
<label class="f-child1 f-req" for="id-password">{!! __('New pass') !!}</label>
<input required class="f-ctrl" id="id-password" type="password" name="password" pattern=".{8,}" autofocus="autofocus" tabindex="1">
<input required class="f-ctrl" id="id-password" type="password" name="password" pattern="^.{16,}$" autofocus="autofocus" tabindex="1">
</div>
<div>
<label class="f-child1 f-req" for="id-password2">{!! __('Confirm new pass') !!}</label>
<input required class="f-ctrl" id="id-password2" type="password" name="password2" pattern=".{8,}" tabindex="2">
<input required class="f-ctrl" id="id-password2" type="password" name="password2" pattern="^.{16,}$" tabindex="2">
<label class="f-child4">{!! __('Pass format') !!} {!! __('Pass info') !!}</label>
</div>
<div>

35
app/templates/forum.tpl Normal file
View file

@ -0,0 +1,35 @@
@section('crumbs')
<section class="f-crumbs">
<ul>
@foreach($crumbs as $cur)
@if($cur[2])
<li class="f-crumb"><a href="{!! $cur[0] !!}" class="active">{{ $cur[1] }}</a></li>
@else
<li class="f-crumb"><a href="{!! $cur[0] !!}">{{ $cur[1] }}</a></li>
@endif
@endforeach
</ul>
</section>
@endsection
@extends('layouts/main')
@if($forums)
@yield('crumbs')
<section class="f-subforums">
<ol class="f-forumlist">
@foreach($forums as $id => $cat)
<li id="id-subforums{!! $id !!}" class="f-category">
<h2>{{ __('Sub forum', 2) }}</h2>
<ol class="f-table">
<li class="f-row f-thead" value="0">
<div class="f-hcell f-cmain">{!! __('Sub forum', 1) !!}</div>
<div class="f-hcell f-cstats">{!! __('Stats') !!}</div>
<div class="f-hcell f-clast">{!! __('Last post') !!}</div>
</li>
@include('layouts/subforums')
</ol>
</li>
@endforeach
</ol>
</section>
@endif
@yield('crumbs')

View file

@ -11,79 +11,7 @@
<div class="f-hcell f-cstats">{!! __('Stats') !!}</div>
<div class="f-hcell f-clast">{!! __('Last post') !!}</div>
</li>
@foreach($cat['forums'] as $cur)
@if($cur['redirect_url'])
<li id="forum-{!! $cur['fid']!!}" class="f-row f-fredir">
<div class="f-cell f-cmain">
<div class="f-ficon"></div>
<div class="f-finfo">
<h3><span class="f-fredirtext">{!! __('Link to') !!}</span> <a href="{!! $cur['redirect_url'] !!}">{{ $cur['forum_name'] }}</a></h3>
@if($cur['forum_desc'])
<p class="f-fdesc">{!! $cur['forum_desc'] !!}</p>
@endif
</div>
</div>
</li>
@else
@if($cur['new'])
<li id="forum-{!! $cur['fid'] !!}" class="f-row f-fnew">
@else
<li id="forum-{!! $cur['fid'] !!}" class="f-row">
@endif
<div class="f-cell f-cmain">
<div class="f-ficon"></div>
<div class="f-finfo">
<h3>
<a href="{!! $cur['forum_link'] !!}">{{ $cur['forum_name'] }}</a>
@if($cur['new'])
<span class="f-newtxt"><a href="">{!! __('New posts') !!}</a></span>
@endif
</h3>
@if($cur['subforums'])
<dl class="f-inline f-fsub"><!--inline-->
<dt>{!! __('Sub forum', count($cur['subforums'])) !!}</dt>
@foreach($cur['subforums'] as $sub)
<dd><a href="{!! $sub[0] !!}">{{ $sub[1] }}</a></dd>
@endforeach
</dl><!--endinline-->
@endif
@if($cur['forum_desc'])
<p class="f-fdesc">{!! $cur['forum_desc'] !!}</p>
@endif
@if($cur['moderators'])
<dl class="f-inline f-modlist"><!--inline-->
<dt>{!! __('Moderated by') !!}</dt>
@foreach($cur['moderators'] as $mod)
@if(is_string($mod))
<dd>{{ $mod }}</dd>
@else
<dd><a href="{!! $mod[0] !!}">{{ $mod[1] }}</a></dd>
@endif
@endforeach
</dl><!--endinline-->
@endif
</div>
</div>
<div class="f-cell f-cstats">
<ul>
<li>{!! __('%s Topic', $cur['num_topics'], $cur['topics']) !!}</li>
<li>{!! __('%s Post', $cur['num_posts'], $cur['posts'])!!}</li>
</ul>
</div>
<div class="f-cell f-clast">
<ul>
@if($cur['last_post_id'])
<li class="f-cltopic"><a href="{!! $cur['last_post_id'] !!}" title="&quot;{{ $cur['last_topic'] }}&quot; - {!! __('Last post') !!}">{{ $cur['last_topic'] }}</a></li>
<li class="f-clposter">{!! __('by') !!} {{ $cur['last_poster'] }}</li>
<li class="f-cltime">{!! $cur['last_post'] !!}</li>
@else
<li class="f-cltopic">{!! __('Never') !!}</li>
@endif
</ul>
</div>
</li>
@endif
@endforeach
@include('layouts/subforums')
</ol>
</li>
@endforeach

View file

@ -0,0 +1,73 @@
@foreach($cat['forums'] as $cur)
@if($cur['redirect_url'])
<li id="forum-{!! $cur['fid']!!}" class="f-row f-fredir">
<div class="f-cell f-cmain">
<div class="f-ficon"></div>
<div class="f-finfo">
<h3><span class="f-fredirtext">{!! __('Link to') !!}</span> <a href="{!! $cur['redirect_url'] !!}">{{ $cur['forum_name'] }}</a></h3>
@if($cur['forum_desc'])
<p class="f-fdesc">{!! $cur['forum_desc'] !!}</p>
@endif
</div>
</div>
</li>
@else
@if($cur['new'])
<li id="forum-{!! $cur['fid'] !!}" class="f-row f-fnew">
@else
<li id="forum-{!! $cur['fid'] !!}" class="f-row">
@endif
<div class="f-cell f-cmain">
<div class="f-ficon"></div>
<div class="f-finfo">
<h3>
<a href="{!! $cur['forum_link'] !!}">{{ $cur['forum_name'] }}</a>
@if($cur['new'])
<span class="f-newtxt"><a href="">{!! __('New posts') !!}</a></span>
@endif
</h3>
@if($cur['subforums'])
<dl class="f-inline f-fsub"><!--inline-->
<dt>{!! __('Sub forum', count($cur['subforums'])) !!}</dt>
@foreach($cur['subforums'] as $sub)
<dd><a href="{!! $sub[0] !!}">{{ $sub[1] }}</a></dd>
@endforeach
</dl><!--endinline-->
@endif
@if($cur['forum_desc'])
<p class="f-fdesc">{!! $cur['forum_desc'] !!}</p>
@endif
@if($cur['moderators'])
<dl class="f-inline f-modlist"><!--inline-->
<dt>{!! __('Moderated by') !!}</dt>
@foreach($cur['moderators'] as $mod)
@if(is_string($mod))
<dd>{{ $mod }}</dd>
@else
<dd><a href="{!! $mod[0] !!}">{{ $mod[1] }}</a></dd>
@endif
@endforeach
</dl><!--endinline-->
@endif
</div>
</div>
<div class="f-cell f-cstats">
<ul>
<li>{!! __('%s Topic', $cur['num_topics'], $cur['topics']) !!}</li>
<li>{!! __('%s Post', $cur['num_posts'], $cur['posts'])!!}</li>
</ul>
</div>
<div class="f-cell f-clast">
<ul>
@if($cur['last_post_id'])
<li class="f-cltopic"><a href="{!! $cur['last_post_id'] !!}" title="&quot;{{ $cur['last_topic'] }}&quot; - {!! __('Last post') !!}">{{ $cur['last_topic'] }}</a></li>
<li class="f-clposter">{!! __('by') !!} {{ $cur['last_poster'] }}</li>
<li class="f-cltime">{!! $cur['last_post'] !!}</li>
@else
<li class="f-cltopic">{!! __('Never') !!}</li>
@endif
</ul>
</div>
</li>
@endif
@endforeach

View file

@ -1,5 +1,5 @@
@extends('layouts/main')
<section class="f-main f-maintenance">
<h2>{{ __('Maintenance') }}</h2>
<p>{!! $MaintenanceMessage !!}</p>
<p>{!! $maintenanceMessage !!}</p>
</section>

View file

@ -1,8 +1,8 @@
@extends('layouts/main')
<section class="f-main f-message">
<h2>{!! __('Info') !!}</h2>
<p>{!! $Message !!}</p>
@if($Back)
<p>{!! $message !!}</p>
@if($back)
<p><a href="javascript: history.go(-1)">{!! __('Go back') !!}</a></p>
@endif
</section>

View file

@ -442,19 +442,20 @@ select {
border-top: 0.0625rem solid #AA7939;
}
.f-crumb {
padding: 0.625rem;
.f-crumbs {
margin: 1rem 0;
padding: 0 0.625rem;
display: block;
overflow: hidden;
}
.f-crumb-item {
.f-crumb {
display: block;
float: left;
white-space: nowrap;
}
.f-crumb-item + .f-crumb-item:before {
.f-crumb + .f-crumb:before {
display: inline-block;
padding-right: 0.5rem;
padding-left: 0.5rem;
@ -462,7 +463,7 @@ select {
content: "/";
}
.f-crumb-item a.active {
.f-crumb a.active {
border: 0;
}
@ -1093,7 +1094,6 @@ li + li .f-btn {
/*************/
/* Установка */
/*************/
.f-install .f-lrdiv {
margin: 1rem 0;
max-width: 100%;
@ -1110,3 +1110,18 @@ li + li .f-btn {
margin-top: -0.375rem;
margin-bottom: 1rem;
}
/**********/
/* Форумы */
/**********/
.f-subforums {
margin: 1rem 0;
}
.f-subforums .f-category > h2 {
display: none;
}
.f-subforums .f-forumlist .f-thead {
border-bottom-width: 0.0625rem;
}