package controller import ( "encoding/json" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" "github.com/google/uuid" "message-pusher/channel" "message-pusher/common" "message-pusher/model" "net/http" "strconv" "strings" ) type LoginRequest struct { Username string `json:"username"` Password string `json:"password"` } func Login(c *gin.Context) { if !common.PasswordLoginEnabled { c.JSON(http.StatusOK, gin.H{ "message": "管理员关闭了密码登录", "success": false, }) return } var loginRequest LoginRequest err := json.NewDecoder(c.Request.Body).Decode(&loginRequest) if err != nil { c.JSON(http.StatusOK, gin.H{ "message": "无效的参数", "success": false, }) return } username := loginRequest.Username password := loginRequest.Password if username == "" || password == "" { c.JSON(http.StatusOK, gin.H{ "message": "无效的参数", "success": false, }) return } user := model.User{ Username: username, Password: password, } err = user.ValidateAndFill() if err != nil { c.JSON(http.StatusOK, gin.H{ "message": err.Error(), "success": false, }) return } setupLogin(&user, c) } // setup session & cookies and then return user info func setupLogin(user *model.User, c *gin.Context) { session := sessions.Default(c) session.Set("id", user.Id) session.Set("username", user.Username) session.Set("role", user.Role) session.Set("status", user.Status) err := session.Save() if err != nil { c.JSON(http.StatusOK, gin.H{ "message": "无法保存会话信息,请重试", "success": false, }) return } cleanUser := model.User{ Id: user.Id, Username: user.Username, DisplayName: user.DisplayName, Role: user.Role, Status: user.Status, } c.JSON(http.StatusOK, gin.H{ "message": "", "success": true, "data": cleanUser, }) } func Logout(c *gin.Context) { session := sessions.Default(c) session.Clear() err := session.Save() if err != nil { c.JSON(http.StatusOK, gin.H{ "message": err.Error(), "success": false, }) return } c.JSON(http.StatusOK, gin.H{ "message": "", "success": true, }) } func Register(c *gin.Context) { if !common.RegisterEnabled { c.JSON(http.StatusOK, gin.H{ "message": "管理员关闭了新用户注册", "success": false, }) return } if !common.PasswordRegisterEnabled { c.JSON(http.StatusOK, gin.H{ "message": "管理员关闭了通过密码进行注册,请使用第三方账户验证的形式进行注册", "success": false, }) return } var user model.User err := json.NewDecoder(c.Request.Body).Decode(&user) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无效的参数", }) return } if err := common.Validate.Struct(&user); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "输入不合法 " + err.Error(), }) return } if common.EmailVerificationEnabled { if user.Email == "" || user.VerificationCode == "" { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "管理员开启了邮箱验证,请输入邮箱地址和验证码", }) return } if !common.VerifyCodeWithKey(user.Email, user.VerificationCode, common.EmailVerificationPurpose) { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "验证码错误或已过期", }) return } } cleanUser := model.User{ Username: user.Username, Password: user.Password, DisplayName: user.Username, } if common.EmailVerificationEnabled { cleanUser.Email = user.Email } if err := cleanUser.Insert(); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", }) return } func GetAllUsers(c *gin.Context) { p, _ := strconv.Atoi(c.Query("p")) if p < 0 { p = 0 } users, err := model.GetAllUsers(p*common.ItemsPerPage, common.ItemsPerPage) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": users, }) return } func SearchUsers(c *gin.Context) { keyword := c.Query("keyword") users, err := model.SearchUsers(keyword) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": users, }) return } func GetUser(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } user, err := model.GetUserById(id, false) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } myRole := c.GetInt("role") if myRole <= user.Role { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无权获取同级或更高等级用户的信息", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": user, }) return } func GenerateToken(c *gin.Context) { id := c.GetInt("id") user, err := model.GetUserById(id, true) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } user.Token = uuid.New().String() user.Token = strings.Replace(user.Token, "-", "", -1) if model.DB.Where("token = ?", user.Token).First(user).RowsAffected != 0 { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "请重试,系统生成的 UUID 竟然重复了!", }) return } if err := user.Update(false); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": user.Token, }) return } func GetSelf(c *gin.Context) { id := c.GetInt("id") user, err := model.GetUserById(id, false) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": user, }) return } func UpdateUser(c *gin.Context) { var updatedUser model.User err := json.NewDecoder(c.Request.Body).Decode(&updatedUser) if err != nil || updatedUser.Id == 0 { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无效的参数", }) return } if updatedUser.Password == "" { updatedUser.Password = "$I_LOVE_U" // make Validator happy :) } if err := common.Validate.Struct(&updatedUser); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "输入不合法 " + err.Error(), }) return } originUser, err := model.GetUserById(updatedUser.Id, false) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } myRole := c.GetInt("role") if myRole <= originUser.Role { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无权更新同权限等级或更高权限等级的用户信息", }) return } if myRole <= updatedUser.Role { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无权将其他用户权限等级提升到大于等于自己的权限等级", }) return } if updatedUser.Password == "$I_LOVE_U" { updatedUser.Password = "" // rollback to what it should be } // We only allow admin change those fields. cleanUser := model.User{ Id: updatedUser.Id, Username: updatedUser.Username, Password: updatedUser.Password, DisplayName: updatedUser.DisplayName, } updatePassword := cleanUser.Password != "" if err := cleanUser.Update(updatePassword); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", }) return } func UpdateSelf(c *gin.Context) { var user model.User err := json.NewDecoder(c.Request.Body).Decode(&user) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无效的参数", }) return } if user.Password == "" { user.Password = "$I_LOVE_U" // make Validator happy :) } if err := common.Validate.Struct(&user); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "输入不合法 " + err.Error(), }) return } // White list mode. For safe :) cleanUser := model.User{ Id: c.GetInt("id"), Username: user.Username, Password: user.Password, DisplayName: user.DisplayName, Token: user.Token, Channel: user.Channel, } if user.Password == "$I_LOVE_U" { user.Password = "" // rollback to what it should be cleanUser.Password = "" } updatePassword := user.Password != "" if err := cleanUser.Update(updatePassword); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", }) return } func DeleteUser(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } originUser, err := model.GetUserById(id, false) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } myRole := c.GetInt("role") if myRole <= originUser.Role { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无权删除同权限等级或更高权限等级的用户", }) return } channel.TokenStoreRemoveUser(originUser) err = model.DeleteUserById(id) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", }) return } } func DeleteSelf(c *gin.Context) { id := c.GetInt("id") user := model.User{Id: id} err := user.FillUserById() if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } channel.TokenStoreRemoveUser(&user) err = model.DeleteUserById(id) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", }) return } func CreateUser(c *gin.Context) { var user model.User err := json.NewDecoder(c.Request.Body).Decode(&user) if err != nil || user.Username == "" || user.Password == "" { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无效的参数", }) return } if user.DisplayName == "" { user.DisplayName = user.Username } myRole := c.GetInt("role") if user.Role >= myRole { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无法创建权限大于等于自己的用户", }) return } // Even for admin users, we cannot fully trust them! cleanUser := model.User{ Username: user.Username, Password: user.Password, DisplayName: user.DisplayName, } if err := cleanUser.Insert(); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", }) return } type ManageRequest struct { Username string `json:"username"` Action string `json:"action"` } // ManageUser Only admin user can do this func ManageUser(c *gin.Context) { var req ManageRequest err := json.NewDecoder(c.Request.Body).Decode(&req) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无效的参数", }) return } user := model.User{ Username: req.Username, } // Fill attributes model.DB.Where(&user).First(&user) if user.Id == 0 { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "用户不存在", }) return } myRole := c.GetInt("role") if myRole <= user.Role && myRole != common.RoleRootUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无权更新同权限等级或更高权限等级的用户信息", }) return } switch req.Action { case "disable": if user.Status == common.UserStatusDisabled { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "该账户已经是封禁状态", }) return } if user.Role == common.RoleRootUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无法禁用超级管理员用户", }) return } channel.TokenStoreRemoveUser(&user) user.Status = common.UserStatusDisabled case "enable": if user.Status == common.UserStatusEnabled { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "该账户已经是启用状态", }) return } channel.TokenStoreAddUser(&user) user.Status = common.UserStatusEnabled case "delete": if user.Role == common.RoleRootUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无法删除超级管理员用户", }) return } if err := user.Delete(); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } channel.TokenStoreRemoveUser(&user) case "promote": if myRole != common.RoleRootUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "普通管理员用户无法提升其他用户为管理员", }) return } if user.Role >= common.RoleAdminUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "该用户已经是管理员", }) return } user.Role = common.RoleAdminUser case "demote": if user.Role == common.RoleRootUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "无法降级超级管理员用户", }) return } if user.Role == common.RoleCommonUser { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "该用户已经是普通用户", }) return } user.Role = common.RoleCommonUser case "allow_send_email_to_others": user.SendEmailToOthers = common.SendEmailToOthersAllowed case "disallow_send_email_to_others": user.SendEmailToOthers = common.SendEmailToOthersDisallowed case "allow_save_message_to_database": user.SaveMessageToDatabase = common.SaveMessageToDatabaseAllowed case "disallow_save_message_to_database": user.SaveMessageToDatabase = common.SaveMessageToDatabaseDisallowed } if err := user.Update(false); err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } clearUser := model.User{ Role: user.Role, Status: user.Status, SendEmailToOthers: user.SendEmailToOthers, SaveMessageToDatabase: user.SaveMessageToDatabase, } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": clearUser, }) return } func EmailBind(c *gin.Context) { email := c.Query("email") code := c.Query("code") if !common.VerifyCodeWithKey(email, code, common.EmailVerificationPurpose) { c.JSON(http.StatusOK, gin.H{ "success": false, "message": "验证码错误或已过期", }) return } id := c.GetInt("id") user := model.User{ Id: id, } err := user.FillUserById() if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } user.Email = email // no need to check if this email already taken, because we have used verification code to check it err = user.Update(false) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, "message": err.Error(), }) return } // create email channel for this user emailChannel := model.Channel{ Type: model.TypeEmail, UserId: user.Id, Name: "email", Description: "系统自动创建", Status: common.ChannelStatusEnabled, CreatedTime: common.GetTimestamp(), } _ = emailChannel.Insert() c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", }) return }