瀏覽代碼

2017-12-24

Visman 7 年之前
父節點
當前提交
2066bd1790

+ 2 - 1
app/Controllers/Routing.php

@@ -108,11 +108,12 @@ class Routing
         if ($user->isAdmin) {
         if ($user->isAdmin) {
             $r->add('GET',  '/admin/statistics/info', 'AdminStatistics:info', 'AdminInfo');
             $r->add('GET',  '/admin/statistics/info', 'AdminStatistics:info', 'AdminInfo');
             $r->add('GET',  '/admin/groups', 'AdminGroups:view', 'AdminGroups');
             $r->add('GET',  '/admin/groups', 'AdminGroups:view', 'AdminGroups');
-            $r->add('POST', '/admin/groups/new[/{base:[1-9]\d*}]', 'AdminGroups:newPost', 'AdminGroupsNew');
+            $r->add('POST', '/admin/groups/new[/{base:[1-9]\d*}]', 'AdminGroups:editPost', 'AdminGroupsNew');
             $r->add('POST', '/admin/groups/default', 'AdminGroups:defaultPost', 'AdminGroupsDefault');
             $r->add('POST', '/admin/groups/default', 'AdminGroups:defaultPost', 'AdminGroupsDefault');
             $r->add('GET',  '/admin/groups/{id:[1-9]\d*}/edit', 'AdminGroups:edit', 'AdminGroupsEdit');
             $r->add('GET',  '/admin/groups/{id:[1-9]\d*}/edit', 'AdminGroups:edit', 'AdminGroupsEdit');
             $r->add('POST', '/admin/groups/{id:[1-9]\d*}/edit', 'AdminGroups:editPost');
             $r->add('POST', '/admin/groups/{id:[1-9]\d*}/edit', 'AdminGroups:editPost');
             $r->add('GET',  '/admin/groups/{id:[1-9]\d*}/delete', 'AdminGroups:delete', 'AdminGroupsDelete');
             $r->add('GET',  '/admin/groups/{id:[1-9]\d*}/delete', 'AdminGroups:delete', 'AdminGroupsDelete');
+            $r->add('POST', '/admin/groups/{id:[1-9]\d*}/delete', 'AdminGroups:deletePost');
         }
         }
 
 
         $uri = $_SERVER['REQUEST_URI'];
         $uri = $_SERVER['REQUEST_URI'];

+ 1 - 1
app/Models/Forum/Manager.php

@@ -19,7 +19,7 @@ class Manager extends ManagerModel
      * 
      * 
      * @param array $attrs
      * @param array $attrs
      * 
      * 
-     * @return Topic
+     * @return Forum
      */
      */
     public function create(array $attrs = [])
     public function create(array $attrs = [])
     {
     {

+ 7 - 8
app/Models/Forum/Save.php

@@ -57,20 +57,19 @@ class Save extends Action
      */
      */
     public function insert(Forum $forum)
     public function insert(Forum $forum)
     {
     {
-        $modified = $forum->getModified();
-        if (null !== $forum->id || in_array('id', $modified)) {
+        if (null !== $forum->id) {
             throw new RuntimeException('The model has ID');
             throw new RuntimeException('The model has ID');
         }
         }
-        $values = $forum->getAttrs();
+        $attrs  = $forum->getAttrs();
         $fileds = $this->c->dbMap->forums;
         $fileds = $this->c->dbMap->forums;
         $set = $set2 = $vars = [];
         $set = $set2 = $vars = [];
-        foreach ($modified as $name) {
-            if (! isset($fileds[$name])) {
+        foreach ($attrs as $key => $value) {
+            if (! isset($fileds[$key])) {
                 continue;
                 continue;
             }
             }
-            $vars[] = $values[$name];
-            $set[] = $name;
-            $set2[] = '?' . $fileds[$name];
+            $vars[] = $value;
+            $set[]  = $key;
+            $set2[] = '?' . $fileds[$key];
         }
         }
         if (empty($set)) {
         if (empty($set)) {
             throw new RuntimeException('The model is empty');
             throw new RuntimeException('The model is empty');

+ 90 - 0
app/Models/Group/Manager.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace ForkBB\Models\Group;
+
+use ForkBB\Models\ManagerModel;
+use ForkBB\Models\Group\Model as Group;
+use RuntimeException;
+
+class Manager extends ManagerModel
+{
+    /**
+     * Флаг загрузки групп
+     * @var bool
+     */
+    protected $flag;
+
+    /**
+     * Создает новую модель раздела
+     * 
+     * @param array $attrs
+     * 
+     * @return Group
+     */
+    public function create(array $attrs = [])
+    {
+        return $this->c->GroupModel->setAttrs($attrs);
+    }
+
+    public function getList()
+    {
+        return $this->repository;
+    }
+
+    /**
+     * Загрузка списка групп
+     * 
+     * @return Manager
+     */
+    public function init()
+    {
+        if (empty($this->flag)) {
+            $stmt = $this->c->DB->query('SELECT * FROM ::groups ORDER BY g_id');
+            while ($row = $stmt->fetch()) {
+                $this->set($row['g_id'], $this->create($row));
+            }
+            $this->flag = true;
+        }
+        return $this;
+    }
+
+    /**
+     * Получение модели группы
+     * 
+     * @param int $id
+     * 
+     * @return null|Group
+     */
+    public function get($id)
+    {
+        $group = parent::get($id);
+
+        return $group instanceof Group ? $group : null;
+    }
+
+    /**
+     * Обновляет группу в БД
+     *
+     * @param Group $group
+     * 
+     * @return Group
+     */
+    public function update(Group $group)
+    {
+        return $this->Save->update($group);
+    }
+
+    /**
+     * Добавляет новую группу в БД
+     *
+     * @param Group $group
+     * 
+     * @return int
+     */
+    public function insert(Group $group)
+    {
+        $id = $this->Save->insert($group);
+        $this->set($id, $group);
+        return $id;
+    }
+}

+ 36 - 0
app/Models/Group/Model.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace ForkBB\Models\Group;
+
+use ForkBB\Models\DataModel;
+use RuntimeException;
+use InvalidArgumentException;
+
+class Model extends DataModel
+{
+    protected function getlinkEdit()
+    {
+        return $this->c->Router->link('AdminGroupsEdit', ['id' => $this->g_id]);
+    }
+
+    protected function getcanDelete()
+    {
+        $notDeleted = [
+            $this->c->GROUP_ADMIN, 
+            $this->c->GROUP_MOD, 
+            $this->c->GROUP_GUEST, 
+            $this->c->GROUP_MEMBER
+        ];
+        return ! in_array($this->g_id, $notDeleted) && $this->g_id != $this->c->config->o_default_user_group;
+    }
+
+    protected function getlinkDelete()
+    {
+        return $this->canDelete ? $this->c->Router->link('AdminGroupsDelete', ['id' => $this->g_id]) : null;
+    }
+
+    protected function getgroupGuest()
+    {
+        return $this->g_id === $this->c->GROUP_GUEST;
+    }
+}

+ 83 - 0
app/Models/Group/Save.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace ForkBB\Models\Group;
+
+use ForkBB\Models\Action;
+use ForkBB\Models\Group\Model as Group;
+use RuntimeException;
+
+class Save extends Action
+{
+    /**
+     * Обновляет группу в БД
+     *
+     * @param Group $group
+     * 
+     * @throws RuntimeException
+     * 
+     * @return Group
+     */
+    public function update(Group $group)
+    {
+        if ($group->g_id < 1) {
+            throw new RuntimeException('The model does not have ID');
+        }
+        $modified = $group->getModified();
+        if (empty($modified)) {
+            return $group;
+        }
+        $values = $group->getAttrs();
+        $fileds = $this->c->dbMap->groups;
+        $set = $vars = [];
+        foreach ($modified as $name) {
+            if (! isset($fileds[$name])) {
+                continue;
+            }
+            $vars[] = $values[$name];
+            $set[] = $name . '=?' . $fileds[$name];
+        }
+        if (empty($set)) {
+            return $group;
+        }
+        $vars[] = $group->g_id;
+        $this->c->DB->query('UPDATE ::groups SET ' . implode(', ', $set) . ' WHERE id=?i', $vars);
+        $group->resModified();
+
+        return $group;
+    }
+
+    /**
+     * Добавляет новую группу в БД
+     *
+     * @param Group $group
+     * 
+     * @throws RuntimeException
+     * 
+     * @return int
+     */
+    public function insert(Group $group)
+    {
+        if (null !== $group->g_id) {
+            throw new RuntimeException('The model has ID');
+        }
+        $attrs  = $group->getAttrs();
+        $fileds = $this->c->dbMap->groups;
+        $set = $set2 = $vars = [];
+        foreach ($attrs as $key => $value) {
+            if (! isset($fileds[$key])) {
+                continue;
+            }
+            $vars[] = $value;
+            $set[]  = $key;
+            $set2[] = '?' . $fileds[$key];
+        }
+        if (empty($set)) {
+            throw new RuntimeException('The model is empty');
+        }
+        $this->c->DB->query('INSERT INTO ::groups (' . implode(', ', $set) . ') VALUES (' . implode(', ', $set2) . ')', $vars);
+        $group->g_id = $this->c->DB->lastInsertId();
+        $group->resModified();
+
+        return $group->g_id;
+    }
+}

+ 422 - 337
app/Models/Pages/Admin/Groups.php

@@ -4,129 +4,117 @@ namespace ForkBB\Models\Pages\Admin;
 
 
 use ForkBB\Core\Container;
 use ForkBB\Core\Container;
 use ForkBB\Core\Validator;
 use ForkBB\Core\Validator;
+use ForkBB\Models\Group\Model as Group;
 use ForkBB\Models\Pages\Admin;
 use ForkBB\Models\Pages\Admin;
 
 
 class Groups extends Admin
 class Groups extends Admin
 {
 {
-    /**
-     * Массив групп
-     * @var array
-     */
-    protected $groups;
-
-    /**
-     * Список групп доступных как основа для новой
-     * @var array
-     */
-    protected $grBase = [];
-
-    /**
-     * Список групп доступных для группы по умолчанию
-     * @var array
-     */
-    protected $grDefault = [];
-
-    /**
-     * Список групп доступных для удаления
-     * @var array
-     */
-    protected $grDelete = [];
-
     /**
     /**
      * Конструктор
      * Конструктор
-     * 
+     *
      * @param Container $container
      * @param Container $container
      */
      */
     public function __construct(Container $container)
     public function __construct(Container $container)
     {
     {
         parent::__construct($container);
         parent::__construct($container);
 
 
-        $this->getGroup();
-        $forBase = [$this->c->GROUP_UNVERIFIED, $this->c->GROUP_ADMIN, $this->c->GROUP_GUEST];
-        $forDelete = [$this->c->GROUP_UNVERIFIED, $this->c->GROUP_ADMIN, $this->c->GROUP_MOD, $this->c->GROUP_GUEST, $this->c->GROUP_MEMBER];
+        $this->c->Lang->load('admin_groups');
 
 
-        foreach ($this->groups as $key => $cur) {
-            if (! in_array($key, $forBase)) {
-                $this->grBase[$key] = true;
-                if ($cur['g_moderator'] == 0) {
-                    $this->grDefault[$key] = true;
-                }
-                if (! in_array($key, $forDelete)) {
-                    $this->grDelete[$key] = true;
-                }
-            }
-        }
-        $this->aIndex = 'groups';
-    }
+        $groupsList    = [];
+        $groupsNew     = [];
+        $groupsDefault = [];
+        $notForNew     = [$this->c->GROUP_ADMIN];
+        $notForDefault = [$this->c->GROUP_ADMIN, $this->c->GROUP_MOD, $this->c->GROUP_GUEST];
 
 
-    /**
-     * Создает массив групп
-     */
-    protected function getGroup()
-    {
-        if (empty($this->groups)) {
-            $this->groups = [];
-            $stmt = $this->c->DB->query('SELECT * FROM ::groups ORDER BY g_id');
-            while ($cur = $stmt->fetch()) {
-                $this->groups[$cur['g_id']] = $cur;
+        foreach ($this->c->groups->getList() as $key => $group) {
+            $groupsList[$key] = [$group->g_title, $group->linkEdit, $group->linkDelete];
+
+            if (! in_array($group->g_id, $notForNew)) {
+                $groupsNew[$key] = $group->g_title;
+            }
+            if (! in_array($group->g_id, $notForDefault) && $group->g_moderator == 0) {
+                $groupsDefault[$key] = $group->g_title;
             }
             }
         }
         }
+        $this->groupsList    = $groupsList;
+        $this->groupsNew     = $groupsNew;
+        $this->groupsDefault = $groupsDefault;
+        $this->aIndex        = 'groups';
     }
     }
 
 
     /**
     /**
      * Подготавливает данные для шаблона
      * Подготавливает данные для шаблона
-     * 
+     *
      * @return Page
      * @return Page
      */
      */
     public function view()
     public function view()
     {
     {
-        $groupsList = [];
-        $groupsNew = [];
-        $groupsDefault = [];
-        foreach ($this->groups as $key => $cur) {
-            $groupsList[] = [
-                $this->c->Router->link('AdminGroupsEdit', ['id' => $key]),
-                $cur['g_title'],
-                isset($this->grDelete[$key]) 
-                    ? $this->c->Router->link('AdminGroupsDelete', ['id' => $key])
-                    : null,
-            ];
-            if (isset($this->grBase[$key])) {
-                $groupsNew[] = [$key, $cur['g_title']];
-            }
-            if (isset($this->grDefault[$key])) {
-                $groupsDefault[] = [$key, $cur['g_title']];
-            }
-        }
-
-        $this->c->Lang->load('admin_groups');
-
-        $this->nameTpl = 'admin/groups';
-        $this->formActionNew     = $this->c->Router->link('AdminGroupsNew');
-        $this->formTokenNew      = $this->c->Csrf->create('AdminGroupsNew');
-        $this->formActionDefault = $this->c->Router->link('AdminGroupsDefault');
-        $this->formTokenDefault  = $this->c->Csrf->create('AdminGroupsDefault');
-        $this->defaultGroup      = $this->c->config->o_default_user_group;
-        $this->groupsNew         = $groupsNew;
-        $this->groupsDefault     = $groupsDefault;
-        $this->groupsList        = $groupsList;
-        $this->tabindex          = 0;
+        $this->nameTpl     = 'admin/groups';
+        $this->formNew     = [
+            'action' => $this->c->Router->link('AdminGroupsNew'),
+            'hidden' => [
+                'token' => $this->c->Csrf->create('AdminGroupsNew'),
+            ],
+            'sets'   => [[
+                'fields' => [
+                    'basegroup' => [
+                        'type'      => 'select',
+                        'options'   => $this->groupsNew,
+                        'value'     => $this->c->config->o_default_user_group,
+                        'title'     => \ForkBB\__('New group label'),
+                        'info'      => \ForkBB\__('New group help'),
+                        'autofocus' => true,
+                    ],
+                ],
+            ]],
+            'btns'   => [
+                'submit'  => [
+                    'type'      => 'submit',
+                    'value'     => \ForkBB\__('Add'),
+                    'accesskey' => 'a',
+                ],
+            ],
+        ];
+        $this->formDefault = [
+            'action' => $this->c->Router->link('AdminGroupsDefault'),
+            'hidden' => [
+                'token' => $this->c->Csrf->create('AdminGroupsDefault'),
+            ],
+            'sets'   => [[
+                'fields' => [
+                    'defaultgroup' => [
+                        'type'    => 'select',
+                        'options' => $this->groupsDefault,
+                        'value'   => $this->c->config->o_default_user_group,
+                        'title'   => \ForkBB\__('Default group label'),
+                        'info'    => \ForkBB\__('Default group help'),
+                    ],
+                ],
+            ]],
+            'btns'   => [
+                'submit'  => [
+                    'type'      => 'submit',
+                    'value'     => \ForkBB\__('Save'),
+                    'accesskey' => 's',
+                ],
+            ],
+        ];
 
 
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
      * Устанавливает группу по умолчанию
      * Устанавливает группу по умолчанию
-     * 
+     *
      * @return Page
      * @return Page
      */
      */
     public function defaultPost()
     public function defaultPost()
     {
     {
-        $this->c->Lang->load('admin_groups');
-
         $v = $this->c->Validator->setRules([
         $v = $this->c->Validator->setRules([
             'token'        => 'token:AdminGroupsDefault',
             'token'        => 'token:AdminGroupsDefault',
-            'defaultgroup' => 'required|integer|in:' . implode(',', array_keys($this->grDefault)),
+            'defaultgroup' => 'required|integer|in:' . implode(',', array_keys($this->groupsDefault)),
+        ])->setMessages([
+            'defaultgroup.in' => 'Invalid default group',
         ]);
         ]);
 
 
         if (! $v->validation($_POST)) {
         if (! $v->validation($_POST)) {
@@ -138,105 +126,107 @@ class Groups extends Admin
         return $this->c->Redirect->page('AdminGroups')->message(\ForkBB\__('Default group redirect'));
         return $this->c->Redirect->page('AdminGroups')->message(\ForkBB\__('Default group redirect'));
     }
     }
 
 
-    /**
-     * Подготавливает данные для создание группы
-     * Создает новую группу
-     * 
-     * @param array $args
-     * 
-     * @return Page
-     */
-    public function newPost(array $args)
-    {
-        $this->c->Lang->load('admin_groups');
-
-        if (empty($args['base'])) {
-            $v = $this->c->Validator->setRules([
-                'token'     => 'token:AdminGroupsNew',
-                'basegroup' => ['required|integer|in:' . implode(',', array_keys($this->grBase)), \ForkBB\__('New group label')]
-            ]);
-
-            if (! $v->validation($_POST)) {
-                $this->fIswev = $v->getErrors();
-                return $this->view();
-            } else {
-                return $this->edit(['id' => $v->basegroup, '_new' => true]);
-            }
-        } else {
-            return $this->editPost(['id' => $args['base'], '_new' => true]);
-        }
-    }
-
     /**
     /**
      * Подготавливает данные для шаблона редактирования группы
      * Подготавливает данные для шаблона редактирования группы
-     * 
+     *
      * @param array $args
      * @param array $args
-     * 
+     *
      * @return Page
      * @return Page
      */
      */
     public function edit(array $args)
     public function edit(array $args)
     {
     {
-        $groups = $this->groups;
+        if (isset($args['base'])) {
+            $group = $this->c->groups->get((int) $args['base']);
+        } else {
+            $group = $this->c->groups->get((int) $args['id']);
+        }
 
 
-        if (isset($args['_data'])) {
-            $groups[$args['id']] = $args['_data'];
-        } elseif (! isset($groups[$args['id']])) {
+        if (null === $group) {
             return $this->c->Message->message('Bad request');
             return $this->c->Message->message('Bad request');
         }
         }
 
 
-        if (isset($args['_new'])) {
-            $id = -1;
-            $marker = 'AdminGroupsNew';
-            $vars = ['base' => $args['id']];
-            if (! isset($args['_data'])) {
-                unset($groups[$args['id']]['g_title']);
-            }
+        $group = clone $group;
+
+        if (isset($args['base'])) {
+            $vars            = ['base' => $group->g_id];
+            $group->g_title  = '';
+            $group->g_id     = null;
+            $marker          = 'AdminGroupsNew';
+            $this->titles    = \ForkBB\__('Create new group');
+            $this->titleForm = \ForkBB\__('Create new group');
         } else {
         } else {
-            $id = (int) $args['id'];
-            $marker = 'AdminGroupsEdit';
-            $vars = ['id' => $id];
+            $vars            = ['id' => $group->g_id];
+            $marker          = 'AdminGroupsEdit';
+            $this->titles    = \ForkBB\__('Edit group');
+            $this->titleForm = \ForkBB\__('Edit group');
         }
         }
 
 
-        $this->c->Lang->load('admin_groups');
+        if (isset($args['_data'])) {
+            $group->replAttrs($args['_data']);
+        }
 
 
-        $this->formAction = $this->c->Router->link($marker, $vars);
-        $this->formToken  = $this->c->Csrf->create($marker, $vars);
-        $this->form       = $this->viewForm($id, $groups[$args['id']]);
-        $this->warn       = empty($groups[$args['id']]['g_moderator']) ? null : \ForkBB\__('Moderator info');
-        $this->tabindex   = 0;
+        $this->nameTpl = 'admin/group';
+        $this->form    = $this->viewForm($group, $marker, $vars);
 
 
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
+     * Создание новой группы
      * Запись данных по новой/измененной группе
      * Запись данных по новой/измененной группе
-     * 
+     *
      * @param array $args
      * @param array $args
-     * 
+     *
      * @return Page
      * @return Page
      */
      */
     public function editPost(array $args)
     public function editPost(array $args)
     {
     {
+        // начало создания новой группы
+        if (empty($args['id']) && empty($args['base'])) {
+            $v = $this->c->Validator->setRules([
+                'token'     => 'token:AdminGroupsNew',
+                'basegroup' => 'required|integer|in:' . implode(',', array_keys($this->groupsNew)),
+            ])->setMessages([
+                'basegroup.in' => 'Invalid group to create on base',
+            ]);
+
+            if (! $v->validation($_POST)) {
+                $this->fIswev = $v->getErrors();
+                return $this->view();
+            } else {
+                return $this->edit(['base' => $v->basegroup]);
+            }
+        }
+
+        if (isset($args['base'])) {
+            $group = $this->c->groups->get((int) $args['base']);
+        } else {
+            $group = $this->c->groups->get((int) $args['id']);
+        }
+
+        if (null === $group) {
+            return $this->c->Message->message('Bad request');
+        }
+
+        $group = clone $group;
+
         $next = $this->c->GROUP_ADMIN . ',' . $this->c->GROUP_GUEST;
         $next = $this->c->GROUP_ADMIN . ',' . $this->c->GROUP_GUEST;
-        if (isset($args['_new'])) {
-            $id = -1;
-            $marker = 'AdminGroupsNew';
-            $vars = ['base' => $args['id']];
+
+        if (isset($args['base'])) {
+            $marker      = 'AdminGroupsNew';
+            $group->g_id = null;
         } else {
         } else {
-            $id = (int) $args['id'];
             $marker = 'AdminGroupsEdit';
             $marker = 'AdminGroupsEdit';
-            $vars = ['id' => $id];
-            $next .= ',' . $id;
+            $next  .= ',' . $group->g_id;
         }
         }
+
         $reserve = [];
         $reserve = [];
-        foreach ($this->groups as $key => $cur) {
-            if ($key != $id) {
-                $reserve[] = $cur['g_title'];
+        foreach ($this->groupsList as $key => $cur) {
+            if ($group->g_id !== $key) {
+                $reserve[] = $cur[0];
             }
             }
         }
         }
 
 
-        $this->c->Lang->load('admin_groups');
-
         $v = $this->c->Validator->setRules([
         $v = $this->c->Validator->setRules([
             'token'                  => 'token:' . $marker,
             'token'                  => 'token:' . $marker,
             'g_title'                => 'required|string:trim|max:50|not_in:' . implode(',', $reserve),
             'g_title'                => 'required|string:trim|max:50|not_in:' . implode(',', $reserve),
@@ -256,6 +246,7 @@ class Groups extends Admin
             'g_edit_posts'           => 'integer|in:0,1',
             'g_edit_posts'           => 'integer|in:0,1',
             'g_delete_posts'         => 'integer|in:0,1',
             'g_delete_posts'         => 'integer|in:0,1',
             'g_delete_topics'        => 'integer|in:0,1',
             'g_delete_topics'        => 'integer|in:0,1',
+            'g_deledit_interval'     => 'integer|min:0|max:999999',
             'g_set_title'            => 'integer|in:0,1',
             'g_set_title'            => 'integer|in:0,1',
             'g_post_links'           => 'integer|in:0,1',
             'g_post_links'           => 'integer|in:0,1',
             'g_search'               => 'integer|in:0,1',
             'g_search'               => 'integer|in:0,1',
@@ -266,11 +257,14 @@ class Groups extends Admin
             'g_email_flood'          => 'integer|min:0|max:999999',
             'g_email_flood'          => 'integer|min:0|max:999999',
             'g_report_flood'         => 'integer|min:0|max:999999',
             'g_report_flood'         => 'integer|min:0|max:999999',
         ])->setArguments([
         ])->setArguments([
-            'token' => $vars,
+            'token' => $args,
+        ])->setMessages([
+            'g_title.required' => 'You must enter a group title',
+            'g_title.not_in'   => 'Title already exists',
         ]);
         ]);
 
 
         if (! $v->validation($_POST)) {
         if (! $v->validation($_POST)) {
-            $this->fIswev = $v->getErrors();
+            $this->fIswev  = $v->getErrors();
             $args['_data'] = $v->getData();
             $args['_data'] = $v->getData();
             return $this->edit($args);
             return $this->edit($args);
         }
         }
@@ -289,283 +283,374 @@ class Groups extends Admin
             $data['g_promote_min_posts']  = 0;
             $data['g_promote_min_posts']  = 0;
         }
         }
 
 
-        $fields = [];
-        $sets = [];
-        $vars = [];
-        foreach($data as $key => $value) {
-            if (substr($key, 0, 2) !== 'g_' || $value === null) {
-                continue;
-            } elseif ($key === 'g_user_title' && ! isset($value{0})) {
-                $value = null;
-            }
-            if ($id === -1) {
-                $fields[] = $key;
-                $sets[] = is_int($value) ? '?i' : '?s';
-                $vars[] = $value;
-            } else {
-                if ($id === $this->c->GROUP_ADMIN 
-                    && ! in_array($key, ['g_title', 'g_user_title'])
-                ) {
-                    continue;
-                }
-                $sets[] = $key . '=' . (is_int($value) ? '?i' : '?s');
-                $vars[] = $value;
-            } 
+        foreach ($data as $attr => $value) {
+            $group->$attr = $value;
         }
         }
-        if ($id === -1) {
-            $this->c->DB->exec('INSERT INTO ::groups (' . implode(', ', $fields) . ') VALUES(' . implode(', ', $sets) . ')', $vars);
-            $newId = $this->c->DB->lastInsertId();
 
 
-            $this->c->DB->exec('INSERT INTO ::forum_perms (group_id, forum_id, read_forum, post_replies, post_topics) SELECT ?i:new, forum_id, read_forum, post_replies, post_topics FROM ::forum_perms WHERE group_id=?i:old', [':new' => $newId, ':old' => $args['id']]);
-        } else {
-            $vars[] = $id;
-            $this->c->DB->exec('UPDATE ::groups SET ' . implode(', ', $sets) . ' WHERE g_id=?i', $vars);
+        $this->c->DB->beginTransaction();
 
 
+        if (null === $group->g_id) {
+            $message = \ForkBB\__('Group added redirect');
+            $newId   = $this->c->groups->insert($group);
+            //????
+            $this->c->DB->exec('INSERT INTO ::forum_perms (group_id, forum_id, read_forum, post_replies, post_topics) SELECT ?i:new, forum_id, read_forum, post_replies, post_topics FROM ::forum_perms WHERE group_id=?i:old', [':new' => $newId, ':old' => $args['base']]);
+
+        } else {
+            $message = \ForkBB\__('Group edited redirect');
+            $this->c->groups->update($group);
+            //????
             if ($data['g_promote_next_group']) {
             if ($data['g_promote_next_group']) {
-                $vars = [':next' => $data['g_promote_next_group'], ':id' => $id, ':posts' => $data['g_promote_min_posts']];
+                $vars = [':next' => $data['g_promote_next_group'], ':id' => $group->g_id, ':posts' => $data['g_promote_min_posts']];
                 $this->c->DB->exec('UPDATE ::users SET group_id=?i:next WHERE group_id=?i:id AND num_posts>=?i:posts', $vars);
                 $this->c->DB->exec('UPDATE ::users SET group_id=?i:next WHERE group_id=?i:id AND num_posts>=?i:posts', $vars);
             }
             }
         }
         }
 
 
+        $this->c->DB->commit();
+
         $this->c->Cache->delete('forums_mark');
         $this->c->Cache->delete('forums_mark');
 
 
-        return $this->c->Redirect
-            ->page('AdminGroups')
-            ->message($id === -1 ? \ForkBB\__('Group added redirect') : \ForkBB\__('Group edited redirect'));
+        return $this->c->Redirect->page('AdminGroups')->message($message);
     }
     }
 
 
     /**
     /**
      * Формирует данные для формы редактирования группы
      * Формирует данные для формы редактирования группы
-     * @param int $id
-     * @param array $data
+     *
+     * @param Group $group
+     * @param string $marker
+     * @param array $args
+     *
      * @return array
      * @return array
      */
      */
-    protected function viewForm($id, array $data)
+    protected function viewForm(Group $group, $marker, array $args)
     {
     {
-        $this->nameTpl = 'admin/group';
         $form = [
         $form = [
-            'g_title' => [
-                'type' => 'text',
-                'maxlength' => 50,
-                'value' => isset($data['g_title']) ? $data['g_title'] : '',
-                'title' => \ForkBB\__('Group title label'),
-                'required' => true,
+            'action' => $this->c->Router->link($marker, $args),
+            'hidden' => [
+                'token' => $this->c->Csrf->create($marker, $args),
             ],
             ],
-            'g_user_title' => [
-                'type' => 'text',
-                'maxlength' => 50,
-                'value' => isset($data['g_user_title']) ? $data['g_user_title'] : '',
-                'title' => \ForkBB\__('User title label'),
-                'info' => \ForkBB\__('User title help', $id == $this->c->GROUP_GUEST ? \ForkBB\__('Guest') : \ForkBB\__('Member')),
+            'sets'   => [],
+            'btns'   => [
+                'submit'  => [
+                    'type'      => 'submit',
+                    'value'     => \ForkBB\__('Submit'),
+                    'accesskey' => 's',
+                ],
             ],
             ],
         ];
         ];
 
 
-        if ($id === $this->c->GROUP_UNVERIFIED || $id === $this->c->GROUP_ADMIN) {
+        $fieldset = [];
+        $fieldset['g_title'] = [
+            'type'      => 'text',
+            'maxlength' => 50,
+            'value'     => $group->g_title,
+            'title'     => \ForkBB\__('Group title label'),
+            'required'  => true,
+            'autofocus' => true,
+        ];
+        $fieldset['g_user_title'] = [
+            'type'      => 'text',
+            'maxlength' => 50,
+            'value'     => $group->g_user_title,
+            'title'     => \ForkBB\__('User title label'),
+            'info'      => \ForkBB\__('User title help', $group->groupGuest ? \ForkBB\__('Guest') : \ForkBB\__('Member')),
+        ];
+
+        if ($group->g_id === $this->c->GROUP_ADMIN) {
+            $form['sets'][] = [
+                'fields' => $fieldset,
+            ];
             return $form;
             return $form;
         }
         }
 
 
-        if ($id !== $this->c->GROUP_GUEST) {
+        if (! $group->groupGuest) {
             $options = [0 => \ForkBB\__('Disable promotion')];
             $options = [0 => \ForkBB\__('Disable promotion')];
 
 
-            foreach ($this->groups as $group) {
-                if ($group['g_id'] == $id || empty($this->grBase[$group['g_id']])) {
+            foreach ($this->groupsNew as $key => $title) {
+                if ($key === $group->g_id || $key === $this->c->GROUP_GUEST) {
                     continue;
                     continue;
                 }
                 }
-                $options[$group['g_id']] = $group['g_title'];
+                $options[$key] = $title;
             }
             }
 
 
-            $form['g_promote_next_group'] = [
-                'type' => 'select',
+            $fieldset['g_promote_next_group'] = [
+                'type'    => 'select',
                 'options' => $options,
                 'options' => $options,
-                'value' => isset($data['g_promote_next_group']) ? $data['g_promote_next_group'] : 0,
-                'title' => \ForkBB\__('Promote users label'),
-                'info' => \ForkBB\__('Promote users help', \ForkBB\__('Disable promotion')),
+                'value'   => $group->g_promote_next_group,
+                'title'   => \ForkBB\__('Promote users label'),
+                'info'    => \ForkBB\__('Promote users help', \ForkBB\__('Disable promotion')),
             ];
             ];
-            $form['g_promote_min_posts'] = [
-                'type' => 'number',
-                'min' => 0,
-                'max' => 9999999999,
-                'value' => isset($data['g_promote_min_posts']) ? $data['g_promote_min_posts'] : 0,
+            $fieldset['g_promote_min_posts'] = [
+                'type'  => 'number',
+                'min'   => 0,
+                'max'   => 9999999999,
+                'value' => $group->g_promote_min_posts,
                 'title' => \ForkBB\__('Number for promotion label'),
                 'title' => \ForkBB\__('Number for promotion label'),
-                'info' => \ForkBB\__('Number for promotion help'),
+                'info'  => \ForkBB\__('Number for promotion help'),
             ];
             ];
         }
         }
 
 
         $y = \ForkBB\__('Yes');
         $y = \ForkBB\__('Yes');
         $n = \ForkBB\__('No');
         $n = \ForkBB\__('No');
-        if ($id !== $this->c->GROUP_GUEST && $id != $this->c->config->o_default_user_group) {
-            $form['g_moderator'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_moderator']) ? $data['g_moderator'] : 0,
+
+        if (! $group->groupGuest && $group->g_id != $this->c->config->o_default_user_group) {
+            $fieldset['g_moderator'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_moderator,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Mod privileges label'),
-                'info' => \ForkBB\__('Mod privileges help'),
+                'title'  => \ForkBB\__('Mod privileges label'),
+                'info'   => \ForkBB\__('Mod privileges help'),
             ];
             ];
-            $form['g_mod_edit_users'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_mod_edit_users']) ? $data['g_mod_edit_users'] : 0,
+            $fieldset['g_mod_edit_users'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_mod_edit_users,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Edit profile label'),
-                'info' => \ForkBB\__('Edit profile help'),
+                'title'  => \ForkBB\__('Edit profile label'),
+                'info'   => \ForkBB\__('Edit profile help'),
             ];
             ];
-            $form['g_mod_rename_users'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_mod_rename_users']) ? $data['g_mod_rename_users'] : 0,
+            $fieldset['g_mod_rename_users'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_mod_rename_users,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Rename users label'),
-                'info' => \ForkBB\__('Rename users help'),
+                'title'  => \ForkBB\__('Rename users label'),
+                'info'   => \ForkBB\__('Rename users help'),
             ];
             ];
-            $form['g_mod_change_passwords'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_mod_change_passwords']) ? $data['g_mod_change_passwords'] : 0,
+            $fieldset['g_mod_change_passwords'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_mod_change_passwords,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Change passwords label'),
-                'info' => \ForkBB\__('Change passwords help'),
+                'title'  => \ForkBB\__('Change passwords label'),
+                'info'   => \ForkBB\__('Change passwords help'),
             ];
             ];
-            $form['g_mod_promote_users'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_mod_promote_users']) ? $data['g_mod_promote_users'] : 0,
+            $fieldset['g_mod_promote_users'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_mod_promote_users,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Mod promote users label'),
-                'info' => \ForkBB\__('Mod promote users help'),
+                'title'  => \ForkBB\__('Mod promote users label'),
+                'info'   => \ForkBB\__('Mod promote users help'),
             ];
             ];
-            $form['g_mod_ban_users'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_mod_ban_users']) ? $data['g_mod_ban_users'] : 0,
+            $fieldset['g_mod_ban_users'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_mod_ban_users,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Ban users label'),
-                'info' => \ForkBB\__('Ban users help'),
+                'title'  => \ForkBB\__('Ban users label'),
+                'info'   => \ForkBB\__('Ban users help'),
             ];
             ];
         }
         }
 
 
-        $form['g_read_board'] = [
-            'type' => 'radio',
-            'value' => isset($data['g_read_board']) ? $data['g_read_board'] : 0,
+        $fieldset['g_read_board'] = [
+            'type'   => 'radio',
+            'value'  => $group->g_read_board,
             'values' => [1 => $y, 0 => $n],
             'values' => [1 => $y, 0 => $n],
-            'title' => \ForkBB\__('Read board label'),
-            'info' => \ForkBB\__('Read board help'),
+            'title'  => \ForkBB\__('Read board label'),
+            'info'   => \ForkBB\__('Read board help'),
         ];
         ];
-        $form['g_view_users'] = [
-            'type' => 'radio',
-            'value' => isset($data['g_view_users']) ? $data['g_view_users'] : 0,
+        $fieldset['g_view_users'] = [
+            'type'   => 'radio',
+            'value'  => $group->g_view_users,
             'values' => [1 => $y, 0 => $n],
             'values' => [1 => $y, 0 => $n],
-            'title' => \ForkBB\__('View user info label'),
-            'info' => \ForkBB\__('View user info help'),
+            'title'  => \ForkBB\__('View user info label'),
+            'info'   => \ForkBB\__('View user info help'),
         ];
         ];
-        $form['g_post_replies'] = [
-            'type' => 'radio',
-            'value' => isset($data['g_post_replies']) ? $data['g_post_replies'] : 0,
+        $fieldset['g_post_replies'] = [
+            'type'   => 'radio',
+            'value'  => $group->g_post_replies,
             'values' => [1 => $y, 0 => $n],
             'values' => [1 => $y, 0 => $n],
-            'title' => \ForkBB\__('Post replies label'),
-            'info' => \ForkBB\__('Post replies help'),
+            'title'  => \ForkBB\__('Post replies label'),
+            'info'   => \ForkBB\__('Post replies help'),
         ];
         ];
-        $form['g_post_topics'] = [
-            'type' => 'radio',
-            'value' => isset($data['g_post_topics']) ? $data['g_post_topics'] : 0,
+        $fieldset['g_post_topics'] = [
+            'type'   => 'radio',
+            'value'  => $group->g_post_topics,
             'values' => [1 => $y, 0 => $n],
             'values' => [1 => $y, 0 => $n],
-            'title' => \ForkBB\__('Post topics label'),
-            'info' => \ForkBB\__('Post topics help'),
+            'title'  => \ForkBB\__('Post topics label'),
+            'info'   => \ForkBB\__('Post topics help'),
         ];
         ];
 
 
-        if ($id !== $this->c->GROUP_GUEST) {
-            $form['g_edit_posts'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_edit_posts']) ? $data['g_edit_posts'] : 0,
+        if (! $group->groupGuest) {
+            $fieldset['g_edit_posts'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_edit_posts,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Edit posts label'),
-                'info' => \ForkBB\__('Edit posts help'),
+                'title'  => \ForkBB\__('Edit posts label'),
+                'info'   => \ForkBB\__('Edit posts help'),
             ];
             ];
-            $form['g_delete_posts'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_delete_posts']) ? $data['g_delete_posts'] : 0,
+            $fieldset['g_delete_posts'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_delete_posts,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Delete posts label'),
-                'info' => \ForkBB\__('Delete posts help'),
+                'title'  => \ForkBB\__('Delete posts label'),
+                'info'   => \ForkBB\__('Delete posts help'),
             ];
             ];
-            $form['g_delete_topics'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_delete_topics']) ? $data['g_delete_topics'] : 0,
+            $fieldset['g_delete_topics'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_delete_topics,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Delete topics label'),
-                'info' => \ForkBB\__('Delete topics help'),
+                'title'  => \ForkBB\__('Delete topics label'),
+                'info'   => \ForkBB\__('Delete topics help'),
+            ];
+            $fieldset['g_deledit_interval'] = [
+                'type'  => 'number',
+                'min'   => 0,
+                'max'   => 999999,
+                'value' => $group->g_deledit_interval,
+                'title' => \ForkBB\__('Delete-edit interval label'),
+                'info'  => \ForkBB\__('Delete-edit interval help'),
             ];
             ];
-            $form['g_set_title'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_set_title']) ? $data['g_set_title'] : 0,
+            $fieldset['g_set_title'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_set_title,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Set own title label'),
-                'info' => \ForkBB\__('Set own title help'),
+                'title'  => \ForkBB\__('Set own title label'),
+                'info'   => \ForkBB\__('Set own title help'),
             ];
             ];
         }
         }
 
 
-        $form['g_post_links'] = [
-            'type' => 'radio',
-            'value' => isset($data['g_post_links']) ? $data['g_post_links'] : 0,
+        $fieldset['g_post_links'] = [
+            'type'   => 'radio',
+            'value'  => $group->g_post_links,
             'values' => [1 => $y, 0 => $n],
             'values' => [1 => $y, 0 => $n],
-            'title' => \ForkBB\__('Post links label'),
-            'info' => \ForkBB\__('Post links help'),
+            'title'  => \ForkBB\__('Post links label'),
+            'info'   => \ForkBB\__('Post links help'),
         ];
         ];
-        $form['g_search'] = [
-            'type' => 'radio',
-            'value' => isset($data['g_search']) ? $data['g_search'] : 0,
+        $fieldset['g_search'] = [
+            'type'   => 'radio',
+            'value'  => $group->g_search,
             'values' => [1 => $y, 0 => $n],
             'values' => [1 => $y, 0 => $n],
-            'title' => \ForkBB\__('User search label'),
-            'info' => \ForkBB\__('User search help'),
+            'title'  => \ForkBB\__('User search label'),
+            'info'   => \ForkBB\__('User search help'),
         ];
         ];
-        $form['g_search_users'] = [
-            'type' => 'radio',
-            'value' => isset($data['g_search_users']) ? $data['g_search_users'] : 0,
+        $fieldset['g_search_users'] = [
+            'type'   => 'radio',
+            'value'  => $group->g_search_users,
             'values' => [1 => $y, 0 => $n],
             'values' => [1 => $y, 0 => $n],
-            'title' => \ForkBB\__('User list search label'),
-            'info' => \ForkBB\__('User list search help'),
+            'title'  => \ForkBB\__('User list search label'),
+            'info'   => \ForkBB\__('User list search help'),
         ];
         ];
 
 
-        if ($id !== $this->c->GROUP_GUEST) {
-            $form['g_send_email'] = [
-                'type' => 'radio',
-                'value' => isset($data['g_send_email']) ? $data['g_send_email'] : 0,
+        if (! $group->groupGuest) {
+            $fieldset['g_send_email'] = [
+                'type'   => 'radio',
+                'value'  => $group->g_send_email,
                 'values' => [1 => $y, 0 => $n],
                 'values' => [1 => $y, 0 => $n],
-                'title' => \ForkBB\__('Send e-mails label'),
-                'info' => \ForkBB\__('Send e-mails help'),
+                'title'  => \ForkBB\__('Send e-mails label'),
+                'info'   => \ForkBB\__('Send e-mails help'),
             ];
             ];
         }
         }
 
 
-        $form['g_post_flood'] = [
-            'type' => 'number',
-            'min' => 0,
-            'max' => 999999,
-            'value' => isset($data['g_post_flood']) ? $data['g_post_flood'] : 0,
+        $fieldset['g_post_flood'] = [
+            'type'  => 'number',
+            'min'   => 0,
+            'max'   => 999999,
+            'value' => $group->g_post_flood,
             'title' => \ForkBB\__('Post flood label'),
             'title' => \ForkBB\__('Post flood label'),
-            'info' => \ForkBB\__('Post flood help'),
+            'info'  => \ForkBB\__('Post flood help'),
         ];
         ];
-        $form['g_search_flood'] = [
-            'type' => 'number',
-            'min' => 0,
-            'max' => 999999,
-            'value' => isset($data['g_search_flood']) ? $data['g_search_flood'] : 0,
+        $fieldset['g_search_flood'] = [
+            'type'  => 'number',
+            'min'   => 0,
+            'max'   => 999999,
+            'value' => $group->g_search_flood,
             'title' => \ForkBB\__('Search flood label'),
             'title' => \ForkBB\__('Search flood label'),
-            'info' => \ForkBB\__('Search flood help'),
+            'info'  => \ForkBB\__('Search flood help'),
         ];
         ];
 
 
-        if ($id !== $this->c->GROUP_GUEST) {
-            $form['g_email_flood'] = [
-                'type' => 'number',
-                'min' => 0,
-                'max' => 999999,
-                'value' => isset($data['g_email_flood']) ? $data['g_email_flood'] : 0,
+        if (! $group->groupGuest) {
+            $fieldset['g_email_flood'] = [
+                'type'  => 'number',
+                'min'   => 0,
+                'max'   => 999999,
+                'value' => $group->g_email_flood,
                 'title' => \ForkBB\__('E-mail flood label'),
                 'title' => \ForkBB\__('E-mail flood label'),
-                'info' => \ForkBB\__('E-mail flood help'),
+                'info'  => \ForkBB\__('E-mail flood help'),
             ];
             ];
-            $form['g_report_flood'] = [
-                'type' => 'number',
-                'min' => 0,
-                'max' => 999999,
-                'value' => isset($data['g_report_flood']) ? $data['g_report_flood'] : 0,
+            $fieldset['g_report_flood'] = [
+                'type'  => 'number',
+                'min'   => 0,
+                'max'   => 999999,
+                'value' => $group->g_report_flood,
                 'title' => \ForkBB\__('Report flood label'),
                 'title' => \ForkBB\__('Report flood label'),
-                'info' => \ForkBB\__('Report flood help'),
+                'info'  => \ForkBB\__('Report flood help'),
+            ];
+        }
+
+        $form['sets'][] = [
+            'fields' => $fieldset,
+        ];
+
+        if (! empty($group->g_moderator)) {
+            $form['sets'][] = [
+                'info' => [
+                    'info1' => [
+                        'type'  => '', //????
+                        'value' => \ForkBB\__('Moderator info'),
+                    ],
+                ],
             ];
             ];
         }
         }
 
 
         return $form;
         return $form;
     }
     }
+
+    /**
+     * Подготавливает данные для шаблона
+     *
+     * @param array $args
+     * 
+     * @return Page
+     */
+    public function delete(array $args)
+    {
+        $group = $this->c->groups->get((int) $args['id']);
+
+        if (null === $group || ! $group->canDelete) {
+            return $this->c->Message->message('Bad request');
+        }
+
+        $form = [
+            'action' => $this->c->Router->link('AdminGroupsDelete', $args),
+            'hidden' => [
+                'token' => $this->c->Csrf->create('AdminGroupsDelete', $args),
+            ],
+            'sets'   => [],
+            'btns'   => [
+                'delete'  => [
+                    'type'      => 'submit',
+                    'value'     => \ForkBB\__('Delete group'),
+                    'accesskey' => 'd',
+                ],
+            ],
+        ];
+
+        $form['sets'][] = [
+            'info' => [
+                'info1' => [
+                    'type'  => '', //????
+                    'value' => \ForkBB\__('Confirm delete warn'),
+                ],
+#                'info2' => [
+#                    'type'  => '', //????
+#                    'value' => \ForkBB\__('Confirm delete info', $group->g_title),
+#                    'html'  => true,
+#                ],
+            ],
+        ];
+        $form['sets'][] = [
+            'fields' => [
+                'confirm' => [
+#                    'dl'      => 'full',
+                    'title'   => \ForkBB\__('Confirm delete'),
+                    'type'    => 'checkbox',
+                    'label'   => \ForkBB\__('I want to delete this group', $group->g_title),
+                    'value'   => '1',
+                    'checked' => false,
+                ],
+            ],
+        ];
+
+        $this->nameTpl = 'admin/group_delete';
+        $this->titles  = \ForkBB\__('Group delete');
+        $this->form    = $form;
+
+        return $this;
+    }
 }
 }

+ 3 - 3
app/Models/Pages/Auth.php

@@ -193,7 +193,7 @@ class Auth extends Page
             'token' => 'token:Forget',
             'token' => 'token:Forget',
             'email' => 'required|string:trim,lower|email|check_email',
             'email' => 'required|string:trim,lower|email|check_email',
         ])->setMessages([
         ])->setMessages([
-            'email.email' => \ForkBB\__('Invalid email'),
+            'email.email' => 'Invalid email',
         ]);
         ]);
 
 
         if (! $v->validation($_POST)) {
         if (! $v->validation($_POST)) {
@@ -342,8 +342,8 @@ class Auth extends Page
         ])->setArguments([
         ])->setArguments([
             'token' => $args,
             'token' => $args,
         ])->setMessages([
         ])->setMessages([
-            'password.password'  => \ForkBB\__('Pass format'),
-            'password2.same' => \ForkBB\__('Pass not match'),
+            'password.password'  => 'Pass format',
+            'password2.same'     => 'Pass not match',
         ]);
         ]);
 
 
         if (! $v->validation($_POST)) {
         if (! $v->validation($_POST)) {

+ 10 - 10
app/Models/Pages/Delete.php

@@ -10,9 +10,9 @@ class Delete extends Page
 
 
     /**
     /**
      * Подготовка данных для шаблона удаления сообщения/темы
      * Подготовка данных для шаблона удаления сообщения/темы
-     * 
+     *
      * @param array $args
      * @param array $args
-     * 
+     *
      * @return Page
      * @return Page
      */
      */
     public function delete(array $args)
     public function delete(array $args)
@@ -27,7 +27,7 @@ class Delete extends Page
         $deleteTopic = $post->id === $topic->first_post_id;
         $deleteTopic = $post->id === $topic->first_post_id;
 
 
         $this->c->Lang->load('delete');
         $this->c->Lang->load('delete');
-        
+
         $this->nameTpl    = 'post';
         $this->nameTpl    = 'post';
         $this->onlinePos  = 'topic-' . $topic->id;
         $this->onlinePos  = 'topic-' . $topic->id;
         $this->canonical  = $post->linkDelete;
         $this->canonical  = $post->linkDelete;
@@ -68,25 +68,25 @@ class Delete extends Page
             ],
             ],
             'btns'   => [
             'btns'   => [
                 'delete'  => [
                 'delete'  => [
-                    'type'      => 'submit', 
-                    'value'     => \ForkBB\__($deleteTopic ? 'Delete  topic' : 'Delete  post'), 
+                    'type'      => 'submit',
+                    'value'     => \ForkBB\__($deleteTopic ? 'Delete  topic' : 'Delete  post'),
                     'accesskey' => 'd',
                     'accesskey' => 'd',
                 ],
                 ],
                 'cancel'  => [
                 'cancel'  => [
-                    'type'      => 'submit', 
-                    'value'     => \ForkBB\__('Cancel'), 
+                    'type'      => 'submit',
+                    'value'     => \ForkBB\__('Cancel'),
                 ],
                 ],
             ],
             ],
         ];
         ];
-                
+
         return $this;
         return $this;
     }
     }
 
 
     /**
     /**
      * Обработка данных от формы удаления сообщения/темы
      * Обработка данных от формы удаления сообщения/темы
-     * 
+     *
      * @param array $args
      * @param array $args
-     * 
+     *
      * @return Page
      * @return Page
      */
      */
     public function deletePost(array $args)
     public function deletePost(array $args)

+ 1 - 1
app/Models/Pages/Install.php

@@ -709,7 +709,7 @@ class Install extends Page
         $schema = [
         $schema = [
             'FIELDS' => [
             'FIELDS' => [
                 'id'               => ['SERIAL', false],
                 'id'               => ['SERIAL', false],
-                'group_id'         => ['INT(10) UNSIGNED', false, $this->c->GROUP_UNVERIFIED],
+                'group_id'         => ['INT(10) UNSIGNED', false, 0],
                 'username'         => ['VARCHAR(200)', false, ''],
                 'username'         => ['VARCHAR(200)', false, ''],
                 'password'         => ['VARCHAR(255)', false, ''],
                 'password'         => ['VARCHAR(255)', false, ''],
                 'email'            => ['VARCHAR(80)', false, ''],
                 'email'            => ['VARCHAR(80)', false, ''],

+ 3 - 3
app/Models/Pages/Register.php

@@ -31,8 +31,8 @@ class Register extends Page
         ])->setMessages([
         ])->setMessages([
             'agree.required'    => ['cancel', 'cancel'],
             'agree.required'    => ['cancel', 'cancel'],
             'agree.token'       => [\ForkBB\__('Bad agree', $this->c->Router->link('Register')), 'w'],
             'agree.token'       => [\ForkBB\__('Bad agree', $this->c->Router->link('Register')), 'w'],
-            'password.password' => \ForkBB\__('Pass format'),
-            'username.login'    => \ForkBB\__('Login format'),
+            'password.password' => 'Pass format',
+            'username.login'    => 'Login format',
         ]);
         ]);
 
 
         // завершение регистрации
         // завершение регистрации
@@ -124,7 +124,7 @@ class Register extends Page
     protected function regEnd(Validator $v)
     protected function regEnd(Validator $v)
     {
     {
         if ($this->c->config->o_regs_verify == '1') {
         if ($this->c->config->o_regs_verify == '1') {
-            $groupId = $this->c->GROUP_UNVERIFIED;
+            $groupId = 0;
             $key = 'w' . $this->c->Secury->randomPass(79);
             $key = 'w' . $this->c->Secury->randomPass(79);
         } else {
         } else {
             $groupId = $this->c->config->o_default_user_group;
             $groupId = $this->c->config->o_default_user_group;

+ 0 - 1
app/Models/Post/Model.php

@@ -44,7 +44,6 @@ class Model extends DataModel
         $user = $this->c->users->get($this->poster_id);
         $user = $this->c->users->get($this->poster_id);
 
 
         if (! $user instanceof User) {
         if (! $user instanceof User) {
-            var_dump($this->poster_id);
             $attrs = $this->a; //????
             $attrs = $this->a; //????
             $attrs['id'] = $attrs['poster_id'];
             $attrs['id'] = $attrs['poster_id'];
 
 

+ 7 - 8
app/Models/Post/Save.php

@@ -57,20 +57,19 @@ class Save extends Action
      */
      */
     public function insert(Post $post)
     public function insert(Post $post)
     {
     {
-        $modified = $post->getModified();
-        if (null !== $post->id || in_array('id', $modified)) {
+        if (null !== $post->id) {
             throw new RuntimeException('The model has ID');
             throw new RuntimeException('The model has ID');
         }
         }
-        $values = $post->getAttrs();
+        $attrs  = $post->getAttrs();
         $fileds = $this->c->dbMap->posts;
         $fileds = $this->c->dbMap->posts;
         $set = $set2 = $vars = [];
         $set = $set2 = $vars = [];
-        foreach ($modified as $name) {
-            if (! isset($fileds[$name])) {
+        foreach ($attrs as $key => $value) {
+            if (! isset($fileds[$key])) {
                 continue;
                 continue;
             }
             }
-            $vars[] = $values[$name];
-            $set[] = $name;
-            $set2[] = '?' . $fileds[$name];
+            $vars[] = $value;
+            $set[]  = $key;
+            $set2[] = '?' . $fileds[$key];
         }
         }
         if (empty($set)) {
         if (empty($set)) {
             throw new RuntimeException('The model is empty');
             throw new RuntimeException('The model is empty');

+ 2 - 2
app/Models/Stats/Load.php

@@ -14,8 +14,8 @@ class Load extends Method
      */
      */
     public function load()
     public function load()
     {
     {
-        $total = $this->c->DB->query('SELECT COUNT(id)-1 FROM ::users WHERE group_id!=?i', [$this->c->GROUP_UNVERIFIED])->fetchColumn();
-        $last  = $this->c->DB->query('SELECT id, username FROM ::users WHERE group_id!=?i ORDER BY registered DESC LIMIT 1', [$this->c->GROUP_UNVERIFIED])->fetch();
+        $total = $this->c->DB->query('SELECT COUNT(id)-1 FROM ::users WHERE group_id!=0')->fetchColumn();
+        $last  = $this->c->DB->query('SELECT id, username FROM ::users WHERE group_id!=0 ORDER BY registered DESC LIMIT 1')->fetch();
         $this->model->userTotal = $total;
         $this->model->userTotal = $total;
         $this->model->userLast  = $last;
         $this->model->userLast  = $last;
         $this->c->Cache->set('stats', [
         $this->c->Cache->set('stats', [

+ 7 - 8
app/Models/Topic/Save.php

@@ -57,20 +57,19 @@ class Save extends Action
      */
      */
     public function insert(Topic $topic)
     public function insert(Topic $topic)
     {
     {
-        $modified = $topic->getModified();
-        if (null !== $topic->id || in_array('id', $modified)) {
+        if (null !== $topic->id) {
             throw new RuntimeException('The model has ID');
             throw new RuntimeException('The model has ID');
         }
         }
-        $values = $topic->getAttrs();
+        $attrs  = $topic->getAttrs();
         $fileds = $this->c->dbMap->topics;
         $fileds = $this->c->dbMap->topics;
         $set = $set2 = $vars = [];
         $set = $set2 = $vars = [];
-        foreach ($modified as $name) {
-            if (! isset($fileds[$name])) {
+        foreach ($attrs as $key => $value) {
+            if (! isset($fileds[$key])) {
                 continue;
                 continue;
             }
             }
-            $vars[] = $values[$name];
-            $set[] = $name;
-            $set2[] = '?' . $fileds[$name];
+            $vars[] = $value;
+            $set[]  = $key;
+            $set2[] = '?' . $fileds[$key];
         }
         }
         if (empty($set)) {
         if (empty($set)) {
             throw new RuntimeException('The model is empty');
             throw new RuntimeException('The model is empty');

+ 2 - 2
app/Models/User/Manager.php

@@ -70,8 +70,8 @@ class Manager extends ManagerModel
      */
      */
     public function insert(User $user)
     public function insert(User $user)
     {
     {
-        $id = $this->Save->insert($topic);
-        $this->set($id, $topic);
+        $id = $this->Save->insert($user);
+        $this->set($id, $user);
         return $id;
         return $id;
     }
     }
 }
 }

+ 2 - 2
app/Models/User/Model.php

@@ -16,7 +16,7 @@ class Model extends DataModel
      */
      */
     protected function getisUnverified()
     protected function getisUnverified()
     {
     {
-        return $this->group_id == $this->c->GROUP_UNVERIFIED;
+        return empty($this->group_id);
     }
     }
 
 
     /**
     /**
@@ -28,7 +28,7 @@ class Model extends DataModel
     {
     {
         return $this->group_id == $this->c->GROUP_GUEST
         return $this->group_id == $this->c->GROUP_GUEST
             || $this->id < 2
             || $this->id < 2
-            || $this->group_id == $this->c->GROUP_UNVERIFIED;
+            || empty($this->group_id);
     }
     }
 
 
     /**
     /**

+ 7 - 8
app/Models/User/Save.php

@@ -70,20 +70,19 @@ class Save extends Action
      */
      */
     public function insert(User $user)
     public function insert(User $user)
     {
     {
-        $modified = $user->getModified();
-        if (null !== $user->id || in_array('id', $modified)) {
+        if (null !== $user->id) {
             throw new RuntimeException('The model has ID');
             throw new RuntimeException('The model has ID');
         }
         }
-        $values = $user->getAttrs();
+        $attrs  = $user->getAttrs();
         $fileds = $this->c->dbMap->users;
         $fileds = $this->c->dbMap->users;
         $set = $set2 = $vars = [];
         $set = $set2 = $vars = [];
-        foreach ($modified as $name) {
-            if (! isset($fileds[$name])) {
+        foreach ($attrs as $key => $value) {
+            if (! isset($fileds[$key])) {
                 continue;
                 continue;
             }
             }
-            $vars[] = $values[$name];
-            $set[] = $name;
-            $set2[] = '?' . $fileds[$name];
+            $vars[] = $value;
+            $set[]  = $key;
+            $set2[] = '?' . $fileds[$key];
         }
         }
         if (empty($set)) {
         if (empty($set)) {
             throw new RuntimeException('The model is empty');
             throw new RuntimeException('The model is empty');

+ 0 - 1
app/config/install.php

@@ -3,7 +3,6 @@
 return [
 return [
     'BASE_URL'    => 'http://forkbb.local',
     'BASE_URL'    => 'http://forkbb.local',
     'DEBUG' => 1,
     'DEBUG' => 1,
-    'GROUP_UNVERIFIED' => 0,
     'GROUP_ADMIN'      => 1,
     'GROUP_ADMIN'      => 1,
     'GROUP_MOD'        => 2,
     'GROUP_MOD'        => 2,
     'GROUP_GUEST'      => 3,
     'GROUP_GUEST'      => 3,

+ 0 - 1
app/config/main.dist.php

@@ -25,7 +25,6 @@ return [
     'JQUERY_LINK' => '//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js',
     'JQUERY_LINK' => '//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js',
     'DEBUG' => 1,
     'DEBUG' => 1,
     'MAINTENANCE_OFF' => false,
     'MAINTENANCE_OFF' => false,
-    'GROUP_UNVERIFIED' => 0,
     'GROUP_ADMIN' => 1,
     'GROUP_ADMIN' => 1,
     'GROUP_MOD' => 2,
     'GROUP_MOD' => 2,
     'GROUP_GUEST' => 3,
     'GROUP_GUEST' => 3,

+ 26 - 8
app/lang/English/admin_groups.po

@@ -12,11 +12,11 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Language: en\n"
 "Language: en\n"
 
 
-msgid "Must enter title message"
+msgid "You must enter a group title"
 msgstr "You must enter a group title."
 msgstr "You must enter a group title."
 
 
-msgid "Title already exists message"
-msgstr "There is already a group with the title <strong>%s</strong>."
+msgid "Title already exists"
+msgstr "There is already a group with this title."
 
 
 msgid "Default group redirect"
 msgid "Default group redirect"
 msgstr "Default group set. Redirecting …"
 msgstr "Default group set. Redirecting …"
@@ -69,14 +69,14 @@ msgstr "Edit"
 msgid "Delete link"
 msgid "Delete link"
 msgstr "Delete"
 msgstr "Delete"
 
 
-msgid "Group delete head"
+msgid "Group delete"
 msgstr "Group delete"
 msgstr "Group delete"
 
 
-msgid "Confirm delete subhead"
-msgstr "Confirm delete group"
+msgid "I want to delete this group"
+msgstr "Yes, I want to delete the group <b>%s</b>"
 
 
-msgid "Confirm delete info"
-msgstr "Are you sure that you want to delete the group <strong>%s</strong>?"
+msgid "Confirm delete"
+msgstr "Delete group?"
 
 
 msgid "Confirm delete warn"
 msgid "Confirm delete warn"
 msgstr "WARNING! After you deleted a group you cannot restore it."
 msgstr "WARNING! After you deleted a group you cannot restore it."
@@ -263,3 +263,21 @@ msgstr "Number of seconds that users in this group have to wait between reports.
 
 
 msgid "Moderator info"
 msgid "Moderator info"
 msgstr "Please note that in order for a user in this group to have moderator abilities, he/she must be assigned to moderate one or more forums. This is done via the user administration page of the user's profile."
 msgstr "Please note that in order for a user in this group to have moderator abilities, he/she must be assigned to moderate one or more forums. This is done via the user administration page of the user's profile."
+
+msgid "Delete-edit interval label"
+msgstr "Interval for editing/deleting"
+
+msgid "Delete-edit interval help"
+msgstr "Number of seconds to edit (delete) your messages or topics. Set to 0 to disable.<br>Moderators have no restrictions in the zone of responsibility."
+
+msgid "Create new group"
+msgstr "Create new group"
+
+msgid "Edit group"
+msgstr "Edit group"
+
+msgid "Invalid default group"
+msgstr "Invalid default group."
+
+msgid "Invalid group to create on base"
+msgstr "Invalid group to create on base."

+ 26 - 8
app/lang/Russian/admin_groups.po

@@ -12,11 +12,11 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Language: ru\n"
 "Language: ru\n"
 
 
-msgid "Must enter title message"
+msgid "You must enter a group title"
 msgstr "Необходимо ввести заголовок группы."
 msgstr "Необходимо ввести заголовок группы."
 
 
-msgid "Title already exists message"
-msgstr "Уже есть группа с заголовком <strong>%s</strong>."
+msgid "Title already exists"
+msgstr "Уже есть группа с таким заголовком."
 
 
 msgid "Default group redirect"
 msgid "Default group redirect"
 msgstr "Установлена группа по умолчанию. Переадресация …"
 msgstr "Установлена группа по умолчанию. Переадресация …"
@@ -69,14 +69,14 @@ msgstr "Править"
 msgid "Delete link"
 msgid "Delete link"
 msgstr "Удалить"
 msgstr "Удалить"
 
 
-msgid "Group delete head"
+msgid "Group delete"
 msgstr "Удаление группы"
 msgstr "Удаление группы"
 
 
-msgid "Confirm delete subhead"
-msgstr "Подтверждение удаления"
+msgid "I want to delete this group"
+msgstr "Да, я хочу удалить группу <b>%s</b>"
 
 
-msgid "Confirm delete info"
-msgstr "Вы действительно хотите удалить группу <strong>%s</strong>?"
+msgid "Confirm delete"
+msgstr "Удалить группу?"
 
 
 msgid "Confirm delete warn"
 msgid "Confirm delete warn"
 msgstr "ВНИМАНИЕ! Удалённую группу невозможно восстановить."
 msgstr "ВНИМАНИЕ! Удалённую группу невозможно восстановить."
@@ -263,3 +263,21 @@ msgstr "Количество секунд, которые необходимо 
 
 
 msgid "Moderator info"
 msgid "Moderator info"
 msgstr "Пожалуйста, обратите внимание, что пока пользователь не назначен модератором конкретного раздела, он не сможет реализовать свои модераторские права. Назначение производится в разделе "Модерация" пользовательского профиля."
 msgstr "Пожалуйста, обратите внимание, что пока пользователь не назначен модератором конкретного раздела, он не сможет реализовать свои модераторские права. Назначение производится в разделе "Модерация" пользовательского профиля."
+
+msgid "Delete-edit interval label"
+msgstr "Интервал для редактирования/удаления"
+
+msgid "Delete-edit interval help"
+msgstr "Количество секунд для редактирования (удаления) своих сообщений или тем. Поставьте 0 чтобы выключить ограничение.<br>Модераторы не имеют ограничений в зоне своей модерации."
+
+msgid "Create new group"
+msgstr "Создание новой группы"
+
+msgid "Edit group"
+msgstr "Редактирование группы"
+
+msgid "Invalid default group"
+msgstr "Недопустимая группа по умолчанию."
+
+msgid "Invalid group to create on base"
+msgstr "Недопустимая группа для создания на основании."

+ 3 - 34
app/templates/admin/group.tpl

@@ -1,40 +1,9 @@
 @extends ('layouts/admin')
 @extends ('layouts/admin')
       <section class="f-admin">
       <section class="f-admin">
-        <h2>{!! __('Group settings head') !!}</h2>
+        <h2>{!! $p->titleForm !!}</h2>
         <div class="f-fdiv">
         <div class="f-fdiv">
-          <form class="f-form" method="post" action="{!! $p->formAction !!}">
-            <input type="hidden" name="token" value="{!! $p->formToken !!}">
-            <dl>
-@foreach ($p->form as $key => $cur)
-              <dt>{!! $cur['title'] !!}</dt>
-              <dd>
-  @if ($cur['type'] == 'text')
-                <input class="f-ctrl" @if (isset($cur['required'])) required @endif type="text" name="{{ $key }}" maxlength="{!! $cur['maxlength'] !!}" value="{{ $cur['value'] }}" tabindex="{!! ++$p->tabindex !!}">
-  @elseif ($cur['type'] == 'number')
-                <input class="f-ctrl" type="number" name="{{ $key }}" min="{!! $cur['min'] !!}" max="{!! $cur['max'] !!}" value="{{ $cur['value'] }}" tabindex="{!! ++$p->tabindex !!}">
-  @elseif ($cur['type'] == 'select')
-                <select class="f-ctrl" name="{{ $key }}" tabindex="{!! ++$p->tabindex !!}">
-    @foreach ($cur['options'] as $v => $n)
-                  <option value="{{ $v }}" @if ($v == $cur['value']) selected @endif>{{ $n }}</option>
-    @endforeach
-                </select>
-  @elseif ($cur['type'] == 'radio')
-    @foreach ($cur['values'] as $v => $n)
-                <label class="f-label"><input type="radio" name="{{ $key }}" value="{{ $v }}" @if ($v == $cur['value']) checked @endif tabindex="{!! ++$p->tabindex !!}">{{ $n }}</label>
-    @endforeach
-  @endif
-  @if (isset($cur['info']))
-                <span class="f-child4">{!! $cur['info'] !!}</span>
-  @endif
-              </dd>
-@endforeach
-            </dl>
-@if ($p->warn)
-            <p class="f-finfo">{!! $p->warn !!}</p>
+@if ($form = $p->form)
+  @include ('layouts/form')
 @endif
 @endif
-            <div>
-              <input class="f-btn" type="submit" name="submit" value="{!! __('Save') !!}" tabindex="{!! ++$p->tabindex !!}">
-            </div>
-          </form>
         </div>
         </div>
       </section>
       </section>

+ 9 - 0
app/templates/admin/group_delete.tpl

@@ -0,0 +1,9 @@
+@extends ('layouts/admin')
+      <section class="f-admin">
+        <h2>{!! __('Group delete') !!}</h2>
+        <div class="f-fdiv">
+@if ($form = $p->form)
+  @include ('layouts/form')
+@endif
+        </div>
+      </section>

+ 8 - 36
app/templates/admin/groups.tpl

@@ -2,45 +2,17 @@
       <section class="f-admin">
       <section class="f-admin">
         <h2>{!! __('Add group subhead') !!}</h2>
         <h2>{!! __('Add group subhead') !!}</h2>
         <div class="f-fdiv">
         <div class="f-fdiv">
-          <form class="f-form" method="post" action="{!! $p->formActionNew !!}">
-            <input type="hidden" name="token" value="{!! $p->formTokenNew !!}">
-            <dl>
-              <dt>{!! __('New group label') !!}</dt>
-              <dd>
-                <select class="f-ctrl" id="id-basegroup" name="basegroup" tabindex="{!! ++$p->tabindex !!}">
-@foreach ($p->groupsNew as $cur)
-                  <option value="{!! $cur[0] !!}" @if ($cur[0] == $p->defaultGroup) selected @endif>{{ $cur[1] }}</option>
-@endforeach
-                </select>
-                <span class="f-child4">{!! __('New group help') !!}</span>
-              </dd>
-            </dl>
-            <div>
-              <input class="f-btn" type="submit" name="submit" value="{!! __('Add') !!}" tabindex="{!! ++$p->tabindex !!}">
-            </div>
-          </form>
+@if ($form = $p->formNew)
+  @include ('layouts/form')
+@endif
         </div>
         </div>
       </section>
       </section>
       <section class="f-admin">
       <section class="f-admin">
         <h2>{!! __('Default group subhead') !!}</h2>
         <h2>{!! __('Default group subhead') !!}</h2>
         <div class="f-fdiv">
         <div class="f-fdiv">
-          <form class="f-form" method="post" action="{!! $p->formActionDefault !!}">
-            <input type="hidden" name="token" value="{!! $p->formTokenDefault !!}">
-            <dl>
-              <dt>{!! __('Default group label') !!}</dt>
-              <dd>
-                <select class="f-ctrl" id="id-defaultgroup" name="defaultgroup" tabindex="{!! ++$p->tabindex !!}">
-@foreach ($p->groupsDefault as $cur)
-                  <option value="{!! $cur[0] !!}" @if ($cur[0] == $p->defaultGroup) selected @endif>{{ $cur[1] }}</option>
-@endforeach
-                </select>
-                <span class="f-child4">{!! __('Default group help') !!}</span>
-              </dd>
-            </dl>
-            <div>
-              <input class="f-btn" type="submit" name="submit" value="{!! __('Save') !!}" tabindex="{!! ++$p->tabindex !!}">
-            </div>
-          </form>
+@if ($form = $p->formDefault)
+  @include ('layouts/form')
+@endif
         </div>
         </div>
       </section>
       </section>
       <section class="f-admin">
       <section class="f-admin">
@@ -50,9 +22,9 @@
           <ol class="f-grlist">
           <ol class="f-grlist">
 @foreach ($p->groupsList as $cur)
 @foreach ($p->groupsList as $cur)
             <li>
             <li>
-              <a href="{!! $cur[0] !!}" tabindex="{!! ++$p->tabindex !!}">{{ $cur[1] }}</a>
+              <a href="{!! $cur[1] !!}">{{ $cur[0] }}</a>
   @if ($cur[2])
   @if ($cur[2])
-              <a class="f-btn" href="{!! $cur[2] !!}" tabindex="{!! ++$p->tabindex !!}">{!! __('Delete link') !!}</a>
+              <a class="f-btn" href="{!! $cur[2] !!}">{!! __('Delete link') !!}</a>
   @endif
   @endif
             </li>
             </li>
 @endforeach
 @endforeach

+ 15 - 9
app/templates/admin/index.tpl

@@ -16,14 +16,20 @@
           </ul>
           </ul>
         </div>
         </div>
         <h2>{!! __('About head') !!}</h2>
         <h2>{!! __('About head') !!}</h2>
-        <div>
-          <dl>
-            <dt>{!! __('ForkBB version label') !!}</dt>
-            <dd>{!! __('ForkBB version data', $p->revision) !!}</dd>
-            <dt>{!! __('Server statistics label') !!}</dt>
-            <dd><a href="{!! $p->linkStat !!}">{!! __('View server statistics') !!}</a></dd>
-            <dt>{!! __('Support label') !!}</dt>
-            <dd><a href="https://github.com/forkbb/forkbb">GitHub</a></dd>
-          </dl>
+        <div class="f-fdiv">
+          <fieldset>
+            <dl>
+              <dt>{!! __('ForkBB version label') !!}</dt>
+              <dd>{!! __('ForkBB version data', $p->revision) !!}</dd>
+            </dl>
+            <dl>
+              <dt>{!! __('Server statistics label') !!}</dt>
+              <dd><a href="{!! $p->linkStat !!}">{!! __('View server statistics') !!}</a></dd>
+            </dl>
+            <dl>
+              <dt>{!! __('Support label') !!}</dt>
+              <dd><a href="https://github.com/forkbb/forkbb">GitHub</a></dd>
+            </dl>
+          </fieldset>
         </div>
         </div>
       </section>
       </section>

+ 26 - 20
app/templates/admin/statistics.tpl

@@ -1,36 +1,42 @@
 @extends ('layouts/admin')
 @extends ('layouts/admin')
       <section class="f-admin">
       <section class="f-admin">
         <h2>{!! __('Server statistics head') !!}</h2>
         <h2>{!! __('Server statistics head') !!}</h2>
-        <div>
-          <dl>
-            <dt>{!! __('Server load label') !!}</dt>
-            <dd>{!! __('Server load data', $p->serverLoad, $p->numOnline) !!}</dd>
+        <div class="f-fdiv">
+          <fieldset>
+            <dl>
+              <dt>{!! __('Server load label') !!}</dt>
+              <dd>{!! __('Server load data', $p->serverLoad, $p->numOnline) !!}</dd>
+            </dl>
 @if ($p->isAdmin)
 @if ($p->isAdmin)
-            <dt>{!! __('Environment label') !!}</dt>
-            <dd>
-              {!! __('Environment data OS', PHP_OS) !!}<br>
-              {!! __('Environment data version', PHP_VERSION) !!} - <a href="{!! $p->linkInfo !!}">{!! __('Show info') !!}</a><br>
+            <dl>
+              <dt>{!! __('Environment label') !!}</dt>
+              <dd>
+                {!! __('Environment data OS', PHP_OS) !!}<br>
+                {!! __('Environment data version', PHP_VERSION) !!} - <a href="{!! $p->linkInfo !!}">{!! __('Show info') !!}</a><br>
   @if ($p->linkAcc)
   @if ($p->linkAcc)
-              {!! __('Environment data acc') !!} <a href="{!! $p->linkAcc !!}">{{ $p->accelerator }}</a>
+                {!! __('Environment data acc') !!} <a href="{!! $p->linkAcc !!}">{{ $p->accelerator }}</a>
   @else
   @else
-              {!! __('Environment data acc') !!} {{ $p->accelerator }}
+                {!! __('Environment data acc') !!} {{ $p->accelerator }}
   @endif
   @endif
-            </dd>
-            <dt>{!! __('Database label') !!}</dt>
-            <dd>
-              {{ $p->dbVersion }}
+              </dd>
+            </dl>
+            <dl>
+              <dt>{!! __('Database label') !!}</dt>
+              <dd>
+                {{ $p->dbVersion }}
   @if ($p->tRecords && $p->tSize)
   @if ($p->tRecords && $p->tSize)
-              <br>{!! __('Database data rows', num($p->tRecords)) !!}
-              <br>{!! __('Database data size', size($p->tSize)) !!}
+                <br>{!! __('Database data rows', num($p->tRecords)) !!}
+                <br>{!! __('Database data size', size($p->tSize)) !!}
   @endif
   @endif
   @if ($p->tOther)
   @if ($p->tOther)
-              <br><br>{!! __('Other')!!}
+                <br><br>{!! __('Other')!!}
     @foreach ($p->tOther as $key => $value)
     @foreach ($p->tOther as $key => $value)
-              <br>{{ $key }} = {{ $value }}
+                <br>{{ $key }} = {{ $value }}
     @endforeach
     @endforeach
   @endif
   @endif
-            </dd>
+              </dd>
 @endif
 @endif
-          </dl>
+            </dl>
+          </fieldset>
         </div>
         </div>
       </section>
       </section>

+ 1 - 1
app/templates/change_passphrase.tpl

@@ -19,7 +19,7 @@
               </dd>
               </dd>
             </dl>
             </dl>
           </fieldset>
           </fieldset>
-          <p>
+          <p class="f-btns">
             <input class="f-btn" type="submit" name="login" value="{!! __('Change passphrase') !!}" tabindex="3">
             <input class="f-btn" type="submit" name="login" value="{!! __('Change passphrase') !!}" tabindex="3">
           </p>
           </p>
         </form>
         </form>

+ 16 - 4
app/templates/layouts/form.tpl

@@ -22,7 +22,7 @@
             <dl @if (isset($cur['dl'])) class="f-field-{{ $cur['dl'] }}" @endif>
             <dl @if (isset($cur['dl'])) class="f-field-{{ $cur['dl'] }}" @endif>
               <dt> @if (isset($cur['title']))<label class="f-child1 @if (isset($cur['required'])) f-req @endif" for="id-{{ $key }}">{!! $cur['title'] !!}</label> @endif</dt>
               <dt> @if (isset($cur['title']))<label class="f-child1 @if (isset($cur['required'])) f-req @endif" for="id-{{ $key }}">{!! $cur['title'] !!}</label> @endif</dt>
               <dd>
               <dd>
-      @if ($cur['type'] === 'textarea')
+      @if ('textarea' === $cur['type'])
                 <textarea @if (isset($cur['required'])) required @endif @if (isset($cur['autofocus'])) autofocus @endif class="f-ctrl" id="id-{{ $key }}" name="{{ $key }}">{{ $cur['value'] or '' }}</textarea>
                 <textarea @if (isset($cur['required'])) required @endif @if (isset($cur['autofocus'])) autofocus @endif class="f-ctrl" id="id-{{ $key }}" name="{{ $key }}">{{ $cur['value'] or '' }}</textarea>
         @if (isset($cur['bb']))
         @if (isset($cur['bb']))
                 <ul class="f-child5">
                 <ul class="f-child5">
@@ -31,10 +31,22 @@
           @endforeach
           @endforeach
                 </ul>
                 </ul>
         @endif
         @endif
-      @elseif ($cur['type'] === 'text')
+      @elseif ('select' === $cur['type'])
+                <select @if (isset($cur['required'])) required @endif @if (isset($cur['autofocus'])) autofocus @endif class="f-ctrl" id="id-{{ $key }}" name="{{ $key }}">
+        @foreach ($cur['options'] as $v => $n)
+                  <option value="{{ $v }}" @if ($v == $cur['value']) selected @endif>{{ $n }}</option>
+        @endforeach
+                </select>
+      @elseif ('text' === $cur['type'])
                 <input @if (isset($cur['required'])) required @endif @if (isset($cur['autofocus'])) autofocus @endif class="f-ctrl" id="id-{{ $key }}" name="{{ $key }}" type="text" @if (! empty($cur['maxlength'])) maxlength="{{ $cur['maxlength'] }}" @endif @if (isset($cur['pattern'])) pattern="{{ $cur['pattern'] }}" @endif @if (isset($cur['value'])) value="{{ $cur['value'] }}" @endif>
                 <input @if (isset($cur['required'])) required @endif @if (isset($cur['autofocus'])) autofocus @endif class="f-ctrl" id="id-{{ $key }}" name="{{ $key }}" type="text" @if (! empty($cur['maxlength'])) maxlength="{{ $cur['maxlength'] }}" @endif @if (isset($cur['pattern'])) pattern="{{ $cur['pattern'] }}" @endif @if (isset($cur['value'])) value="{{ $cur['value'] }}" @endif>
-      @elseif ($cur['type'] === 'checkbox')
+      @elseif ('number' === $cur['type'])
+                <input @if (isset($cur['required'])) required @endif @if (isset($cur['autofocus'])) autofocus @endif class="f-ctrl" id="id-{{ $key }}" name="{{ $key }}" type="number" min="{{ $cur['min'] }}" max="{{ $cur['max'] }}" @if (isset($cur['value'])) value="{{ $cur['value'] }}" @endif>
+      @elseif ('checkbox' === $cur['type'])
                 <label class="f-child2"><input @if (isset($cur['autofocus'])) autofocus @endif type="checkbox" id="id-{{ $key }}" name="{{ $key }}" value="{{ $cur['value'] or '1' }}" @if (! empty($cur['checked'])) checked @endif>{!! $cur['label'] !!}</label>
                 <label class="f-child2"><input @if (isset($cur['autofocus'])) autofocus @endif type="checkbox" id="id-{{ $key }}" name="{{ $key }}" value="{{ $cur['value'] or '1' }}" @if (! empty($cur['checked'])) checked @endif>{!! $cur['label'] !!}</label>
+      @elseif ('radio' === $cur['type'])
+        @foreach ($cur['values'] as $v => $n)
+                <label class="f-label"><input @if (isset($cur['autofocus'])) autofocus @endif type="radio" id="id-{{ $key }}-{{ $v }}" name="{{ $key }}" value="{{ $v }}" @if ($v == $cur['value']) checked @endif>{{ $n }}</label>
+        @endforeach
       @endif
       @endif
       @if (isset($cur['info']))
       @if (isset($cur['info']))
                 <p class="f-child4">{!! $cur['info'] !!}</p>
                 <p class="f-child4">{!! $cur['info'] !!}</p>
@@ -45,7 +57,7 @@
           </fieldset>
           </fieldset>
   @endif
   @endif
 @endforeach
 @endforeach
-          <p>
+          <p class="f-btns">
 @foreach ($form['btns'] as $key => $cur)
 @foreach ($form['btns'] as $key => $cur)
             <input class="f-btn @if(isset($cur['class'])) {{ $cur['class'] }} @endif" type="{{ $cur['type'] }}" name="{{ $key }}" value="{{ $cur['value'] }}" @if (isset($cur['accesskey'])) accesskey="{{ $cur['accesskey'] }}" @endif>
             <input class="f-btn @if(isset($cur['class'])) {{ $cur['class'] }} @endif" type="{{ $cur['type'] }}" name="{{ $key }}" value="{{ $cur['value'] }}" @if (isset($cur['accesskey'])) accesskey="{{ $cur['accesskey'] }}" @endif>
 @endforeach
 @endforeach

+ 1 - 1
app/templates/login.tpl

@@ -27,7 +27,7 @@
 @endif
 @endif
             </dl>
             </dl>
           </fieldset>
           </fieldset>
-          <p>
+          <p class="f-btns">
             <input class="f-btn" type="submit" name="login" value="{!! __('Sign in') !!}" tabindex="4">
             <input class="f-btn" type="submit" name="login" value="{!! __('Sign in') !!}" tabindex="4">
           </p>
           </p>
         </form>
         </form>

+ 1 - 1
app/templates/passphrase_reset.tpl

@@ -13,7 +13,7 @@
               </dd>
               </dd>
             </dl>
             </dl>
           </fieldset>
           </fieldset>
-          <p>
+          <p class="f-btns">
             <input class="f-btn" type="submit" name="submit" value="{!! __('Send email') !!}" tabindex="2">
             <input class="f-btn" type="submit" name="submit" value="{!! __('Send email') !!}" tabindex="2">
           </p>
           </p>
         </form>
         </form>

+ 1 - 1
app/templates/register.tpl

@@ -29,7 +29,7 @@
               </dd>
               </dd>
             </dl>
             </dl>
           </fieldset>
           </fieldset>
-          <p>
+          <p class="f-btns">
             <input class="f-btn" type="submit" name="register" value="{!! __('Sign up') !!}" tabindex="4">
             <input class="f-btn" type="submit" name="register" value="{!! __('Sign up') !!}" tabindex="4">
           </p>
           </p>
         </form>
         </form>

+ 1 - 1
app/templates/rules.tpl

@@ -12,7 +12,7 @@
               <dd><label class="f-child2"><input type="checkbox" name="agree" value="{!! $p->formHash !!}" tabindex="1">{!! __('Agree') !!}</label></dd>
               <dd><label class="f-child2"><input type="checkbox" name="agree" value="{!! $p->formHash !!}" tabindex="1">{!! __('Agree') !!}</label></dd>
             </dl>
             </dl>
           </fieldset>
           </fieldset>
-          <p>
+          <p class="f-btns">
             <input class="f-btn" type="submit" name="register" value="{!! __('Register') !!}" tabindex="2">
             <input class="f-btn" type="submit" name="register" value="{!! __('Register') !!}" tabindex="2">
           </p>
           </p>
         </form>
         </form>

+ 93 - 27
public/style/ForkBB/style.css

@@ -94,10 +94,35 @@ html {
 }
 }
 
 
 h1, h2, h3 {
 h1, h2, h3 {
-  font-family: "Segoe Print", "Flow Ext";
   font-weight: bold;
   font-weight: bold;
 }
 }
 
 
+h2 {
+  font-size: 1.25rem;
+}
+
+h3 {
+  font-size: 1rem;
+}
+
+.f-header h1, 
+.f-category h2, 
+.f-category h3 {
+  font-family: "Segoe Print", "Flow Ext";
+}
+
+.f-header h1 {
+  font-size: 2rem;
+}
+
+.f-category h2 {
+  font-size: 1.5rem
+}
+
+.f-category h3 {
+  font-size: 1.25rem;
+}
+
 .f-wrap {
 .f-wrap {
   padding: 0 0.3125rem;
   padding: 0 0.3125rem;
   max-width: 64rem;
   max-width: 64rem;
@@ -392,27 +417,31 @@ select {
 }
 }
 
 
 .f-fdiv h2,
 .f-fdiv h2,
-.f-fdiv .f-form {
-  padding: 0.625rem;
+.f-fdiv fieldset {
+  padding: 0.625rem 0.625rem 0 0.625rem;
 }
 }
 
 
 .f-fdiv h3 {
 .f-fdiv h3 {
   padding: 0.625rem 0.625rem 0 0.625rem;
   padding: 0.625rem 0.625rem 0 0.625rem;
 }
 }
 
 
+.f-fdiv dl {
+  padding: 0 0 0.625rem 0;
+}
+
 .f-fdiv .f-ctrl,
 .f-fdiv .f-ctrl,
 .f-fdiv .f-btn {
 .f-fdiv .f-btn {
   padding: 0.5rem;
   padding: 0.5rem;
   font-size: 1rem;
   font-size: 1rem;
   display: block;
   display: block;
   width: 100%;
   width: 100%;
-  margin-bottom: 1rem;
+/*  margin-bottom: 1rem; */
   box-sizing: border-box;
   box-sizing: border-box;
 }
 }
 
 
 .f-fdiv .f-label {
 .f-fdiv .f-label {
   font-size: 1rem;
   font-size: 1rem;
-  margin-bottom: 1rem;
+/*  margin-bottom: 1rem; */
   display: inline-block;
   display: inline-block;
 }
 }
 
 
@@ -447,8 +476,12 @@ select {
   margin: 0 0.625rem 0 0;
   margin: 0 0.625rem 0 0;
 }
 }
 
 
+.f-fdiv .f-btns {
+  padding: 0 0.625rem;
+}
+
 .f-fdiv .f-btn {
 .f-fdiv .f-btn {
-  margin: 1rem 0 0.375rem 0;
+  margin: 0.625rem 0;
 }
 }
 
 
 .f-fdiv .f-child3 {
 .f-fdiv .f-child3 {
@@ -459,27 +492,30 @@ select {
 
 
 .f-fdiv .f-child4 {
 .f-fdiv .f-child4 {
   font-size: 0.8125rem;
   font-size: 0.8125rem;
+  margin-top: 0.3125rem;
   text-align: justify;
   text-align: justify;
 }
 }
 
 
 .f-fdiv .f-child5 {
 .f-fdiv .f-child5 {
-  margin-top: -0.375rem;
-  margin-bottom: 1rem
+/*  margin-top: -0.375rem; */
+/*  margin-bottom: 1rem */
+  padding-top: 0.3125rem;
 }
 }
 
 
 .f-fdiv .f-finfo {
 .f-fdiv .f-finfo {
-  margin: -0.625rem -0.625rem 1rem -0.625rem;
+/*  margin: -0.625rem -0.625rem 1rem -0.625rem; */
   background-color: #AA7939;
   background-color: #AA7939;
   padding: 0.625rem;
   padding: 0.625rem;
   color: #F8F4E3;
   color: #F8F4E3;
+  margin-bottom: 0.625rem;
 }
 }
 
 
-.f-finfo + .f-finfo {
-  margin-top: -1rem;
+.f-fdiv .f-finfo + .f-finfo {
+  margin-top: -0.625rem;
 }
 }
 
 
-fieldset + .f-finfo {
-  margin-top: 1rem;
+.f-fdiv fieldset + .f-finfo {
+/*  margin-top: 0.625rem; */
 }
 }
 
 
 .f-ctrl {
 .f-ctrl {
@@ -487,7 +523,7 @@ fieldset + .f-finfo {
 }
 }
 
 
 .f-ctrl:focus {
 .f-ctrl:focus {
-  box-shadow: inset 0px 0px 0.25rem 0 rgba(170,121,57,0.5), 0px 0px 0.25rem 0 rgba(170,121,57,0.5);
+  box-shadow: inset 0 0 0.5rem 0 rgba(170,121,57,0.75), 0 0 0.5rem 0 rgba(170,121,57,0.75); 
 }
 }
 
 
 .f-ctrl + .f-fhint {
 .f-ctrl + .f-fhint {
@@ -501,9 +537,10 @@ fieldset + .f-finfo {
 
 
 .f-ctrl:focus + .f-fhint,
 .f-ctrl:focus + .f-fhint,
 .f-ctrl:active + .f-fhint {
 .f-ctrl:active + .f-fhint {
-  margin-top: -0.375rem;
-  margin-bottom: 1rem;
-  max-height: 1000rem;
+/*  margin-top: 0.3125rem; */
+/*  margin-bottom: -0.625rem; */
+  
+  max-height: 10rem;
 }
 }
 
 
 /**************/
 /**************/
@@ -750,7 +787,7 @@ fieldset + .f-finfo {
   text-align: center;
   text-align: center;
   border: 0;
   border: 0;
   white-space: nowrap;
   white-space: nowrap;
-  font-size: 1.125rem;
+/*  font-size: 1.125rem; */
   text-transform: uppercase;
   text-transform: uppercase;
 }
 }
 
 
@@ -821,20 +858,36 @@ fieldset + .f-finfo {
 }
 }
 
 
 .f-admin dl {
 .f-admin dl {
-  margin: 0 0.625rem 0.625rem 0.625rem;
+/*  margin: 0 0.625rem 0.625rem 0.625rem; */
+  border-bottom: 0.0625rem dotted #AA7939;
+  margin-bottom: 0.625rem;
+}
+
+.f-admin dl:before,
+.f-admin dl:after {
+  content: " ";
+  display: table;
+}
+
+.f-admin dl:after {
+  clear: both;
 }
 }
 
 
 .f-admin dt {
 .f-admin dt {
-  padding-top: 0.625rem;
+/*  padding-top: 0.625rem; */
 }
 }
 
 
 .f-admin dd {
 .f-admin dd {
-  padding: 0.625rem 0;
-  border-bottom: 0.0625rem dotted #AA7939;
+/*  padding: 0.625rem 0; */
+/*  border-bottom: 0.0625rem dotted #AA7939; */
 }
 }
 
 
 .f-admin .f-fdiv dl {
 .f-admin .f-fdiv dl {
-  margin: 0;
+/*  margin: 0; */
+}
+
+.f-admin .f-fdiv .f-child2 {
+  font-size: 1rem;
 }
 }
 
 
 .f-grlist {
 .f-grlist {
@@ -861,9 +914,22 @@ fieldset + .f-finfo {
     float: left;
     float: left;
     width: 14rem;
     width: 14rem;
   }
   }
+
   .f-admin dd {
   .f-admin dd {
     padding-left: 14.625rem;
     padding-left: 14.625rem;
   }
   }
+
+  .f-admin .f-fdiv .f-child1 {
+    font-weight: normal;
+  }
+
+  .f-field-full dt {
+    display: none;
+  }
+
+  .f-field-full dd {
+    padding-left: 0;
+  }
 }
 }
 
 
 /*********************/
 /*********************/
@@ -1139,7 +1205,7 @@ fieldset + .f-finfo {
 }
 }
 
 
 .f-forum h3 {
 .f-forum h3 {
-  font-family: Arial, Helvetica, sans-serif;
+/*  font-family: Arial, Helvetica, sans-serif;  */
   font-weight: normal;
   font-weight: normal;
   font-size: 1rem;
   font-size: 1rem;
   position: relative;
   position: relative;
@@ -1395,7 +1461,7 @@ li + li .f-btn {
 }
 }
 
 
 .f-preview > h2 {
 .f-preview > h2 {
-  font-family: Arial, Helvetica, sans-serif;
+/**  font-family: Arial, Helvetica, sans-serif; */
   font-size: 1rem;
   font-size: 1rem;
   line-height: 1.5;
   line-height: 1.5;
   padding: 1rem 0.625rem 0.3125rem 0.625rem
   padding: 1rem 0.625rem 0.3125rem 0.625rem
@@ -1424,7 +1490,7 @@ li + li .f-btn {
 
 
 .f-post-form > h2,
 .f-post-form > h2,
 .f-view-posts > h2 {
 .f-view-posts > h2 {
-  font-family: Arial, Helvetica, sans-serif;
+/**  font-family: Arial, Helvetica, sans-serif; */
   font-size: 1rem;
   font-size: 1rem;
   padding-right: 0.625rem;
   padding-right: 0.625rem;
   padding: 1rem 0.625rem 0.3125rem 0.625rem
   padding: 1rem 0.625rem 0.3125rem 0.625rem
@@ -1437,7 +1503,7 @@ li + li .f-btn {
 
 
 .f-post-form legend {
 .f-post-form legend {
   width: 100%;
   width: 100%;
-  padding-bottom: 0.625rem;
+  padding: 0.625rem 0 0.3125rem 0;
   margin-bottom: 0.625rem;
   margin-bottom: 0.625rem;
   border-bottom: 0.0625rem dotted #AA7939;
   border-bottom: 0.0625rem dotted #AA7939;
   font-weight: bold;
   font-weight: bold;