浏览代码

1、实现管理员编辑用户信息
2、禁止管理员更改自己的权限和状态

Minho 8 年之前
父节点
当前提交
89b59ab1e1
共有 8 个文件被更改,包括 284 次插入4 次删除
  1. 4 0
      controllers/account.go
  2. 71 0
      controllers/manager.go
  3. 7 0
      models/errors.go
  4. 68 2
      models/member.go
  5. 1 0
      routers/router.go
  6. 117 0
      views/manager/edit_users.tpl
  7. 15 1
      views/manager/users.tpl
  8. 1 1
      views/widgets/header.tpl

+ 4 - 0
controllers/account.go

@@ -57,6 +57,9 @@ func (c *AccountController) Login()  {
 
 
 		//如果没有数据
 		//如果没有数据
 		if err == nil {
 		if err == nil {
+			member.LastLoginTime = time.Now()
+			member.Update()
+
 			c.SetMember(*member)
 			c.SetMember(*member)
 			if strings.EqualFold(is_remember,"yes") {
 			if strings.EqualFold(is_remember,"yes") {
 				remember.MemberId = member.MemberId
 				remember.MemberId = member.MemberId
@@ -68,6 +71,7 @@ func (c *AccountController) Login()  {
 				}
 				}
 
 
 			}
 			}
+
 			c.JsonResult(0,"ok")
 			c.JsonResult(0,"ok")
 		}else{
 		}else{
 			logs.Error("用户登录 =>",err)
 			logs.Error("用户登录 =>",err)

+ 71 - 0
controllers/manager.go

@@ -18,6 +18,14 @@ type ManagerController struct {
 	BaseController
 	BaseController
 }
 }
 
 
+func (c *ManagerController) Prepare (){
+	c.BaseController.Prepare()
+
+	if !c.Member.IsAdministrator() {
+		c.Abort("403")
+	}
+}
+
 func (c *ManagerController) Index() {
 func (c *ManagerController) Index() {
 	c.TplName = "manager/index.tpl"
 	c.TplName = "manager/index.tpl"
 	if !c.Member.IsAdministrator() {
 	if !c.Member.IsAdministrator() {
@@ -141,6 +149,9 @@ func (c *ManagerController) UpdateMemberStatus() {
 	if _, err := member.Find(member_id); err != nil {
 	if _, err := member.Find(member_id); err != nil {
 		c.JsonResult(6002, "用户不存在")
 		c.JsonResult(6002, "用户不存在")
 	}
 	}
+	if member.MemberId == c.Member.MemberId {
+		c.JsonResult(6004,"不能变更自己的状态")
+	}
 	member.Status = status
 	member.Status = status
 
 
 	if err := member.Update(); err != nil {
 	if err := member.Update(); err != nil {
@@ -171,6 +182,9 @@ func (c *ManagerController) ChangeMemberRole() {
 	if _, err := member.Find(member_id); err != nil {
 	if _, err := member.Find(member_id); err != nil {
 		c.JsonResult(6002, "用户不存在")
 		c.JsonResult(6002, "用户不存在")
 	}
 	}
+	if member.MemberId == c.Member.MemberId {
+		c.JsonResult(6004,"不能变更自己的权限")
+	}
 	member.Role = role
 	member.Role = role
 
 
 	if err := member.Update(); err != nil {
 	if err := member.Update(); err != nil {
@@ -181,6 +195,60 @@ func (c *ManagerController) ChangeMemberRole() {
 	c.JsonResult(0, "ok", member)
 	c.JsonResult(0, "ok", member)
 }
 }
 
 
+func (c *ManagerController) EditMember() {
+	c.Prepare()
+	c.TplName = "manager/edit_users.tpl"
+	if !c.Member.IsAdministrator() {
+		c.Abort("403")
+	}
+	member_id,_ := c.GetInt(":id",0)
+
+	if member_id <= 0 {
+		c.Abort("404")
+	}
+
+	member ,err := models.NewMember().Find(member_id)
+
+	if err != nil {
+		beego.Error(err)
+		c.Abort("404")
+	}
+	if c.Ctx.Input.IsPost() {
+		password1 := c.GetString("password1")
+		password2 := c.GetString("password2")
+		email := c.GetString("email")
+		phone := c.GetString("phone")
+		description := c.GetString("description")
+		member.Email = email
+		member.Phone = phone
+		member.Description = description
+		if password1 != "" && password2 != password1 {
+			c.JsonResult(6001,"确认密码不正确")
+		}
+		if password1 != "" {
+			member.Password = password1
+		}
+		if err := member.Valid(password1 == "");err != nil {
+			c.JsonResult(6002,err.Error())
+		}
+		if password1 != "" {
+			password,err := utils.PasswordHash(password1)
+			if err != nil {
+				beego.Error(err)
+				c.JsonResult(6003,"对用户密码加密时出错")
+			}
+			member.Password = password
+		}
+		if err := member.Update();err != nil {
+			beego.Error(err)
+			c.JsonResult(6004,"保存失败")
+		}
+		c.JsonResult(0,"ok")
+	}
+
+	c.Data["Model"] = member
+}
+
 func (c *ManagerController) Books() {
 func (c *ManagerController) Books() {
 	c.Prepare()
 	c.Prepare()
 	c.TplName = "manager/books.tpl"
 	c.TplName = "manager/books.tpl"
@@ -207,6 +275,9 @@ func (c *ManagerController) Books() {
 //编辑项目
 //编辑项目
 func (c *ManagerController) EditBook() {
 func (c *ManagerController) EditBook() {
 	c.TplName = "manager/edit_book.tpl"
 	c.TplName = "manager/edit_book.tpl"
+	if !c.Member.IsAdministrator() {
+		c.Abort("403")
+	}
 	identify := c.GetString(":key")
 	identify := c.GetString(":key")
 
 
 	if identify == "" {
 	if identify == "" {

+ 7 - 0
models/errors.go

@@ -6,7 +6,14 @@ import "errors"
 var (
 var (
 	// ErrMemberNoExist 用户不存在.
 	// ErrMemberNoExist 用户不存在.
 	ErrMemberNoExist  = errors.New("用户不存在")
 	ErrMemberNoExist  = errors.New("用户不存在")
+	ErrMemberExist  = errors.New("用户已存在")
 	ErrMemberDisabled = errors.New("用户被禁用")
 	ErrMemberDisabled = errors.New("用户被禁用")
+	ErrMemberEmailEmpty = errors.New("用户邮箱不能为空")
+	ErrMemberEmailExist = errors.New("用户邮箱已被使用")
+	ErrMemberDescriptionTooLong = errors.New("用户描述必须小于500字")
+	ErrMemberEmailFormatError = errors.New("邮箱格式不正确")
+	ErrMemberPasswordFormatError = errors.New("密码必须在6-50个字符之间")
+	ErrMemberAccountFormatError = errors.New("账号只能由英文字母数字组成,且在3-50个字符")
 	// ErrorMemberPasswordError 密码错误.
 	// ErrorMemberPasswordError 密码错误.
 	ErrorMemberPasswordError = errors.New("用户密码错误")
 	ErrorMemberPasswordError = errors.New("用户密码错误")
 	//ErrorMemberAuthMethodInvalid 不支持此认证方式
 	//ErrorMemberAuthMethodInvalid 不支持此认证方式

+ 68 - 2
models/member.go

@@ -22,7 +22,7 @@ type Member struct {
 	Account  string `orm:"size(100);unique;column(account)" json:"account"`
 	Account  string `orm:"size(100);unique;column(account)" json:"account"`
 	Password string `orm:"size(1000);column(password)" json:"-"`
 	Password string `orm:"size(1000);column(password)" json:"-"`
 	//认证方式: local 本地数据库 /ldap LDAP
 	//认证方式: local 本地数据库 /ldap LDAP
-	AuthMethod  string `orm:"column(auth_method);default(local);size(50);" json:"auth_method)"`
+	AuthMethod  string `orm:"column(auth_method);default(local);size(50);" json:"auth_method"`
 	Description string `orm:"column(description);size(2000)" json:"description"`
 	Description string `orm:"column(description);size(2000)" json:"description"`
 	Email       string `orm:"size(100);column(email);unique" json:"email"`
 	Email       string `orm:"size(100);column(email);unique" json:"email"`
 	Phone       string `orm:"size(255);column(phone);null;default(null)" json:"phone"`
 	Phone       string `orm:"size(255);column(phone);null;default(null)" json:"phone"`
@@ -73,6 +73,7 @@ func (m *Member) Login(account string, password string) (*Member, error) {
 	}
 	}
 
 
 	switch member.AuthMethod {
 	switch member.AuthMethod {
+	case "":
 	case "local":
 	case "local":
 		ok, err := utils.PasswordVerify(member.Password, password)
 		ok, err := utils.PasswordVerify(member.Password, password)
 		if ok && err == nil {
 		if ok && err == nil {
@@ -169,7 +170,9 @@ func (m *Member) Add() error {
 	}
 	}
 
 
 	m.Password = hash
 	m.Password = hash
-
+	if m.AuthMethod == "" {
+		m.AuthMethod = "local"
+	}
 	_, err = o.Insert(m)
 	_, err = o.Insert(m)
 
 
 	if err != nil {
 	if err != nil {
@@ -263,3 +266,66 @@ func (m *Member) FindByFieldFirst(field string, value interface{}) (*Member, err
 
 
 	return m, err
 	return m, err
 }
 }
+
+func (m *Member) Valid(is_hash_password bool) error {
+
+	//邮箱不能为空
+	if m.Email == "" {
+		return ErrMemberEmailEmpty
+	}
+	//用户描述必须小于500字
+	if strings.Count(m.Description,"") > 500 {
+		return ErrMemberDescriptionTooLong
+	}
+	//邮箱格式校验
+	if  ok,err := regexp.MatchString(conf.RegexpEmail,m.Email); !ok || err != nil || m.Email == "" {
+		return ErrMemberEmailFormatError
+	}
+	//如果是未加密密码,需要校验密码格式
+	if !is_hash_password {
+		if  l := strings.Count(m.Password,"") ; m.Password == "" || l > 50 || l < 6{
+			return ErrMemberPasswordFormatError
+		}
+	}
+	//校验邮箱是否呗使用
+	if member,err := NewMember().FindByFieldFirst("email",m.Account); err == nil && member.MemberId > 0 {
+		if m.MemberId > 0 && m.MemberId != member.MemberId {
+			return ErrMemberEmailExist
+		}
+		if m.MemberId <= 0{
+			return  ErrMemberEmailExist
+		}
+	}
+	if m.MemberId > 0{
+		//校验用户是否存在
+		if _,err := NewMember().Find(m.MemberId);err != nil {
+			return err
+		}
+	}else{
+		//校验账号格式是否正确
+		if ok,err := regexp.MatchString(conf.RegexpAccount,m.Account); m.Account == "" || !ok || err != nil {
+			return ErrMemberAccountFormatError
+		}
+		//校验账号是否被使用
+		if member,err := NewMember().FindByAccount(m.Account); err == nil && member.MemberId > 0 {
+			return ErrMemberExist
+		}
+	}
+
+	return nil
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 1 - 0
routers/router.go

@@ -17,6 +17,7 @@ func init()  {
 
 
 	beego.Router("/manager", &controllers.ManagerController{},"*:Index")
 	beego.Router("/manager", &controllers.ManagerController{},"*:Index")
 	beego.Router("/manager/users", &controllers.ManagerController{},"*:Users")
 	beego.Router("/manager/users", &controllers.ManagerController{},"*:Users")
+	beego.Router("/manager/users/edit/:id", &controllers.ManagerController{},"*:EditMember")
 	beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember")
 	beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember")
 	beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus")
 	beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus")
 	beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole")
 	beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole")

+ 117 - 0
views/manager/edit_users.tpl

@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <title>编辑用户 - Powered by MinDoc</title>
+
+    <!-- Bootstrap -->
+    <link href="{{cdncss "/static/bootstrap/css/bootstrap.min.css"}}" rel="stylesheet">
+    <link href="{{cdncss "/static/font-awesome/css/font-awesome.min.css"}}" rel="stylesheet">
+    <link href="/static/css/main.css" rel="stylesheet">
+    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
+    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+    <!--[if lt IE 9]>
+    <script src="/static/html5shiv/3.7.3/html5shiv.min.js"></script>
+    <script src="/static/respond.js/1.4.2/respond.min.js"></script>
+    <![endif]-->
+</head>
+<body>
+<div class="manual-reader">
+    {{template "widgets/header.tpl" .}}
+    <div class="container manual-body">
+        <div class="row">
+            <div class="page-left">
+                <ul class="menu">
+                    <li><a href="{{urlfor "ManagerController.Index"}}" class="item"><i class="fa fa-dashboard" aria-hidden="true"></i> 仪表盘</a> </li>
+                    <li class="active"><a href="{{urlfor "ManagerController.Users" }}" class="item"><i class="fa fa-users" aria-hidden="true"></i> 用户管理</a> </li>
+                    <li><a href="{{urlfor "ManagerController.Books" }}" class="item"><i class="fa fa-book" aria-hidden="true"></i> 项目管理</a> </li>
+                    {{/*<li><a href="{{urlfor "ManagerController.Comments" }}" class="item"><i class="fa fa-comments-o" aria-hidden="true"></i> 评论管理</a> </li>*/}}
+                    <li><a href="{{urlfor "ManagerController.Setting" }}" class="item"><i class="fa fa-cogs" aria-hidden="true"></i> 配置管理</a> </li>
+                </ul>
+            </div>
+            <div class="page-right">
+                <div class="m-box">
+                    <div class="box-head">
+                        <strong class="box-title"> 编辑用户</strong>
+                    </div>
+                </div>
+                <div class="box-body col-lg-6 col-sm-12">
+                    <form method="post" id="saveMemberInfoForm">
+                        <div class="form-group">
+                            <label>用户账号</label>
+                            <input type="text" class="form-control" name="account" disabled placeholder="用户账号" value="{{.Model.Account}}">
+                        </div>
+                        <div class="form-group">
+                            <label>用户密码</label>
+                            <input type="password" class="form-control" name="password1" placeholder="用户密码" maxlength="50">
+                            <p style="color: #999;font-size: 12px;">不修改密码请留空</p>
+                        </div>
+                        <div class="form-group">
+                            <label>确认密码</label>
+                            <input type="password" class="form-control" name="password2" placeholder="确认密码" maxlength="50">
+                        </div>
+                        <div class="form-group">
+                            <label>用户邮箱 <strong class="text-danger">*</strong></label>
+                            <input type="email" class="form-control" name="email" placeholder="用户邮箱" value="{{.Model.Email}}" maxlength="50">
+                        </div>
+                        <div class="form-group">
+                            <label>手机号码</label>
+                            <input type="text" class="form-control" name="phone" placeholder="手机号码" maxlength="50" value="{{.Model.Phone}}">
+                        </div>
+                        <div class="form-group">
+                            <label class="description">描述</label>
+                            <textarea class="form-control" rows="3" title="描述" name="description" id="description" maxlength="500" >{{.Model.Description}}</textarea>
+                            <p style="color: #999;font-size: 12px;">描述不能超过500字</p>
+                        </div>
+                        <div class="form-group">
+                            <button type="submit" id="btnMemberInfo" class="btn btn-success" data-loading-text="保存中...">保存修改</button>
+                            <span id="form-error-message" class="error-message"></span>
+                        </div>
+                    </form>
+
+                    <div class="clearfix"></div>
+
+                </div>
+            </div>
+        </div>
+    </div>
+    {{template "widgets/footer.tpl" .}}
+</div>
+
+
+<script src="{{cdnjs "/static/jquery/1.12.4/jquery.min.js"}}" type="text/javascript"></script>
+<script src="{{cdnjs "/static/bootstrap/js/bootstrap.min.js"}}" type="text/javascript"></script>
+<script src="{{cdnjs "/static/js/jquery.form.js"}}" type="text/javascript"></script>
+<script src="/static/js/main.js" type="text/javascript"></script>
+<script type="text/javascript">
+    $(function () {
+        $("#saveMemberInfoForm").ajaxForm({
+            beforeSubmit : function () {
+                var $then = $("#saveMemberInfoForm");
+
+                var email = $.trim($then.find("input[name='email']").val());
+                var password1 = $.trim($then.find("input[name='password1']").val());
+                var password2 = $.trim($then.find("input[name='password2']").val());
+                if (email === ""){
+                    return showError("用户邮箱不能为空!");
+                }
+                if (password1 !== "" && password1 !== password2){
+                    return showError("确认密码不正确!");
+                }
+                $("#btnMemberInfo").button("loading");
+            },success : function (res) {
+                if(res.errcode === 0) {
+                    showSuccess("保存成功")
+                }else{
+                    showError(res.message);
+                }
+                $("#btnMemberInfo").button("reset");
+            }
+        });
+    });
+</script>
+</body>
+</html>

+ 15 - 1
views/manager/users.tpl

@@ -56,6 +56,7 @@
                                     <th width="80">头像</th>
                                     <th width="80">头像</th>
                                     <th>账号</th>
                                     <th>账号</th>
                                     <th>角色</th>
                                     <th>角色</th>
+                                    <th>类型</th>
                                     <th>状态</th>
                                     <th>状态</th>
                                     <th>操作</th>
                                     <th>操作</th>
                                 </tr>
                                 </tr>
@@ -69,6 +70,9 @@
                                         <template v-if="item.role == 0">
                                         <template v-if="item.role == 0">
                                             超级管理员
                                             超级管理员
                                         </template>
                                         </template>
+                                        <template v-else-if="item.member_id == {{.Member.MemberId}}">
+                                            ${item.role_name}
+                                        </template>
                                         <template v-else>
                                         <template v-else>
                                             <div class="btn-group">
                                             <div class="btn-group">
                                             <button type="button" class="btn btn-default btn-sm"  data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                             <button type="button" class="btn btn-default btn-sm"  data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@@ -81,6 +85,9 @@
                                             </div>
                                             </div>
                                         </template>
                                         </template>
                                     </td>
                                     </td>
+                                    <td>
+                                        ${item.auth_method}
+                                    </td>
                                     <td>
                                     <td>
                                         <template v-if="item.status == 0">
                                         <template v-if="item.status == 0">
                                             <span class="label label-success">正常</span>
                                             <span class="label label-success">正常</span>
@@ -89,8 +96,15 @@
                                             <span class="label label-danger">禁用</span>
                                             <span class="label label-danger">禁用</span>
                                         </template>
                                         </template>
                                     </td>
                                     </td>
+
                                     <td>
                                     <td>
-                                        <template v-if="item.role != 0">
+                                        <template v-if="item.member_id == {{.Member.MemberId}}">
+
+                                        </template>
+                                        <template v-else-if="item.role != 0">
+                                            <a :href="'{{urlfor "ManagerController.EditMember" ":id" ""}}' + item.member_id" class="btn btn-sm btn-default" @click="editMember(item.member_id)">
+                                                编辑
+                                            </a>
                                             <template v-if="item.status == 0">
                                             <template v-if="item.status == 0">
                                                 <button type="button" class="btn btn-danger btn-sm" @click="setMemberStatus(item.member_id,1,$event)" data-loading-text="启用中...">禁用</button>
                                                 <button type="button" class="btn btn-danger btn-sm" @click="setMemberStatus(item.member_id,1,$event)" data-loading-text="启用中...">禁用</button>
                                             </template>
                                             </template>

+ 1 - 1
views/widgets/header.tpl

@@ -62,7 +62,7 @@
                         <li>
                         <li>
                             <a href="{{urlfor "BookController.Index"}}" title="我的项目"><i class="fa fa-book" aria-hidden="true"></i> 我的项目</a>
                             <a href="{{urlfor "BookController.Index"}}" title="我的项目"><i class="fa fa-book" aria-hidden="true"></i> 我的项目</a>
                         </li>
                         </li>
-                        {{if eq .Member.Role 0 }}
+                        {{if eq .Member.Role 0  1}}
                         <li>
                         <li>
                             <a href="{{urlfor "ManagerController.Index"}}" title="管理后台"><i class="fa fa-university" aria-hidden="true"></i> 管理后台</a>
                             <a href="{{urlfor "ManagerController.Index"}}" title="管理后台"><i class="fa fa-university" aria-hidden="true"></i> 管理后台</a>
                         </li>
                         </li>