mirror of https://github.com/openspug/spug
				
				
				
			A 微信token普通用户可以通过个人中心设置
							parent
							
								
									eae6f0b818
								
							
						
					
					
						commit
						02d9563367
					
				| 
						 | 
					@ -142,14 +142,20 @@ class RoleView(AdminView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SelfView(View):
 | 
					class SelfView(View):
 | 
				
			||||||
 | 
					    def get(self, request):
 | 
				
			||||||
 | 
					        data = request.user.to_dict(selects=('nickname', 'wx_token'))
 | 
				
			||||||
 | 
					        return json_response(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def patch(self, request):
 | 
					    def patch(self, request):
 | 
				
			||||||
        form, error = JsonParser(
 | 
					        form, error = JsonParser(
 | 
				
			||||||
            Argument('old_password', required=False),
 | 
					            Argument('old_password', required=False),
 | 
				
			||||||
            Argument('new_password', required=False),
 | 
					            Argument('new_password', required=False),
 | 
				
			||||||
            Argument('nickname', required=False),
 | 
					            Argument('nickname', required=False, help='请输入昵称'),
 | 
				
			||||||
        ).parse(request.body, True)
 | 
					            Argument('wx_token', required=False),
 | 
				
			||||||
 | 
					        ).parse(request.body)
 | 
				
			||||||
        if error is None:
 | 
					        if error is None:
 | 
				
			||||||
            if form.get('old_password') and form.get('new_password'):
 | 
					            print(form)
 | 
				
			||||||
 | 
					            if form.old_password and form.new_password:
 | 
				
			||||||
                if request.user.type == 'ldap':
 | 
					                if request.user.type == 'ldap':
 | 
				
			||||||
                    return json_response(error='LDAP账户无法修改密码')
 | 
					                    return json_response(error='LDAP账户无法修改密码')
 | 
				
			||||||
                if len(form.new_password) < 6:
 | 
					                if len(form.new_password) < 6:
 | 
				
			||||||
| 
						 | 
					@ -158,11 +164,14 @@ class SelfView(View):
 | 
				
			||||||
                    request.user.password_hash = User.make_password(form.new_password)
 | 
					                    request.user.password_hash = User.make_password(form.new_password)
 | 
				
			||||||
                    request.user.token_expired = 0
 | 
					                    request.user.token_expired = 0
 | 
				
			||||||
                    request.user.save()
 | 
					                    request.user.save()
 | 
				
			||||||
 | 
					                    return json_response()
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    return json_response(error='原密码错误,请重新输入')
 | 
					                    return json_response(error='原密码错误,请重新输入')
 | 
				
			||||||
            if form.get('nickname'):
 | 
					            if form.nickname is not None:
 | 
				
			||||||
                request.user.nickname = form.nickname
 | 
					                request.user.nickname = form.nickname
 | 
				
			||||||
                request.user.save()
 | 
					            if form.wx_token is not None:
 | 
				
			||||||
 | 
					                request.user.wx_token = form.wx_token
 | 
				
			||||||
 | 
					            request.user.save()
 | 
				
			||||||
        return json_response(error=error)
 | 
					        return json_response(error=error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,13 +20,11 @@ class Argument(object):
 | 
				
			||||||
    :param bool required: is required
 | 
					    :param bool required: is required
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, name, default=None, handler=None, required=True, type=str, filter=None, help=None,
 | 
					    def __init__(self, name, default=None, handler=None, required=True, type=str, filter=None, help=None):
 | 
				
			||||||
                 nullable=False):
 | 
					 | 
				
			||||||
        self.name = name
 | 
					        self.name = name
 | 
				
			||||||
        self.default = default
 | 
					        self.default = default
 | 
				
			||||||
        self.type = type
 | 
					        self.type = type
 | 
				
			||||||
        self.required = required
 | 
					        self.required = required
 | 
				
			||||||
        self.nullable = nullable
 | 
					 | 
				
			||||||
        self.filter = filter
 | 
					        self.filter = filter
 | 
				
			||||||
        self.help = help
 | 
					        self.help = help
 | 
				
			||||||
        self.handler = handler
 | 
					        self.handler = handler
 | 
				
			||||||
| 
						 | 
					@ -45,11 +43,12 @@ class Argument(object):
 | 
				
			||||||
        elif value in [u'', '', None]:
 | 
					        elif value in [u'', '', None]:
 | 
				
			||||||
            if self.default is not None:
 | 
					            if self.default is not None:
 | 
				
			||||||
                return self.default
 | 
					                return self.default
 | 
				
			||||||
            elif not self.nullable and self.required:
 | 
					            elif self.required:
 | 
				
			||||||
                raise ParseError(
 | 
					                raise ParseError(self.help or 'Value Error: %s must not be null' % self.name)
 | 
				
			||||||
                    self.help or 'Value Error: %s must not be null' % self.name)
 | 
					            elif self.help:
 | 
				
			||||||
 | 
					                raise ParseError(self.help)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                return None
 | 
					                return value
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if self.type:
 | 
					            if self.type:
 | 
				
			||||||
                if self.type in (list, dict) and isinstance(value, str):
 | 
					                if self.type in (list, dict) and isinstance(value, str):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,37 +3,55 @@
 | 
				
			||||||
 * Copyright (c) <spug.dev@gmail.com>
 | 
					 * Copyright (c) <spug.dev@gmail.com>
 | 
				
			||||||
 * Released under the AGPL-3.0 License.
 | 
					 * Released under the AGPL-3.0 License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import React, { useState } from 'react';
 | 
					import React, { useState, useEffect } from 'react';
 | 
				
			||||||
import { Button, Form, Input, message } from 'antd';
 | 
					import { observer } from 'mobx-react';
 | 
				
			||||||
 | 
					import { Button, Form, Input, Spin, message } from 'antd';
 | 
				
			||||||
import styles from './index.module.css';
 | 
					import styles from './index.module.css';
 | 
				
			||||||
import { http } from 'libs';
 | 
					import { http } from 'libs';
 | 
				
			||||||
 | 
					import store from './store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function Basic(props) {
 | 
					export default observer(function Basic(props) {
 | 
				
			||||||
  const [nickname, setNickname] = useState(localStorage.getItem('nickname'));
 | 
					  const [form] = Form.useForm()
 | 
				
			||||||
  const [loading, setLoading] = useState(false);
 | 
					  const [fetching, setFetching] = useState(false)
 | 
				
			||||||
 | 
					  const [loading, setLoading] = useState(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (!store.user.nickname) {
 | 
				
			||||||
 | 
					      setFetching(true)
 | 
				
			||||||
 | 
					      store.fetchUser()
 | 
				
			||||||
 | 
					        .then(() => form.setFieldsValue(store.user))
 | 
				
			||||||
 | 
					        .finally(() => setFetching(false))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
				
			||||||
 | 
					  }, [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function handleSubmit() {
 | 
					  function handleSubmit() {
 | 
				
			||||||
    setLoading(true);
 | 
					    setLoading(true);
 | 
				
			||||||
    http.patch('/api/account/self/', {nickname})
 | 
					    const formData = form.getFieldsValue();
 | 
				
			||||||
 | 
					    http.patch('/api/account/self/', formData)
 | 
				
			||||||
      .then(() => {
 | 
					      .then(() => {
 | 
				
			||||||
        message.success('设置成功,重新登录或刷新页面后生效');
 | 
					        message.success('保存成功,昵称将在重新登录或刷新页面后生效');
 | 
				
			||||||
        localStorage.setItem('nickname', nickname)
 | 
					        localStorage.setItem('nickname', formData.nickname);
 | 
				
			||||||
 | 
					        store.fetchUser()
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .finally(() =>setLoading(false))
 | 
					      .finally(() => setLoading(false))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <React.Fragment>
 | 
					    <Spin spinning={fetching}>
 | 
				
			||||||
      <div className={styles.title}>基本设置</div>
 | 
					      <div className={styles.title}>基本设置</div>
 | 
				
			||||||
      <Form style={{maxWidth: 320}}>
 | 
					      <Form form={form} layout="vertical" style={{maxWidth: 320}} initialValues={store.user}>
 | 
				
			||||||
        <Form.Item colon={false} label="昵称">
 | 
					        <Form.Item required name="nickname" label="昵称">
 | 
				
			||||||
          <Input value={nickname} placeholder="请输入" onChange={e => setNickname(e.target.value)}/>
 | 
					          <Input placeholder="请输入"/>
 | 
				
			||||||
 | 
					        </Form.Item>
 | 
				
			||||||
 | 
					        <Form.Item name="wx_token" label="微信Token" extra={<a target="_blank" rel="noopener noreferrer" href="https://spug.cc/docs/wx-token/">什么是微信Token?</a>}>
 | 
				
			||||||
 | 
					          <Input placeholder="请输入"/>
 | 
				
			||||||
        </Form.Item>
 | 
					        </Form.Item>
 | 
				
			||||||
        <Form.Item>
 | 
					        <Form.Item>
 | 
				
			||||||
          <Button type="primary" loading={loading} onClick={handleSubmit}>保存设置</Button>
 | 
					          <Button type="primary" loading={loading} onClick={handleSubmit}>保存设置</Button>
 | 
				
			||||||
        </Form.Item>
 | 
					        </Form.Item>
 | 
				
			||||||
      </Form>
 | 
					      </Form>
 | 
				
			||||||
    </React.Fragment>
 | 
					    </Spin>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,13 +38,13 @@ export default function Reset(props) {
 | 
				
			||||||
    <React.Fragment>
 | 
					    <React.Fragment>
 | 
				
			||||||
      <div className={styles.title}>修改密码</div>
 | 
					      <div className={styles.title}>修改密码</div>
 | 
				
			||||||
      <Form style={{maxWidth: 320}} labelCol={{span: 6}} wrapperCol={{span: 18}}>
 | 
					      <Form style={{maxWidth: 320}} labelCol={{span: 6}} wrapperCol={{span: 18}}>
 | 
				
			||||||
        <Form.Item label="原密码">
 | 
					        <Form.Item required label="原密码">
 | 
				
			||||||
          <Input.Password value={old_password} placeholder="请输入" onChange={e => setOldPassword(e.target.value)}/>
 | 
					          <Input.Password value={old_password} placeholder="请输入" onChange={e => setOldPassword(e.target.value)}/>
 | 
				
			||||||
        </Form.Item>
 | 
					        </Form.Item>
 | 
				
			||||||
        <Form.Item label="新密码">
 | 
					        <Form.Item required label="新密码">
 | 
				
			||||||
          <Input.Password value={new_password} placeholder="请输入" onChange={e => setNewPassword(e.target.value)}/>
 | 
					          <Input.Password value={new_password} placeholder="请输入" onChange={e => setNewPassword(e.target.value)}/>
 | 
				
			||||||
        </Form.Item>
 | 
					        </Form.Item>
 | 
				
			||||||
        <Form.Item label="再次确认">
 | 
					        <Form.Item required label="再次确认">
 | 
				
			||||||
          <Input.Password value={new2_password} placeholder="请输入" onChange={e => setNew2Password(e.target.value)}/>
 | 
					          <Input.Password value={new2_password} placeholder="请输入" onChange={e => setNew2Password(e.target.value)}/>
 | 
				
			||||||
        </Form.Item>
 | 
					        </Form.Item>
 | 
				
			||||||
        <Form.Item>
 | 
					        <Form.Item>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,48 +3,40 @@
 | 
				
			||||||
 * Copyright (c) <spug.dev@gmail.com>
 | 
					 * Copyright (c) <spug.dev@gmail.com>
 | 
				
			||||||
 * Released under the AGPL-3.0 License.
 | 
					 * Released under the AGPL-3.0 License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import React from 'react';
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
import { Menu } from 'antd';
 | 
					import { Menu } from 'antd';
 | 
				
			||||||
import { Breadcrumb } from 'components';
 | 
					import { Breadcrumb } from 'components';
 | 
				
			||||||
import Basic from './Basic';
 | 
					import Basic from './Basic';
 | 
				
			||||||
import Reset from './Reset';
 | 
					import Reset from './Reset';
 | 
				
			||||||
import styles from './index.module.css';
 | 
					import styles from './index.module.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Index extends React.Component {
 | 
					function Index() {
 | 
				
			||||||
  constructor(props) {
 | 
					  const [selectedKeys, setSelectedKeys] = useState(['basic'])
 | 
				
			||||||
    super(props);
 | 
					 | 
				
			||||||
    this.state = {
 | 
					 | 
				
			||||||
      selectedKeys: ['basic']
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render() {
 | 
					  return (
 | 
				
			||||||
    const {selectedKeys} = this.state;
 | 
					    <div>
 | 
				
			||||||
    return (
 | 
					      <Breadcrumb>
 | 
				
			||||||
      <div>
 | 
					        <Breadcrumb.Item>首页</Breadcrumb.Item>
 | 
				
			||||||
        <Breadcrumb>
 | 
					        <Breadcrumb.Item>个人中心</Breadcrumb.Item>
 | 
				
			||||||
          <Breadcrumb.Item>首页</Breadcrumb.Item>
 | 
					      </Breadcrumb>
 | 
				
			||||||
          <Breadcrumb.Item>个人中心</Breadcrumb.Item>
 | 
					      <div className={styles.container}>
 | 
				
			||||||
        </Breadcrumb>
 | 
					        <div className={styles.left}>
 | 
				
			||||||
        <div className={styles.container}>
 | 
					          <Menu
 | 
				
			||||||
          <div className={styles.left}>
 | 
					            mode="inline"
 | 
				
			||||||
            <Menu
 | 
					            selectedKeys={selectedKeys}
 | 
				
			||||||
              mode="inline"
 | 
					            style={{border: 'none'}}
 | 
				
			||||||
              selectedKeys={selectedKeys}
 | 
					            onSelect={({selectedKeys}) => setSelectedKeys(selectedKeys)}>
 | 
				
			||||||
              style={{border: 'none'}}
 | 
					            <Menu.Item key="basic">基本设置</Menu.Item>
 | 
				
			||||||
              onSelect={({selectedKeys}) => this.setState({selectedKeys})}>
 | 
					            <Menu.Item key="reset">修改密码</Menu.Item>
 | 
				
			||||||
              <Menu.Item key="basic">基本设置</Menu.Item>
 | 
					          </Menu>
 | 
				
			||||||
              <Menu.Item key="reset">修改密码</Menu.Item>
 | 
					        </div>
 | 
				
			||||||
            </Menu>
 | 
					        <div className={styles.right}>
 | 
				
			||||||
          </div>
 | 
					          {selectedKeys[0] === 'basic' && <Basic/>}
 | 
				
			||||||
          <div className={styles.right}>
 | 
					          {selectedKeys[0] === 'reset' && <Reset/>}
 | 
				
			||||||
            {selectedKeys[0] === 'basic' && <Basic/>}
 | 
					 | 
				
			||||||
            {selectedKeys[0] === 'reset' && <Reset/>}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    )
 | 
					    </div>
 | 
				
			||||||
  }
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Index
 | 
					export default Index
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.title {
 | 
					.title {
 | 
				
			||||||
    margin-bottom: 12px;
 | 
					    margin-bottom: 24px;
 | 
				
			||||||
    color: rgba(0, 0, 0, .85);
 | 
					    color: rgba(0, 0, 0, .85);
 | 
				
			||||||
    font-weight: 500;
 | 
					    font-weight: 500;
 | 
				
			||||||
    font-size: 20px;
 | 
					    font-size: 20px;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright (c) OpenSpug Organization. https://github.com/openspug/spug
 | 
				
			||||||
 | 
					 * Copyright (c) <spug.dev@gmail.com>
 | 
				
			||||||
 | 
					 * Released under the AGPL-3.0 License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					import { observable } from 'mobx';
 | 
				
			||||||
 | 
					import http from 'libs/http';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Store {
 | 
				
			||||||
 | 
					  @observable user = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fetchUser = () => {
 | 
				
			||||||
 | 
					    return http.get('/api/account/self/')
 | 
				
			||||||
 | 
					      .then(res => this.user = res)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default new Store()
 | 
				
			||||||
		Loading…
	
		Reference in New Issue