mirror of
https://github.com/halejohn/Cloudreve.git
synced 2026-01-26 09:34:57 +08:00
Feat: user setting
This commit is contained in:
159
pkg/qq/connect.go
Normal file
159
pkg/qq/connect.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package qq
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/request"
|
||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||
"github.com/gofrs/uuid"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// LoginPage 登陆页面描述
|
||||
type LoginPage struct {
|
||||
URL string
|
||||
SecretKey string
|
||||
}
|
||||
|
||||
// UserCredentials 登陆成功后的凭证
|
||||
type UserCredentials struct {
|
||||
OpenID string
|
||||
AccessToken string
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrNotEnabled 未开启登录功能
|
||||
ErrNotEnabled = serializer.NewError(serializer.CodeNoPermissionErr, "QQ登录功能未开启", nil)
|
||||
// ErrObtainAccessToken 无法获取AccessToken
|
||||
ErrObtainAccessToken = serializer.NewError(serializer.CodeParamErr, "无法获取AccessToken", nil)
|
||||
// ErrObtainOpenID 无法获取OpenID
|
||||
ErrObtainOpenID = serializer.NewError(serializer.CodeParamErr, "无法获取OpenID", nil)
|
||||
//ErrDecodeResponse 无法解析服务端响应
|
||||
ErrDecodeResponse = serializer.NewError(serializer.CodeInternalSetting, "无法解析服务端响应", nil)
|
||||
)
|
||||
|
||||
// NewLoginRequest 新建登录会话
|
||||
func NewLoginRequest() (*LoginPage, error) {
|
||||
// 获取相关设定
|
||||
options := model.GetSettingByNames("qq_login", "qq_login_id")
|
||||
if options["qq_login"] == "0" {
|
||||
return nil, ErrNotEnabled
|
||||
}
|
||||
|
||||
// 生成唯一ID
|
||||
u2, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret := fmt.Sprintf("%x", md5.Sum(u2.Bytes()))
|
||||
|
||||
// 生成登录地址
|
||||
loginURL, _ := url.Parse("https://graph.qq.com/oauth2.0/authorize?response_type=code")
|
||||
queries := loginURL.Query()
|
||||
queries.Add("client_id", options["qq_login_id"])
|
||||
queries.Add("redirect_uri", getCallbackURL())
|
||||
queries.Add("state", secret)
|
||||
loginURL.RawQuery = queries.Encode()
|
||||
|
||||
return &LoginPage{
|
||||
URL: loginURL.String(),
|
||||
SecretKey: secret,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getCallbackURL() string {
|
||||
return "https://drive.aoaoao.me/Callback/QQ"
|
||||
// 生成回调地址
|
||||
gateway, _ := url.Parse("/#/login/qq")
|
||||
callback := model.GetSiteURL().ResolveReference(gateway).String()
|
||||
|
||||
return callback
|
||||
}
|
||||
|
||||
func getAccessTokenURL(code string) string {
|
||||
// 获取相关设定
|
||||
options := model.GetSettingByNames("qq_login_id", "qq_login_key")
|
||||
|
||||
api, _ := url.Parse("https://graph.qq.com/oauth2.0/token?grant_type=authorization_code")
|
||||
queries := api.Query()
|
||||
queries.Add("client_id", options["qq_login_id"])
|
||||
queries.Add("redirect_uri", getCallbackURL())
|
||||
queries.Add("client_secret", options["qq_login_key"])
|
||||
queries.Add("code", code)
|
||||
api.RawQuery = queries.Encode()
|
||||
|
||||
return api.String()
|
||||
}
|
||||
|
||||
func getResponse(body string) (map[string]interface{}, error) {
|
||||
var res map[string]interface{}
|
||||
|
||||
if !strings.Contains(body, "callback") {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
body = strings.TrimPrefix(body, "callback(")
|
||||
body = strings.TrimSuffix(body, ");\n")
|
||||
|
||||
err := json.Unmarshal([]byte(body), &res)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Callback 处理回调,返回openid和access key
|
||||
func Callback(code string) (*UserCredentials, error) {
|
||||
// 获取相关设定
|
||||
options := model.GetSettingByNames("qq_login")
|
||||
if options["qq_login"] == "0" {
|
||||
return nil, ErrNotEnabled
|
||||
}
|
||||
|
||||
api := getAccessTokenURL(code)
|
||||
|
||||
// 获取AccessToken
|
||||
client := request.HTTPClient{}
|
||||
res := client.Request("GET", api, nil)
|
||||
resp, err := res.GetResponse()
|
||||
if err != nil {
|
||||
return nil, ErrObtainAccessToken.WithError(err)
|
||||
}
|
||||
|
||||
// 如果服务端返回错误
|
||||
errResp, err := getResponse(resp)
|
||||
if msg, ok := errResp["error_description"]; err == nil && ok {
|
||||
return nil, ErrObtainAccessToken.WithError(errors.New(msg.(string)))
|
||||
}
|
||||
|
||||
// 获取AccessToken
|
||||
vals, err := url.ParseQuery(resp)
|
||||
if err != nil {
|
||||
return nil, ErrDecodeResponse.WithError(err)
|
||||
}
|
||||
accessToken := vals.Get("access_token")
|
||||
|
||||
// 用 AccessToken 换取OpenID
|
||||
res = client.Request("GET", "https://graph.qq.com/oauth2.0/me?access_token="+accessToken, nil)
|
||||
resp, err = res.GetResponse()
|
||||
if err != nil {
|
||||
return nil, ErrObtainOpenID.WithError(err)
|
||||
}
|
||||
|
||||
// 解析服务端响应
|
||||
errResp, err = getResponse(resp)
|
||||
if msg, ok := errResp["error_description"]; err == nil && ok {
|
||||
return nil, ErrObtainOpenID.WithError(errors.New(msg.(string)))
|
||||
}
|
||||
|
||||
if openid, ok := errResp["openid"]; ok {
|
||||
return &UserCredentials{
|
||||
OpenID: openid.(string),
|
||||
AccessToken: accessToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, ErrDecodeResponse
|
||||
}
|
||||
@@ -46,6 +46,7 @@ type group struct {
|
||||
ShareFreeEnabled bool `json:"shareFree"`
|
||||
ShareDownload bool `json:"shareDownload"`
|
||||
CompressEnabled bool `json:"compress"`
|
||||
WebDAVEnabled bool `json:"webdav"`
|
||||
}
|
||||
|
||||
type tag struct {
|
||||
@@ -91,6 +92,7 @@ func BuildUser(user model.User) User {
|
||||
ShareFreeEnabled: user.Group.OptionsSerialized.ShareFree,
|
||||
ShareDownload: user.Group.OptionsSerialized.ShareDownload,
|
||||
CompressEnabled: user.Group.OptionsSerialized.ArchiveTask,
|
||||
WebDAVEnabled: user.Group.WebDAVEnabled,
|
||||
},
|
||||
Tags: buildTagRes(tags),
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@ package thumb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/util"
|
||||
"image"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -66,14 +68,36 @@ func (image *Thumb) GetSize() (int, int) {
|
||||
|
||||
// Save 保存图像到给定路径
|
||||
func (image *Thumb) Save(path string) (err error) {
|
||||
out, err := os.Create(path)
|
||||
defer out.Close()
|
||||
out, err := util.CreatNestedFile(path)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
err = png.Encode(out, image.src)
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
// CreateAvatar 创建头像
|
||||
func (image *Thumb) CreateAvatar(uid uint) error {
|
||||
// 读取头像相关设定
|
||||
savePath := model.GetSettingByName("avatar_path")
|
||||
s := model.GetIntSetting("avatar_size_s", 50)
|
||||
m := model.GetIntSetting("avatar_size_m", 130)
|
||||
l := model.GetIntSetting("avatar_size_l", 200)
|
||||
|
||||
// 生成头像缩略图
|
||||
src := image.src
|
||||
for k, size := range []int{s, m, l} {
|
||||
image.src = resize.Resize(uint(size), uint(size), src, resize.Lanczos3)
|
||||
err := image.Save(filepath.Join(savePath, fmt.Sprintf("avatar_%d_%d.png", uid, k)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user