Feat: login / register setting in dashboard

pull/247/head
HFO4 4 years ago
parent 04d13bd071
commit 3ce4b87f2b

@ -106,9 +106,9 @@ solid #e9e9e9;"bgcolor="#fff"><tbody><tr style="font-family: 'Helvetica Neue',He
{Name: "onedrive_callback_check", Value: `20`, Type: "timeout"},
{Name: "aria2_call_timeout", Value: `5`, Type: "timeout"},
{Name: "onedrive_chunk_retries", Value: `1`, Type: "retry"},
{Name: "allowdVisitorDownload", Value: `false`, Type: "share"},
{Name: "login_captcha", Value: `0`, Type: "login"},
{Name: "qq_login", Value: `0`, Type: "login"},
{Name: "qq_direct_login", Value: `0`, Type: "login"},
{Name: "qq_login_id", Value: ``, Type: "login"},
{Name: "qq_login_key", Value: ``, Type: "login"},
{Name: "reg_captcha", Value: `0`, Type: "login"},

@ -1,6 +1,9 @@
package email
import "errors"
import (
"errors"
"strings"
)
// Driver 邮件发送驱动
type Driver interface {
@ -19,6 +22,11 @@ var (
// Send 发送邮件
func Send(to, title, body string) error {
// 忽略通过QQ登录的邮箱
if strings.HasSuffix(to, "@login.qq.com") {
return nil
}
if Client == nil {
return ErrNoActiveDriver
}

@ -25,6 +25,12 @@ type UserCredentials struct {
AccessToken string
}
// UserInfo 用户信息
type UserInfo struct {
Nick string
Avatar string
}
var (
// ErrNotEnabled 未开启登录功能
ErrNotEnabled = serializer.NewError(serializer.CodeNoPermissionErr, "QQ登录功能未开启", nil)
@ -89,6 +95,20 @@ func getAccessTokenURL(code string) string {
return api.String()
}
func getUserInfoURL(openid, ak string) string {
// 获取相关设定
options := model.GetSettingByNames("qq_login_id", "qq_login_key")
api, _ := url.Parse("https://graph.qq.com/user/get_user_info")
queries := api.Query()
queries.Add("oauth_consumer_key", options["qq_login_id"])
queries.Add("openid", openid)
queries.Add("access_token", ak)
api.RawQuery = queries.Encode()
return api.String()
}
func getResponse(body string) (map[string]interface{}, error) {
var res map[string]interface{}
@ -157,3 +177,35 @@ func Callback(code string) (*UserCredentials, error) {
return nil, ErrDecodeResponse
}
// GetUserInfo 使用凭证获取用户信息
func GetUserInfo(credential *UserCredentials) (*UserInfo, error) {
api := getUserInfoURL(credential.OpenID, credential.AccessToken)
// 获取用户信息
client := request.HTTPClient{}
res := client.Request("GET", api, nil)
resp, err := res.GetResponse()
if err != nil {
return nil, ErrObtainAccessToken.WithError(err)
}
var resSerialized map[string]interface{}
if err := json.Unmarshal([]byte(resp), &resSerialized); err != nil {
return nil, ErrDecodeResponse.WithError(err)
}
// 如果服务端返回错误
if msg, ok := resSerialized["msg"]; ok && msg.(string) != "" {
return nil, ErrObtainAccessToken.WithError(errors.New(msg.(string)))
}
if avatar, ok := resSerialized["figureurl_qq_2"]; ok {
return &UserInfo{
Nick: resSerialized["nickname"].(string),
Avatar: avatar.(string),
}, nil
}
return nil, ErrDecodeResponse
}

@ -24,7 +24,7 @@ type Thumb struct {
// NewThumbFromFile 从文件数据获取新的Thumb对象
// 尝试通过文件名name解码图像
func NewThumbFromFile(file io.ReadSeeker, name string) (*Thumb, error) {
func NewThumbFromFile(file io.Reader, name string) (*Thumb, error) {
ext := strings.ToLower(filepath.Ext(name))
// 无扩展名时
if len(ext) == 0 {

@ -46,3 +46,14 @@ func AdminGetSetting(c *gin.Context) {
c.JSON(200, ErrorResponse(err))
}
}
// AdminGetGroups 获取用户组列表
func AdminGetGroups(c *gin.Context) {
var service admin.NoParamService
if err := c.ShouldBindUri(&service); err == nil {
res := service.GroupList()
c.JSON(200, res)
} else {
c.JSON(200, ErrorResponse(err))
}
}

@ -297,6 +297,8 @@ func InitMasterRouter() *gin.Engine {
admin.PATCH("setting", controllers.AdminChangeSetting)
// 获取设置
admin.POST("setting", controllers.AdminGetSetting)
// 获取用户组列表
admin.GET("groups", controllers.AdminGetGroups)
}
// 用户

@ -0,0 +1,13 @@
package admin
import (
model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/serializer"
)
// GroupList 获取用户组列表
func (service *NoParamService) GroupList() serializer.Response {
var res []model.Group
model.DB.Model(&model.Group{}).Find(&res)
return serializer.Response{Data: res}
}

@ -36,13 +36,20 @@ func (service *BatchSettingGet) Get() serializer.Response {
// Change 批量更改站点设定
func (service *BatchSettingChangeService) Change() serializer.Response {
cacheClean := make([]string, 0, len(service.Options))
for _, setting := range service.Options {
if err := model.DB.Model(&model.Setting{}).Where("name = ?", setting.Key).Update("value", setting.Value).Error; err != nil {
cache.Deletes(cacheClean, "setting_")
return serializer.DBErr("设置 "+setting.Key+" 更新失败", err)
}
cache.Deletes([]string{setting.Key}, "setting_")
cacheClean = append(cacheClean, setting.Key)
}
cache.Deletes(cacheClean, "setting_")
return serializer.Response{}
}

@ -14,6 +14,7 @@ import (
"net/url"
"os"
"path/filepath"
"strings"
"time"
)
@ -203,8 +204,13 @@ func (service *PolicyChange) Update(c *gin.Context, user *model.User) serializer
func (service *QQBind) Update(c *gin.Context, user *model.User) serializer.Response {
// 解除绑定
if user.OpenID != "" {
// 只通过QQ登录的用户无法解除绑定
if strings.HasSuffix(user.Email, "@login.qq.com") {
return serializer.Err(serializer.CodeNoPermissionErr, "无法解绑此账号", nil)
}
if err := user.Update(map[string]interface{}{"open_id": ""}); err != nil {
return serializer.DBErr("接触绑定失败", err)
return serializer.DBErr("接绑定失败", err)
}
return serializer.Response{
Data: "",

@ -3,7 +3,9 @@ package vas
import (
model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/qq"
"github.com/HFO4/cloudreve/pkg/request"
"github.com/HFO4/cloudreve/pkg/serializer"
"github.com/HFO4/cloudreve/pkg/thumb"
"github.com/HFO4/cloudreve/pkg/util"
"github.com/gin-gonic/gin"
)
@ -54,9 +56,52 @@ func (service *QQCallbackService) Callback(c *gin.Context, user *model.User) ser
res.Code = 203
return res
} else {
// 无匹配用户,创建新用户
}
return serializer.Response{}
// 无匹配用户,创建新用户
if !model.IsTrueVal(model.GetSettingByName("qq_direct_login")) {
return serializer.Err(serializer.CodeNoPermissionErr, "此QQ号未绑定任何账号", nil)
}
// 获取用户信息
userInfo, err := qq.GetUserInfo(credential)
if err != nil {
return serializer.Err(serializer.CodeNotSet, "无法获取用户信息", err)
}
// 生成邮箱地址
fakeEmail := util.RandStringRunes(16) + "@login.qq.com"
// 创建用户
defaultGroup := model.GetIntSetting("default_group", 2)
newUser := model.NewUser()
newUser.Email = fakeEmail
newUser.Nick = userInfo.Nick
newUser.SetPassword("")
newUser.Status = model.Active
newUser.GroupID = uint(defaultGroup)
newUser.OpenID = credential.OpenID
newUser.Avatar = "file"
// 创建用户
if err := model.DB.Create(&newUser).Error; err != nil {
return serializer.DBErr("此邮箱已被使用", err)
}
// 下载头像
r := request.HTTPClient{}
rawAvatar := r.Request("GET", userInfo.Avatar, nil)
if avatar, err := thumb.NewThumbFromFile(rawAvatar.Response.Body, "avatar.jpg"); err == nil {
avatar.CreateAvatar(newUser.ID)
}
// 登录
util.SetSession(c, map[string]interface{}{"user_id": newUser.ID})
newUser, _ = model.GetActiveUserByID(newUser.ID)
res := serializer.BuildUserResponse(newUser)
res.Code = 203
return res
}

Loading…
Cancel
Save