mirror of
https://git.beihong.wang/wangbeihong/blog-source.git
synced 2026-04-23 14:13:04 +08:00
initial
This commit is contained in:
120
var/Widget/Users/Admin.php
Executable file
120
var/Widget/Users/Admin.php
Executable file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Widget\Users;
|
||||
|
||||
use Typecho\Common;
|
||||
use Typecho\Db;
|
||||
use Typecho\Db\Query;
|
||||
use Typecho\Widget\Exception;
|
||||
use Typecho\Widget\Helper\PageNavigator\Box;
|
||||
use Widget\Base\Users;
|
||||
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台成员列表组件
|
||||
*
|
||||
* @author qining
|
||||
* @category typecho
|
||||
* @package Widget
|
||||
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
|
||||
* @license GNU General Public License 2.0
|
||||
*/
|
||||
class Admin extends Users
|
||||
{
|
||||
/**
|
||||
* 分页计算对象
|
||||
*
|
||||
* @var Query
|
||||
*/
|
||||
private Query $countSql;
|
||||
|
||||
/**
|
||||
* 所有文章个数
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private int $total;
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private int $currentPage;
|
||||
|
||||
/**
|
||||
* 执行函数
|
||||
*
|
||||
* @throws Db\Exception
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$this->parameter->setDefault('pageSize=20');
|
||||
$select = $this->select();
|
||||
$this->currentPage = $this->request->filter('int')->get('page', 1);
|
||||
|
||||
/** 过滤标题 */
|
||||
if (null != ($keywords = $this->request->get('keywords'))) {
|
||||
$select->where(
|
||||
'name LIKE ? OR screenName LIKE ?',
|
||||
'%' . Common::filterSearchQuery($keywords) . '%',
|
||||
'%' . Common::filterSearchQuery($keywords) . '%'
|
||||
);
|
||||
}
|
||||
|
||||
$this->countSql = clone $select;
|
||||
|
||||
$select->order('table.users.uid')
|
||||
->page($this->currentPage, $this->parameter->pageSize);
|
||||
|
||||
$this->db->fetchAll($select, [$this, 'push']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出分页
|
||||
*
|
||||
* @throws Exception|Db\Exception
|
||||
*/
|
||||
public function pageNav()
|
||||
{
|
||||
$query = $this->request->makeUriByRequest('page={page}');
|
||||
|
||||
/** 使用盒状分页 */
|
||||
$nav = new Box(
|
||||
!isset($this->total) ? $this->total = $this->size($this->countSql) : $this->total,
|
||||
$this->currentPage,
|
||||
$this->parameter->pageSize,
|
||||
$query
|
||||
);
|
||||
$nav->render('«', '»');
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅仅输出域名和路径
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function ___domainPath(): string
|
||||
{
|
||||
$parts = parse_url($this->url);
|
||||
return $parts['host'] . ($parts['path'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布文章数
|
||||
*
|
||||
* @return integer
|
||||
* @throws Db\Exception
|
||||
*/
|
||||
protected function ___postsNum(): int
|
||||
{
|
||||
return $this->db->fetchObject($this->db->select(['COUNT(cid)' => 'num'])
|
||||
->from('table.contents')
|
||||
->where('table.contents.type = ?', 'post')
|
||||
->where('table.contents.status = ?', 'publish')
|
||||
->where('table.contents.authorId = ?', $this->uid))->num;
|
||||
}
|
||||
}
|
||||
35
var/Widget/Users/Author.php
Executable file
35
var/Widget/Users/Author.php
Executable file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Widget\Users;
|
||||
|
||||
use Typecho\Db\Exception;
|
||||
use Widget\Base\Users;
|
||||
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 相关内容组件(根据标签关联)
|
||||
*
|
||||
* @author qining
|
||||
* @category typecho
|
||||
* @package Widget
|
||||
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
|
||||
* @license GNU General Public License 2.0
|
||||
*/
|
||||
class Author extends Users
|
||||
{
|
||||
/**
|
||||
* 执行函数,初始化数据
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
if (isset($this->parameter->uid)) {
|
||||
$this->db->fetchRow($this->select()
|
||||
->where('uid = ?', $this->parameter->uid), [$this, 'push']);
|
||||
}
|
||||
}
|
||||
}
|
||||
320
var/Widget/Users/Edit.php
Executable file
320
var/Widget/Users/Edit.php
Executable file
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
namespace Widget\Users;
|
||||
|
||||
use Typecho\Common;
|
||||
use Typecho\Widget\Exception;
|
||||
use Typecho\Widget\Helper\Form;
|
||||
use Utils\PasswordHash;
|
||||
use Widget\ActionInterface;
|
||||
use Widget\Base\Users;
|
||||
use Widget\Notice;
|
||||
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑用户组件
|
||||
*
|
||||
* @link typecho
|
||||
* @package Widget
|
||||
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
|
||||
* @license GNU General Public License 2.0
|
||||
*/
|
||||
class Edit extends Users implements ActionInterface
|
||||
{
|
||||
use EditTrait;
|
||||
|
||||
/**
|
||||
* 执行函数
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception|\Typecho\Db\Exception
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
/** 管理员以上权限 */
|
||||
$this->user->pass('administrator');
|
||||
|
||||
/** 更新模式 */
|
||||
if (($this->request->is('uid') && 'delete' != $this->request->get('do')) || $this->request->is('do=update')) {
|
||||
$this->db->fetchRow($this->select()
|
||||
->where('uid = ?', $this->request->get('uid'))->limit(1), [$this, 'push']);
|
||||
|
||||
if (!$this->have()) {
|
||||
throw new Exception(_t('用户不存在'), 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单标题
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMenuTitle(): string
|
||||
{
|
||||
return _t('编辑用户 %s', $this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否存在
|
||||
*
|
||||
* @param integer $uid 用户主键
|
||||
* @return boolean
|
||||
* @throws \Typecho\Db\Exception
|
||||
*/
|
||||
public function userExists(int $uid): bool
|
||||
{
|
||||
$user = $this->db->fetchRow($this->db->select()
|
||||
->from('table.users')
|
||||
->where('uid = ?', $uid)->limit(1));
|
||||
|
||||
return !empty($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加用户
|
||||
*
|
||||
* @throws \Typecho\Db\Exception
|
||||
*/
|
||||
public function insertUser()
|
||||
{
|
||||
if ($this->form('insert')->validate()) {
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
$hasher = new PasswordHash(8, true);
|
||||
|
||||
/** 取出数据 */
|
||||
$user = $this->request->from('name', 'mail', 'screenName', 'password', 'url', 'group');
|
||||
$user['screenName'] = empty($user['screenName']) ? $user['name'] : $user['screenName'];
|
||||
$user['password'] = $hasher->hashPassword($user['password']);
|
||||
$user['created'] = $this->options->time;
|
||||
|
||||
/** 插入数据 */
|
||||
$user['uid'] = $this->insert($user);
|
||||
|
||||
/** 设置高亮 */
|
||||
Notice::alloc()->highlight('user-' . $user['uid']);
|
||||
|
||||
/** 提示信息 */
|
||||
Notice::alloc()->set(_t('用户 %s 已经被增加', $user['screenName']), 'success');
|
||||
|
||||
/** 转向原页 */
|
||||
$this->response->redirect(Common::url('manage-users.php', $this->options->adminUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成表单
|
||||
*
|
||||
* @access public
|
||||
* @param string|null $action 表单动作
|
||||
* @return Form
|
||||
*/
|
||||
public function form(?string $action = null): Form
|
||||
{
|
||||
/** 构建表格 */
|
||||
$form = new Form($this->security->getIndex('/action/users-edit'), Form::POST_METHOD);
|
||||
|
||||
/** 用户名称 */
|
||||
$name = new Form\Element\Text('name', null, null, _t('用户名') . ' *', _t('此用户名将作为用户登录时所用的名称.')
|
||||
. '<br />' . _t('请不要与系统中现有的用户名重复.'));
|
||||
$form->addInput($name);
|
||||
|
||||
/** 电子邮箱地址 */
|
||||
$mail = new Form\Element\Text('mail', null, null, _t('邮件地址') . ' *', _t('电子邮箱地址将作为此用户的主要联系方式.')
|
||||
. '<br />' . _t('请不要与系统中现有的电子邮箱地址重复.'));
|
||||
$form->addInput($mail);
|
||||
|
||||
/** 用户昵称 */
|
||||
$screenName = new Form\Element\Text('screenName', null, null, _t('用户昵称'), _t('用户昵称可以与用户名不同, 用于前台显示.')
|
||||
. '<br />' . _t('如果你将此项留空, 将默认使用用户名.'));
|
||||
$form->addInput($screenName);
|
||||
|
||||
/** 用户密码 */
|
||||
$password = new Form\Element\Password('password', null, null, _t('用户密码'), _t('为此用户分配一个密码.')
|
||||
. '<br />' . _t('建议使用特殊字符与字母、数字的混编样式,以增加系统安全性.'));
|
||||
$password->input->setAttribute('class', 'w-60');
|
||||
$form->addInput($password);
|
||||
|
||||
/** 用户密码确认 */
|
||||
$confirm = new Form\Element\Password('confirm', null, null, _t('用户密码确认'), _t('请确认你的密码, 与上面输入的密码保持一致.'));
|
||||
$confirm->input->setAttribute('class', 'w-60');
|
||||
$form->addInput($confirm);
|
||||
|
||||
/** 个人主页地址 */
|
||||
$url = new Form\Element\Text('url', null, null, _t('个人主页地址'), _t('此用户的个人主页地址, 请用 <code>https://</code> 开头.'));
|
||||
$form->addInput($url);
|
||||
|
||||
/** 用户组 */
|
||||
$group = new Form\Element\Select(
|
||||
'group',
|
||||
[
|
||||
'subscriber' => _t('关注者'),
|
||||
'contributor' => _t('贡献者'), 'editor' => _t('编辑'), 'administrator' => _t('管理员')
|
||||
],
|
||||
null,
|
||||
_t('用户组'),
|
||||
_t('不同的用户组拥有不同的权限.') . '<br />' . _t('具体的权限分配表请<a href="https://docs.typecho.org/develop/acl">参考这里</a>.')
|
||||
);
|
||||
$form->addInput($group);
|
||||
|
||||
/** 用户动作 */
|
||||
$do = new Form\Element\Hidden('do');
|
||||
$form->addInput($do);
|
||||
|
||||
/** 用户主键 */
|
||||
$uid = new Form\Element\Hidden('uid');
|
||||
$form->addInput($uid);
|
||||
|
||||
/** 提交按钮 */
|
||||
$submit = new Form\Element\Submit();
|
||||
$submit->input->setAttribute('class', 'btn primary');
|
||||
$form->addItem($submit);
|
||||
|
||||
if ($this->request->is('uid')) {
|
||||
$submit->value(_t('编辑用户'));
|
||||
$name->value($this->name);
|
||||
$screenName->value($this->screenName);
|
||||
$url->value($this->url);
|
||||
$mail->value($this->mail);
|
||||
$group->value($this->group);
|
||||
$do->value('update');
|
||||
$uid->value($this->uid);
|
||||
$_action = 'update';
|
||||
} else {
|
||||
$submit->value(_t('增加用户'));
|
||||
$do->value('insert');
|
||||
$_action = 'insert';
|
||||
}
|
||||
|
||||
if (empty($action)) {
|
||||
$action = $_action;
|
||||
}
|
||||
|
||||
/** 给表单增加规则 */
|
||||
if ('insert' == $action || 'update' == $action) {
|
||||
$screenName->addRule([$this, 'screenNameExists'], _t('昵称已经存在'));
|
||||
$screenName->addRule('xssCheck', _t('请不要在昵称中使用特殊字符'));
|
||||
$url->addRule('url', _t('个人主页地址格式错误'));
|
||||
$mail->addRule('required', _t('必须填写电子邮箱'));
|
||||
$mail->addRule([$this, 'mailExists'], _t('电子邮箱地址已经存在'));
|
||||
$mail->addRule('email', _t('电子邮箱格式错误'));
|
||||
$password->addRule('minLength', _t('为了保证账户安全, 请输入至少六位的密码'), 6);
|
||||
$confirm->addRule('confirm', _t('两次输入的密码不一致'), 'password');
|
||||
}
|
||||
|
||||
if ('insert' == $action) {
|
||||
$name->addRule('required', _t('必须填写用户名称'));
|
||||
$name->addRule('xssCheck', _t('请不要在用户名中使用特殊字符'));
|
||||
$name->addRule([$this, 'nameExists'], _t('用户名已经存在'));
|
||||
$password->label(_t('用户密码') . ' *');
|
||||
$confirm->label(_t('用户密码确认') . ' *');
|
||||
$password->addRule('required', _t('必须填写密码'));
|
||||
}
|
||||
|
||||
if ('update' == $action) {
|
||||
$name->input->setAttribute('disabled', 'disabled');
|
||||
$uid->addRule('required', _t('用户主键不存在'));
|
||||
$uid->addRule([$this, 'userExists'], _t('用户不存在'));
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*
|
||||
* @throws \Typecho\Db\Exception
|
||||
*/
|
||||
public function updateUser()
|
||||
{
|
||||
if ($this->form('update')->validate()) {
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
/** 取出数据 */
|
||||
$user = $this->request->from('mail', 'screenName', 'password', 'url', 'group');
|
||||
$user['screenName'] = empty($user['screenName']) ? $user['name'] : $user['screenName'];
|
||||
if (empty($user['password'])) {
|
||||
unset($user['password']);
|
||||
} else {
|
||||
$hasher = new PasswordHash(8, true);
|
||||
$user['password'] = $hasher->hashPassword($user['password']);
|
||||
}
|
||||
|
||||
/** 更新数据 */
|
||||
$this->update($user, $this->db->sql()->where('uid = ?', $this->request->get('uid')));
|
||||
|
||||
/** 设置高亮 */
|
||||
Notice::alloc()->highlight('user-' . $this->request->get('uid'));
|
||||
|
||||
/** 提示信息 */
|
||||
Notice::alloc()->set(_t('用户 %s 已经被更新', $user['screenName']), 'success');
|
||||
|
||||
/** 转向原页 */
|
||||
$this->response->redirect(Common::url('manage-users.php?' .
|
||||
$this->getPageOffsetQuery($this->request->get('uid')), $this->options->adminUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页面偏移的URL Query
|
||||
*
|
||||
* @param integer $uid 用户id
|
||||
* @return string
|
||||
* @throws \Typecho\Db\Exception
|
||||
*/
|
||||
protected function getPageOffsetQuery(int $uid): string
|
||||
{
|
||||
return 'page=' . $this->getPageOffset('uid', $uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*
|
||||
* @throws \Typecho\Db\Exception
|
||||
*/
|
||||
public function deleteUser()
|
||||
{
|
||||
$users = $this->request->filter('int')->getArray('uid');
|
||||
$masterUserId = $this->db->fetchObject($this->db->select(['MIN(uid)' => 'num'])->from('table.users'))->num;
|
||||
$deleteCount = 0;
|
||||
|
||||
foreach ($users as $user) {
|
||||
if ($masterUserId == $user || $user == $this->user->uid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->delete($this->db->sql()->where('uid = ?', $user))) {
|
||||
$deleteCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/** 提示信息 */
|
||||
Notice::alloc()->set(
|
||||
$deleteCount > 0 ? _t('用户已经删除') : _t('没有用户被删除'),
|
||||
$deleteCount > 0 ? 'success' : 'notice'
|
||||
);
|
||||
|
||||
/** 转向原页 */
|
||||
$this->response->redirect(Common::url('manage-users.php', $this->options->adminUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* 入口函数
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function action()
|
||||
{
|
||||
$this->user->pass('administrator');
|
||||
$this->security->protect();
|
||||
$this->on($this->request->is('do=insert'))->insertUser();
|
||||
$this->on($this->request->is('do=update'))->updateUser();
|
||||
$this->on($this->request->is('do=delete'))->deleteUser();
|
||||
$this->response->redirect($this->options->adminUrl);
|
||||
}
|
||||
}
|
||||
100
var/Widget/Users/EditTrait.php
Executable file
100
var/Widget/Users/EditTrait.php
Executable file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Widget\Users;
|
||||
|
||||
use Typecho\Db\Exception;
|
||||
|
||||
/**
|
||||
* 编辑用户组件
|
||||
*/
|
||||
trait EditTrait
|
||||
{
|
||||
/**
|
||||
* 判断用户名称是否存在
|
||||
*
|
||||
* @param string $name 用户名称
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
public function nameExists(string $name): bool
|
||||
{
|
||||
$select = $this->db->select()
|
||||
->from('table.users')
|
||||
->where('name = ?', $name)
|
||||
->limit(1);
|
||||
|
||||
if ($this->request->is('uid')) {
|
||||
$select->where('uid <> ?', $this->request->get('uid'));
|
||||
}
|
||||
|
||||
$user = $this->db->fetchRow($select);
|
||||
return !$user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断电子邮件是否存在
|
||||
*
|
||||
* @param string $mail 电子邮件
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
public function mailExists(string $mail): bool
|
||||
{
|
||||
$select = $this->db->select()
|
||||
->from('table.users')
|
||||
->where('mail = ?', $mail)
|
||||
->limit(1);
|
||||
|
||||
if ($this->request->is('uid')) {
|
||||
$select->where('uid <> ?', $this->request->get('uid'));
|
||||
}
|
||||
|
||||
$user = $this->db->fetchRow($select);
|
||||
return !$user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户昵称是否存在
|
||||
*
|
||||
* @param string $screenName 昵称
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
public function screenNameExists(string $screenName): bool
|
||||
{
|
||||
$select = $this->db->select()
|
||||
->from('table.users')
|
||||
->where('screenName = ?', $screenName)
|
||||
->limit(1);
|
||||
|
||||
if ($this->request->is('uid')) {
|
||||
$select->where('uid <> ?', $this->request->get('uid'));
|
||||
}
|
||||
|
||||
$user = $this->db->fetchRow($select);
|
||||
return !$user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页面偏移
|
||||
*
|
||||
* @param string $column 字段名
|
||||
* @param integer $offset 偏移值
|
||||
* @param string|null $group 用户组
|
||||
* @param integer $pageSize 分页值
|
||||
* @return integer
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getPageOffset(string $column, int $offset, ?string $group = null, int $pageSize = 20): int
|
||||
{
|
||||
$select = $this->db->select(['COUNT(uid)' => 'num'])->from('table.users')
|
||||
->where("table.users.{$column} > {$offset}");
|
||||
|
||||
if (!empty($group)) {
|
||||
$select->where('table.users.group = ?', $group);
|
||||
}
|
||||
|
||||
$count = $this->db->fetchObject($select)->num + 1;
|
||||
return ceil($count / $pageSize);
|
||||
}
|
||||
}
|
||||
460
var/Widget/Users/Profile.php
Executable file
460
var/Widget/Users/Profile.php
Executable file
@@ -0,0 +1,460 @@
|
||||
<?php
|
||||
|
||||
namespace Widget\Users;
|
||||
|
||||
use Typecho\Common;
|
||||
use Typecho\Db\Exception;
|
||||
use Typecho\Plugin;
|
||||
use Typecho\Widget\Helper\Form;
|
||||
use Utils\PasswordHash;
|
||||
use Widget\ActionInterface;
|
||||
use Widget\Base\Options;
|
||||
use Widget\Base\Users;
|
||||
use Widget\Notice;
|
||||
use Widget\Plugins\Rows;
|
||||
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑用户组件
|
||||
*
|
||||
* @link typecho
|
||||
* @package Widget
|
||||
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
|
||||
* @license GNU General Public License 2.0
|
||||
*/
|
||||
class Profile extends Users implements ActionInterface
|
||||
{
|
||||
use EditTrait;
|
||||
|
||||
/**
|
||||
* 执行函数
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
/** 注册用户以上权限 */
|
||||
$this->user->pass('subscriber');
|
||||
$this->request->setParam('uid', $this->user->uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出表单结构
|
||||
*
|
||||
* @access public
|
||||
* @return Form
|
||||
*/
|
||||
public function optionsForm(): Form
|
||||
{
|
||||
/** 构建表格 */
|
||||
$form = new Form($this->security->getIndex('/action/users-profile'), Form::POST_METHOD);
|
||||
|
||||
/** 撰写设置 */
|
||||
$markdown = new Form\Element\Radio(
|
||||
'markdown',
|
||||
['0' => _t('关闭'), '1' => _t('打开')],
|
||||
$this->options->markdown,
|
||||
_t('使用 Markdown 语法编辑和解析内容'),
|
||||
_t('使用 <a href="https://daringfireball.net/projects/markdown/">Markdown</a> 语法能够使您的撰写过程更加简便直观.')
|
||||
. '<br />' . _t('此功能开启不会影响以前没有使用 Markdown 语法编辑的内容.')
|
||||
);
|
||||
$form->addInput($markdown);
|
||||
|
||||
$xmlrpcMarkdown = new Form\Element\Radio(
|
||||
'xmlrpcMarkdown',
|
||||
['0' => _t('关闭'), '1' => _t('打开')],
|
||||
$this->options->xmlrpcMarkdown,
|
||||
_t('在 XMLRPC 接口中使用 Markdown 语法'),
|
||||
_t('对于完全支持 <a href="https://daringfireball.net/projects/markdown/">Markdown</a> 语法写作的离线编辑器, 打开此选项后将避免内容被转换为 HTML.')
|
||||
);
|
||||
$form->addInput($xmlrpcMarkdown);
|
||||
|
||||
/** 自动保存 */
|
||||
$autoSave = new Form\Element\Radio(
|
||||
'autoSave',
|
||||
['0' => _t('关闭'), '1' => _t('打开')],
|
||||
$this->options->autoSave,
|
||||
_t('自动保存'),
|
||||
_t('自动保存功能可以更好地保护你的文章不会丢失.')
|
||||
);
|
||||
$form->addInput($autoSave);
|
||||
|
||||
/** 默认允许 */
|
||||
$allow = [];
|
||||
if ($this->options->defaultAllowComment) {
|
||||
$allow[] = 'comment';
|
||||
}
|
||||
|
||||
if ($this->options->defaultAllowPing) {
|
||||
$allow[] = 'ping';
|
||||
}
|
||||
|
||||
if ($this->options->defaultAllowFeed) {
|
||||
$allow[] = 'feed';
|
||||
}
|
||||
|
||||
$defaultAllow = new Form\Element\Checkbox(
|
||||
'defaultAllow',
|
||||
['comment' => _t('可以被评论'), 'ping' => _t('可以被引用'), 'feed' => _t('出现在聚合中')],
|
||||
$allow,
|
||||
_t('默认允许'),
|
||||
_t('设置你经常使用的默认允许权限')
|
||||
);
|
||||
$form->addInput($defaultAllow);
|
||||
|
||||
/** 用户动作 */
|
||||
$do = new Form\Element\Hidden('do', null, 'options');
|
||||
$form->addInput($do);
|
||||
|
||||
/** 提交按钮 */
|
||||
$submit = new Form\Element\Submit('submit', null, _t('保存设置'));
|
||||
$submit->input->setAttribute('class', 'btn primary');
|
||||
$form->addItem($submit);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义设置列表
|
||||
*
|
||||
* @throws Plugin\Exception
|
||||
*/
|
||||
public function personalFormList()
|
||||
{
|
||||
$plugins = Rows::alloc('activated=1');
|
||||
|
||||
while ($plugins->next()) {
|
||||
if ($plugins->personalConfig) {
|
||||
[$pluginFileName, $className] = Plugin::portal($plugins->name, $this->options->pluginDir);
|
||||
|
||||
$form = $this->personalForm($plugins->name, $className, $pluginFileName, $group);
|
||||
if ($this->user->pass($group, true)) {
|
||||
echo '<br><section id="personal-' . $plugins->name . '">';
|
||||
echo '<h3>' . $plugins->title . '</h3>';
|
||||
|
||||
$form->render();
|
||||
|
||||
echo '</section>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出自定义设置选项
|
||||
*
|
||||
* @access public
|
||||
* @param string $pluginName 插件名称
|
||||
* @param string $className 类名称
|
||||
* @param string $pluginFileName 插件文件名
|
||||
* @param string|null $group 用户组
|
||||
* @throws Plugin\Exception
|
||||
*/
|
||||
public function personalForm(string $pluginName, string $className, string $pluginFileName, ?string &$group): Form
|
||||
{
|
||||
/** 构建表格 */
|
||||
$form = new Form($this->security->getIndex('/action/users-profile'), Form::POST_METHOD);
|
||||
$form->setAttribute('name', $pluginName);
|
||||
$form->setAttribute('id', $pluginName);
|
||||
|
||||
require_once $pluginFileName;
|
||||
$group = call_user_func([$className, 'personalConfig'], $form);
|
||||
$group = $group ?: 'subscriber';
|
||||
|
||||
$options = $this->options->personalPlugin($pluginName);
|
||||
|
||||
if (!empty($options)) {
|
||||
foreach ($options as $key => $val) {
|
||||
$form->getInput($key)->value($val);
|
||||
}
|
||||
}
|
||||
|
||||
$form->addItem(new Form\Element\Hidden('do', null, 'personal'));
|
||||
$form->addItem(new Form\Element\Hidden('plugin', null, $pluginName));
|
||||
$submit = new Form\Element\Submit('submit', null, _t('保存设置'));
|
||||
$submit->input->setAttribute('class', 'btn primary');
|
||||
$form->addItem($submit);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateProfile()
|
||||
{
|
||||
if ($this->profileForm()->validate()) {
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
/** 取出数据 */
|
||||
$user = $this->request->from('mail', 'screenName', 'url');
|
||||
$user['screenName'] = empty($user['screenName']) ? $user['name'] : $user['screenName'];
|
||||
|
||||
/** 更新数据 */
|
||||
$this->update($user, $this->db->sql()->where('uid = ?', $this->user->uid));
|
||||
|
||||
/** 设置高亮 */
|
||||
Notice::alloc()->highlight('user-' . $this->user->uid);
|
||||
|
||||
/** 提示信息 */
|
||||
Notice::alloc()->set(_t('您的档案已经更新'), 'success');
|
||||
|
||||
/** 转向原页 */
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成表单
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
public function profileForm(): Form
|
||||
{
|
||||
/** 构建表格 */
|
||||
$form = new Form($this->security->getIndex('/action/users-profile'), Form::POST_METHOD);
|
||||
|
||||
/** 用户昵称 */
|
||||
$screenName = new Form\Element\Text('screenName', null, null, _t('昵称'), _t('用户昵称可以与用户名不同, 用于前台显示.')
|
||||
. '<br />' . _t('如果你将此项留空, 将默认使用用户名.'));
|
||||
$form->addInput($screenName);
|
||||
|
||||
/** 个人主页地址 */
|
||||
$url = new Form\Element\Url('url', null, null, _t('个人主页地址'), _t('此用户的个人主页地址, 请用 <code>https://</code> 开头.'));
|
||||
$form->addInput($url);
|
||||
|
||||
/** 电子邮箱地址 */
|
||||
$mail = new Form\Element\Text('mail', null, null, _t('邮件地址') . ' *', _t('电子邮箱地址将作为此用户的主要联系方式.')
|
||||
. '<br />' . _t('请不要与系统中现有的电子邮箱地址重复.'));
|
||||
$form->addInput($mail);
|
||||
|
||||
/** 用户动作 */
|
||||
$do = new Form\Element\Hidden('do', null, 'profile');
|
||||
$form->addInput($do);
|
||||
|
||||
/** 提交按钮 */
|
||||
$submit = new Form\Element\Submit('submit', null, _t('更新我的档案'));
|
||||
$submit->input->setAttribute('class', 'btn primary');
|
||||
$form->addItem($submit);
|
||||
|
||||
$screenName->value($this->user->screenName);
|
||||
$url->value($this->user->url);
|
||||
$mail->value($this->user->mail);
|
||||
|
||||
/** 给表单增加规则 */
|
||||
$screenName->addRule([$this, 'screenNameExists'], _t('昵称已经存在'));
|
||||
$screenName->addRule('xssCheck', _t('请不要在昵称中使用特殊字符'));
|
||||
$url->addRule('url', _t('个人主页地址格式错误'));
|
||||
$mail->addRule('required', _t('必须填写电子邮箱'));
|
||||
$mail->addRule([$this, 'mailExists'], _t('电子邮箱地址已经存在'));
|
||||
$mail->addRule('email', _t('电子邮箱格式错误'));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行更新动作
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateOptions()
|
||||
{
|
||||
$settings['autoSave'] = $this->request->is('autoSave=1') ? 1 : 0;
|
||||
$settings['markdown'] = $this->request->is('markdown=1') ? 1 : 0;
|
||||
$settings['xmlrpcMarkdown'] = $this->request->is('xmlrpcMarkdown=1') ? 1 : 0;
|
||||
$defaultAllow = $this->request->getArray('defaultAllow');
|
||||
|
||||
$settings['defaultAllowComment'] = in_array('comment', $defaultAllow) ? 1 : 0;
|
||||
$settings['defaultAllowPing'] = in_array('ping', $defaultAllow) ? 1 : 0;
|
||||
$settings['defaultAllowFeed'] = in_array('feed', $defaultAllow) ? 1 : 0;
|
||||
|
||||
foreach ($settings as $name => $value) {
|
||||
if (
|
||||
$this->db->fetchObject($this->db->select(['COUNT(*)' => 'num'])
|
||||
->from('table.options')->where('name = ? AND user = ?', $name, $this->user->uid))->num > 0
|
||||
) {
|
||||
Options::alloc()
|
||||
->update(
|
||||
['value' => $value],
|
||||
$this->db->sql()->where('name = ? AND user = ?', $name, $this->user->uid)
|
||||
);
|
||||
} else {
|
||||
Options::alloc()->insert([
|
||||
'name' => $name,
|
||||
'value' => $value,
|
||||
'user' => $this->user->uid
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Notice::alloc()->set(_t("设置已经保存"), 'success');
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新密码
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updatePassword()
|
||||
{
|
||||
/** 验证格式 */
|
||||
if ($this->passwordForm()->validate()) {
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
$hasher = new PasswordHash(8, true);
|
||||
$password = $hasher->hashPassword($this->request->password);
|
||||
|
||||
/** 更新数据 */
|
||||
$this->update(
|
||||
['password' => $password],
|
||||
$this->db->sql()->where('uid = ?', $this->user->uid)
|
||||
);
|
||||
|
||||
/** 设置高亮 */
|
||||
Notice::alloc()->highlight('user-' . $this->user->uid);
|
||||
|
||||
/** 提示信息 */
|
||||
Notice::alloc()->set(_t('密码已经成功修改'), 'success');
|
||||
|
||||
/** 转向原页 */
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成表单
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
public function passwordForm(): Form
|
||||
{
|
||||
/** 构建表格 */
|
||||
$form = new Form($this->security->getIndex('/action/users-profile'), Form::POST_METHOD);
|
||||
|
||||
/** 用户密码 */
|
||||
$password = new Form\Element\Password('password', null, null, _t('用户密码'), _t('为此用户分配一个密码.')
|
||||
. '<br />' . _t('建议使用特殊字符与字母、数字的混编样式,以增加系统安全性.'));
|
||||
$password->input->setAttribute('class', 'w-60');
|
||||
$form->addInput($password);
|
||||
|
||||
/** 用户密码确认 */
|
||||
$confirm = new Form\Element\Password('confirm', null, null, _t('用户密码确认'), _t('请确认你的密码, 与上面输入的密码保持一致.'));
|
||||
$confirm->input->setAttribute('class', 'w-60');
|
||||
$form->addInput($confirm);
|
||||
|
||||
/** 用户动作 */
|
||||
$do = new Form\Element\Hidden('do', null, 'password');
|
||||
$form->addInput($do);
|
||||
|
||||
/** 提交按钮 */
|
||||
$submit = new Form\Element\Submit('submit', null, _t('更新密码'));
|
||||
$submit->input->setAttribute('class', 'btn primary');
|
||||
$form->addItem($submit);
|
||||
|
||||
$password->addRule('required', _t('必须填写密码'));
|
||||
$password->addRule('minLength', _t('为了保证账户安全, 请输入至少六位的密码'), 6);
|
||||
$confirm->addRule('confirm', _t('两次输入的密码不一致'), 'password');
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新个人设置
|
||||
*
|
||||
* @throws \Typecho\Widget\Exception
|
||||
*/
|
||||
public function updatePersonal()
|
||||
{
|
||||
/** 获取插件名称 */
|
||||
$pluginName = $this->request->get('plugin');
|
||||
|
||||
/** 获取已启用插件 */
|
||||
$plugins = Plugin::export();
|
||||
$activatedPlugins = $plugins['activated'];
|
||||
|
||||
/** 获取插件入口 */
|
||||
[$pluginFileName, $className] = Plugin::portal(
|
||||
$pluginName,
|
||||
__TYPECHO_ROOT_DIR__ . '/' . __TYPECHO_PLUGIN_DIR__
|
||||
);
|
||||
$info = Plugin::parseInfo($pluginFileName);
|
||||
|
||||
if (!$info['personalConfig'] || !isset($activatedPlugins[$pluginName])) {
|
||||
throw new \Typecho\Widget\Exception(_t('无法配置插件'), 500);
|
||||
}
|
||||
|
||||
$form = $this->personalForm($pluginName, $className, $pluginFileName, $group);
|
||||
$this->user->pass($group);
|
||||
|
||||
/** 验证表单 */
|
||||
if ($form->validate()) {
|
||||
$this->response->goBack();
|
||||
}
|
||||
|
||||
$settings = $form->getAllRequest();
|
||||
unset($settings['do'], $settings['plugin']);
|
||||
$name = '_plugin:' . $pluginName;
|
||||
|
||||
if (!$this->personalConfigHandle($className, $settings)) {
|
||||
if (
|
||||
$this->db->fetchObject($this->db->select(['COUNT(*)' => 'num'])
|
||||
->from('table.options')->where('name = ? AND user = ?', $name, $this->user->uid))->num > 0
|
||||
) {
|
||||
Options::alloc()
|
||||
->update(
|
||||
['value' => json_encode($settings)],
|
||||
$this->db->sql()->where('name = ? AND user = ?', $name, $this->user->uid)
|
||||
);
|
||||
} else {
|
||||
Options::alloc()->insert([
|
||||
'name' => $name,
|
||||
'value' => json_encode($settings),
|
||||
'user' => $this->user->uid
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/** 提示信息 */
|
||||
Notice::alloc()->set(_t("%s 设置已经保存", $info['title']), 'success');
|
||||
|
||||
/** 转向原页 */
|
||||
$this->response->redirect(Common::url('profile.php', $this->options->adminUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用自有函数处理自定义配置信息
|
||||
*
|
||||
* @access public
|
||||
* @param string $className 类名
|
||||
* @param array $settings 配置值
|
||||
* @return boolean
|
||||
*/
|
||||
public function personalConfigHandle(string $className, array $settings): bool
|
||||
{
|
||||
if (method_exists($className, 'personalConfigHandle')) {
|
||||
call_user_func([$className, 'personalConfigHandle'], $settings, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入口函数
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function action()
|
||||
{
|
||||
$this->security->protect();
|
||||
$this->on($this->request->is('do=profile'))->updateProfile();
|
||||
$this->on($this->request->is('do=options'))->updateOptions();
|
||||
$this->on($this->request->is('do=password'))->updatePassword();
|
||||
$this->on($this->request->is('do=personal&plugin'))->updatePersonal();
|
||||
$this->response->redirect($this->options->siteUrl);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user