Init V4 community edition (#2265)
* Init V4 community edition * Init V4 community edition
This commit is contained in:
@@ -1,32 +1,33 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/googledrive"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/auth"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/conf"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/cos"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/onedrive"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/oss"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/driver/s3"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
"github.com/cloudreve/Cloudreve/v4/application/constants"
|
||||
"github.com/cloudreve/Cloudreve/v4/application/dependency"
|
||||
"github.com/cloudreve/Cloudreve/v4/ent"
|
||||
"github.com/cloudreve/Cloudreve/v4/inventory"
|
||||
"github.com/cloudreve/Cloudreve/v4/inventory/types"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/cluster/routes"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/credmanager"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver/cos"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver/obs"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver/onedrive"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver/oss"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver/s3"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/manager"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/util"
|
||||
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
|
||||
"github.com/gin-gonic/gin"
|
||||
cossdk "github.com/tencentyun/cos-go-sdk-v5"
|
||||
)
|
||||
|
||||
// PathTestService 本地路径测试服务
|
||||
@@ -40,14 +41,17 @@ type SlaveTestService struct {
|
||||
Server string `json:"server" binding:"required"`
|
||||
}
|
||||
|
||||
// SlavePingService 从机相应ping
|
||||
type SlavePingService struct {
|
||||
Callback string `json:"callback" binding:"required"`
|
||||
}
|
||||
type (
|
||||
SlavePingParameterCtx struct{}
|
||||
// SlavePingService ping slave node
|
||||
SlavePingService struct {
|
||||
Callback string `json:"callback" binding:"required"`
|
||||
}
|
||||
)
|
||||
|
||||
// AddPolicyService 存储策略添加服务
|
||||
type AddPolicyService struct {
|
||||
Policy model.Policy `json:"policy" binding:"required"`
|
||||
//Policy model.Policy `json:"policy" binding:"required"`
|
||||
}
|
||||
|
||||
// PolicyService 存储策略ID服务
|
||||
@@ -57,301 +61,444 @@ type PolicyService struct {
|
||||
}
|
||||
|
||||
// Delete 删除存储策略
|
||||
func (service *PolicyService) Delete() serializer.Response {
|
||||
func (service *SingleStoragePolicyService) Delete(c *gin.Context) error {
|
||||
// 禁止删除默认策略
|
||||
if service.ID == 1 {
|
||||
return serializer.Err(serializer.CodeDeleteDefaultPolicy, "", nil)
|
||||
return serializer.NewError(serializer.CodeDeleteDefaultPolicy, "", nil)
|
||||
}
|
||||
|
||||
policy, err := model.GetPolicyByID(service.ID)
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
ctx := context.WithValue(c, inventory.LoadStoragePolicyGroup{}, true)
|
||||
ctx = context.WithValue(ctx, inventory.SkipStoragePolicyCache{}, true)
|
||||
policy, err := storagePolicyClient.GetPolicyByID(ctx, service.ID)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodePolicyNotExist, "", err)
|
||||
return serializer.NewError(serializer.CodePolicyNotExist, "", err)
|
||||
}
|
||||
|
||||
// 检查是否有文件使用
|
||||
total := 0
|
||||
row := model.DB.Model(&model.File{}).Where("policy_id = ?", service.ID).
|
||||
Select("count(id)").Row()
|
||||
row.Scan(&total)
|
||||
if total > 0 {
|
||||
return serializer.Err(serializer.CodePolicyUsedByFiles, strconv.Itoa(total), nil)
|
||||
// If policy is used by groups, return error
|
||||
if len(policy.Edges.Groups) > 0 {
|
||||
return serializer.NewError(serializer.CodePolicyUsedByGroups, strconv.Itoa(len(policy.Edges.Groups)), nil)
|
||||
}
|
||||
|
||||
// 检查用户组使用
|
||||
var groups []model.Group
|
||||
model.DB.Model(&model.Group{}).Where(
|
||||
"policies like ?",
|
||||
fmt.Sprintf("%%[%d]%%", service.ID),
|
||||
).Find(&groups)
|
||||
|
||||
if len(groups) > 0 {
|
||||
return serializer.Err(serializer.CodePolicyUsedByGroups, strconv.Itoa(len(groups)), nil)
|
||||
}
|
||||
|
||||
model.DB.Delete(&policy)
|
||||
policy.ClearCache()
|
||||
|
||||
return serializer.Response{}
|
||||
}
|
||||
|
||||
// Get 获取存储策略详情
|
||||
func (service *PolicyService) Get() serializer.Response {
|
||||
policy, err := model.GetPolicyByID(service.ID)
|
||||
used, err := dep.FileClient().IsStoragePolicyUsedByEntities(ctx, service.ID)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodePolicyNotExist, "", err)
|
||||
return serializer.NewError(serializer.CodeDBError, "Failed to check if policy is used by entities", err)
|
||||
}
|
||||
|
||||
return serializer.Response{Data: policy}
|
||||
}
|
||||
|
||||
// GetOAuth 获取 OneDrive OAuth 地址
|
||||
func (service *PolicyService) GetOAuth(c *gin.Context, policyType string) serializer.Response {
|
||||
policy, err := model.GetPolicyByID(service.ID)
|
||||
if err != nil || policy.Type != policyType {
|
||||
return serializer.Err(serializer.CodePolicyNotExist, "", nil)
|
||||
if used {
|
||||
return serializer.NewError(serializer.CodePolicyUsedByFiles, "", nil)
|
||||
}
|
||||
|
||||
util.SetSession(c, map[string]interface{}{
|
||||
policyType + "_oauth_policy": policy.ID,
|
||||
})
|
||||
|
||||
var redirect string
|
||||
switch policy.Type {
|
||||
case "onedrive":
|
||||
client, err := onedrive.NewClient(&policy)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "Failed to initialize OneDrive client", err)
|
||||
}
|
||||
|
||||
redirect = client.OAuthURL(context.Background(), []string{
|
||||
"offline_access",
|
||||
"files.readwrite.all",
|
||||
})
|
||||
case "googledrive":
|
||||
client, err := googledrive.NewClient(&policy)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "Failed to initialize Google Drive client", err)
|
||||
}
|
||||
|
||||
redirect = client.OAuthURL(context.Background(), googledrive.RequiredScope)
|
||||
}
|
||||
|
||||
// Delete token cache
|
||||
cache.Deletes([]string{policy.BucketName}, policyType+"_")
|
||||
|
||||
return serializer.Response{Data: redirect}
|
||||
}
|
||||
|
||||
// AddSCF 创建回调云函数
|
||||
func (service *PolicyService) AddSCF() serializer.Response {
|
||||
policy, err := model.GetPolicyByID(service.ID)
|
||||
err = storagePolicyClient.Delete(ctx, policy)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodePolicyNotExist, "", nil)
|
||||
return serializer.NewError(serializer.CodeDBError, "Failed to delete policy", err)
|
||||
}
|
||||
|
||||
if err := cos.CreateSCF(&policy, service.Region); err != nil {
|
||||
return serializer.ParamErr("Failed to create SCF function", err)
|
||||
}
|
||||
|
||||
return serializer.Response{}
|
||||
}
|
||||
|
||||
// AddCORS 创建跨域策略
|
||||
func (service *PolicyService) AddCORS() serializer.Response {
|
||||
policy, err := model.GetPolicyByID(service.ID)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodePolicyNotExist, "", nil)
|
||||
}
|
||||
|
||||
switch policy.Type {
|
||||
case "oss":
|
||||
handler, err := oss.NewDriver(&policy)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeAddCORS, "", err)
|
||||
}
|
||||
if err := handler.CORS(); err != nil {
|
||||
return serializer.Err(serializer.CodeAddCORS, "", err)
|
||||
}
|
||||
case "cos":
|
||||
u, _ := url.Parse(policy.Server)
|
||||
b := &cossdk.BaseURL{BucketURL: u}
|
||||
handler := cos.Driver{
|
||||
Policy: &policy,
|
||||
HTTPClient: request.NewClient(),
|
||||
Client: cossdk.NewClient(b, &http.Client{
|
||||
Transport: &cossdk.AuthorizationTransport{
|
||||
SecretID: policy.AccessKey,
|
||||
SecretKey: policy.SecretKey,
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
if err := handler.CORS(); err != nil {
|
||||
return serializer.Err(serializer.CodeAddCORS, "", err)
|
||||
}
|
||||
case "s3":
|
||||
handler, err := s3.NewDriver(&policy)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeAddCORS, "", err)
|
||||
}
|
||||
|
||||
if err := handler.CORS(); err != nil {
|
||||
return serializer.Err(serializer.CodeAddCORS, "", err)
|
||||
}
|
||||
default:
|
||||
return serializer.Err(serializer.CodePolicyNotAllowed, "", nil)
|
||||
}
|
||||
|
||||
return serializer.Response{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Test 从机响应ping
|
||||
func (service *SlavePingService) Test() serializer.Response {
|
||||
func (service *SlavePingService) Test(c *gin.Context) error {
|
||||
master, err := url.Parse(service.Callback)
|
||||
if err != nil {
|
||||
return serializer.ParamErr("Failed to parse Master site url: "+err.Error(), nil)
|
||||
return serializer.NewError(serializer.CodeParamErr, "Failed to parse callback url", err)
|
||||
}
|
||||
|
||||
controller, _ := url.Parse("/api/v3/site/ping")
|
||||
|
||||
r := request.NewClient()
|
||||
dep := dependency.FromContext(c)
|
||||
r := dep.RequestClient()
|
||||
res, err := r.Request(
|
||||
"GET",
|
||||
master.ResolveReference(controller).String(),
|
||||
routes.MasterPingUrl(master).String(),
|
||||
nil,
|
||||
request.WithContext(c),
|
||||
request.WithLogger(logging.FromContext(c)),
|
||||
request.WithCorrelationID(),
|
||||
request.WithTimeout(time.Duration(10)*time.Second),
|
||||
).DecodeResponse()
|
||||
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeSlavePingMaster, err.Error(), nil)
|
||||
return serializer.NewError(serializer.CodeSlavePingMaster, err.Error(), nil)
|
||||
}
|
||||
|
||||
version := conf.BackendVersion
|
||||
if conf.IsPro == "true" {
|
||||
version += "-pro"
|
||||
}
|
||||
if res.Data.(string) != version {
|
||||
return serializer.Err(serializer.CodeVersionMismatch, "Master: "+res.Data.(string)+", Slave: "+version, nil)
|
||||
version := constants.BackendVersion
|
||||
|
||||
if strings.TrimSuffix(res.Data.(string), "-pro") != version {
|
||||
return serializer.NewError(serializer.CodeVersionMismatch, "Master: "+res.Data.(string)+", Slave: "+version, nil)
|
||||
}
|
||||
|
||||
return serializer.Response{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Test 测试从机通信
|
||||
func (service *SlaveTestService) Test() serializer.Response {
|
||||
slave, err := url.Parse(service.Server)
|
||||
if err != nil {
|
||||
return serializer.ParamErr("Failed to parse slave node server URL: "+err.Error(), nil)
|
||||
}
|
||||
|
||||
controller, _ := url.Parse("/api/v3/slave/ping")
|
||||
|
||||
// 请求正文
|
||||
body := map[string]string{
|
||||
"callback": model.GetSiteURL().String(),
|
||||
}
|
||||
bodyByte, _ := json.Marshal(body)
|
||||
|
||||
r := request.NewClient()
|
||||
res, err := r.Request(
|
||||
"POST",
|
||||
slave.ResolveReference(controller).String(),
|
||||
bytes.NewReader(bodyByte),
|
||||
request.WithTimeout(time.Duration(10)*time.Second),
|
||||
request.WithCredential(
|
||||
auth.HMACAuth{SecretKey: []byte(service.Secret)},
|
||||
int64(model.GetIntSetting("slave_api_timeout", 60)),
|
||||
),
|
||||
).DecodeResponse()
|
||||
if err != nil {
|
||||
return serializer.ParamErr("Failed to connect to slave node: "+err.Error(), nil)
|
||||
}
|
||||
|
||||
if res.Code != 0 {
|
||||
return serializer.ParamErr("Successfully connected to slave node, but slave returns: "+res.Msg, nil)
|
||||
}
|
||||
//slave, err := url.Parse(service.Server)
|
||||
//if err != nil {
|
||||
// return serializer.ParamErrDeprecated("Failed to parse slave node server URL: "+err.Error(), nil)
|
||||
//}
|
||||
//
|
||||
//controller, _ := url.Parse("/api/v3/slave/ping")
|
||||
//
|
||||
//// 请求正文
|
||||
//body := map[string]string{
|
||||
// "callback": model.GetSiteURL().String(),
|
||||
//}
|
||||
//bodyByte, _ := json.Marshal(body)
|
||||
//
|
||||
//r := request.NewClientDeprecated()
|
||||
//res, err := r.Request(
|
||||
// "POST",
|
||||
// slave.ResolveReference(controller).String(),
|
||||
// bytes.NewReader(bodyByte),
|
||||
// request.WithTimeout(time.Duration(10)*time.Second),
|
||||
// request.WithCredential(
|
||||
// auth.HMACAuth{SecretKey: []byte(service.Secret)},
|
||||
// int64(model.GetIntSetting("slave_api_timeout", 60)),
|
||||
// ),
|
||||
//).DecodeResponse()
|
||||
//if err != nil {
|
||||
// return serializer.ParamErrDeprecated("Failed to connect to slave node: "+err.Error(), nil)
|
||||
//}
|
||||
//
|
||||
//if res.Code != 0 {
|
||||
// return serializer.ParamErrDeprecated("Successfully connected to slave node, but slave returns: "+res.Msg, nil)
|
||||
//}
|
||||
|
||||
return serializer.Response{}
|
||||
}
|
||||
|
||||
// Add 添加存储策略
|
||||
func (service *AddPolicyService) Add() serializer.Response {
|
||||
if service.Policy.Type != "local" && service.Policy.Type != "remote" {
|
||||
service.Policy.DirNameRule = strings.TrimPrefix(service.Policy.DirNameRule, "/")
|
||||
}
|
||||
|
||||
if service.Policy.ID > 0 {
|
||||
if err := model.DB.Save(&service.Policy).Error; err != nil {
|
||||
return serializer.DBErr("Failed to save policy", err)
|
||||
}
|
||||
} else {
|
||||
if err := model.DB.Create(&service.Policy).Error; err != nil {
|
||||
return serializer.DBErr("Failed to create policy", err)
|
||||
}
|
||||
}
|
||||
|
||||
service.Policy.ClearCache()
|
||||
|
||||
return serializer.Response{Data: service.Policy.ID}
|
||||
}
|
||||
|
||||
// Test 测试本地路径
|
||||
func (service *PathTestService) Test() serializer.Response {
|
||||
policy := model.Policy{DirNameRule: service.Path}
|
||||
path := policy.GeneratePath(1, "/My File")
|
||||
path = filepath.Join(path, "test.txt")
|
||||
file, err := util.CreatNestedFile(util.RelativePath(path))
|
||||
if err != nil {
|
||||
return serializer.ParamErr(fmt.Sprintf("Failed to create \"%s\": %s", path, err.Error()), nil)
|
||||
}
|
||||
|
||||
file.Close()
|
||||
os.Remove(path)
|
||||
//policy := model.Policy{DirNameRule: service.Path}
|
||||
//path := policy.GeneratePath(1, "/My File")
|
||||
//path = filepath.Join(path, "test.txt")
|
||||
//file, err := util.CreatNestedFile(util.RelativePath(path))
|
||||
//if err != nil {
|
||||
// return serializer.ParamErrDeprecated(fmt.Sprintf("Failed to create \"%s\": %s", path, err.Error()), nil)
|
||||
//}
|
||||
//
|
||||
//file.Close()
|
||||
//os.Remove(path)
|
||||
|
||||
return serializer.Response{}
|
||||
}
|
||||
|
||||
const (
|
||||
policyTypeCondition = "policy_type"
|
||||
)
|
||||
|
||||
// Policies 列出存储策略
|
||||
func (service *AdminListService) Policies() serializer.Response {
|
||||
var res []model.Policy
|
||||
total := 0
|
||||
func (service *AdminListService) Policies(c *gin.Context) (*ListPolicyResponse, error) {
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
tx := model.DB.Model(&model.Policy{})
|
||||
if service.OrderBy != "" {
|
||||
tx = tx.Order(service.OrderBy)
|
||||
ctx := context.WithValue(c, inventory.LoadStoragePolicyGroup{}, true)
|
||||
res, err := storagePolicyClient.ListPolicies(ctx, &inventory.ListPolicyParameters{
|
||||
PaginationArgs: &inventory.PaginationArgs{
|
||||
Page: service.Page - 1,
|
||||
PageSize: service.PageSize,
|
||||
OrderBy: service.OrderBy,
|
||||
Order: inventory.OrderDirection(service.OrderDirection),
|
||||
},
|
||||
Type: types.PolicyType(service.Conditions[policyTypeCondition]),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, serializer.NewError(serializer.CodeDBError, "Failed to list policies", err)
|
||||
}
|
||||
|
||||
for k, v := range service.Conditions {
|
||||
tx = tx.Where(k+" = ?", v)
|
||||
}
|
||||
|
||||
// 计算总数用于分页
|
||||
tx.Count(&total)
|
||||
|
||||
// 查询记录
|
||||
tx.Limit(service.PageSize).Offset((service.Page - 1) * service.PageSize).Find(&res)
|
||||
|
||||
// 统计每个策略的文件使用
|
||||
statics := make(map[uint][2]int, len(res))
|
||||
policyIds := make([]uint, 0, len(res))
|
||||
for i := 0; i < len(res); i++ {
|
||||
policyIds = append(policyIds, res[i].ID)
|
||||
}
|
||||
|
||||
rows, _ := model.DB.Model(&model.File{}).Where("policy_id in (?)", policyIds).
|
||||
Select("policy_id,count(id),sum(size)").Group("policy_id").Rows()
|
||||
|
||||
for rows.Next() {
|
||||
policyId := uint(0)
|
||||
total := [2]int{}
|
||||
rows.Scan(&policyId, &total[0], &total[1])
|
||||
|
||||
statics[policyId] = total
|
||||
}
|
||||
|
||||
return serializer.Response{Data: map[string]interface{}{
|
||||
"total": total,
|
||||
"items": res,
|
||||
"statics": statics,
|
||||
}}
|
||||
return &ListPolicyResponse{
|
||||
Pagination: res.PaginationResults,
|
||||
Policies: res.Policies,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type (
|
||||
SingleStoragePolicyService struct {
|
||||
ID int `uri:"id" json:"id" binding:"required"`
|
||||
}
|
||||
GetStoragePolicyParamCtx struct{}
|
||||
)
|
||||
|
||||
const (
|
||||
countEntityQuery = "countEntity"
|
||||
)
|
||||
|
||||
func (service *SingleStoragePolicyService) Get(c *gin.Context) (*GetStoragePolicyResponse, error) {
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
ctx := context.WithValue(c, inventory.LoadStoragePolicyGroup{}, true)
|
||||
ctx = context.WithValue(ctx, inventory.SkipStoragePolicyCache{}, true)
|
||||
policy, err := storagePolicyClient.GetPolicyByID(ctx, service.ID)
|
||||
if err != nil {
|
||||
return nil, serializer.NewError(serializer.CodeDBError, "Failed to get policy", err)
|
||||
}
|
||||
|
||||
res := &GetStoragePolicyResponse{StoragePolicy: policy}
|
||||
if c.Query(countEntityQuery) != "" {
|
||||
count, size, err := dep.FileClient().CountEntityByStoragePolicyID(ctx, service.ID)
|
||||
if err != nil {
|
||||
return nil, serializer.NewError(serializer.CodeDBError, "Failed to count entities", err)
|
||||
}
|
||||
res.EntitiesCount = count
|
||||
res.EntitiesSize = size
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
type (
|
||||
CreateStoragePolicyService struct {
|
||||
Policy *ent.StoragePolicy `json:"policy" binding:"required"`
|
||||
}
|
||||
CreateStoragePolicyParamCtx struct{}
|
||||
)
|
||||
|
||||
func (service *CreateStoragePolicyService) Create(c *gin.Context) (*GetStoragePolicyResponse, error) {
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
if service.Policy.Type == types.PolicyTypeLocal {
|
||||
service.Policy.DirNameRule = util.DataPath("uploads/{uid}/{path}")
|
||||
}
|
||||
|
||||
service.Policy.ID = 0
|
||||
policy, err := storagePolicyClient.Upsert(c, service.Policy)
|
||||
if err != nil {
|
||||
return nil, serializer.NewError(serializer.CodeDBError, "Failed to create policy", err)
|
||||
}
|
||||
|
||||
return &GetStoragePolicyResponse{StoragePolicy: policy}, nil
|
||||
}
|
||||
|
||||
type (
|
||||
UpdateStoragePolicyService struct {
|
||||
Policy *ent.StoragePolicy `json:"policy" binding:"required"`
|
||||
}
|
||||
UpdateStoragePolicyParamCtx struct{}
|
||||
)
|
||||
|
||||
func (service *UpdateStoragePolicyService) Update(c *gin.Context) (*GetStoragePolicyResponse, error) {
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
return nil, serializer.NewError(serializer.CodeParamErr, "ID is required", nil)
|
||||
}
|
||||
idInt, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
return nil, serializer.NewError(serializer.CodeParamErr, "Invalid ID", err)
|
||||
}
|
||||
|
||||
service.Policy.ID = idInt
|
||||
_, err = storagePolicyClient.Upsert(c, service.Policy)
|
||||
if err != nil {
|
||||
return nil, serializer.NewError(serializer.CodeDBError, "Failed to update policy", err)
|
||||
}
|
||||
|
||||
_ = dep.KV().Delete(manager.EntityUrlCacheKeyPrefix)
|
||||
|
||||
s := SingleStoragePolicyService{ID: idInt}
|
||||
return s.Get(c)
|
||||
}
|
||||
|
||||
type (
|
||||
CreateStoragePolicyCorsService struct {
|
||||
Policy *ent.StoragePolicy `json:"policy" binding:"required"`
|
||||
}
|
||||
CreateStoragePolicyCorsParamCtx struct{}
|
||||
)
|
||||
|
||||
func (service *CreateStoragePolicyCorsService) Create(c *gin.Context) error {
|
||||
dep := dependency.FromContext(c)
|
||||
|
||||
switch service.Policy.Type {
|
||||
case types.PolicyTypeOss:
|
||||
handler, err := oss.New(c, service.Policy, dep.SettingProvider(), dep.ConfigProvider(), dep.Logger(), dep.MimeDetector(c))
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodeDBError, "Failed to create oss driver", err)
|
||||
}
|
||||
if err := handler.CORS(); err != nil {
|
||||
return serializer.NewError(serializer.CodeInternalSetting, "Failed to create cors: "+err.Error(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
case types.PolicyTypeCos:
|
||||
handler, err := cos.New(c, service.Policy, dep.SettingProvider(), dep.ConfigProvider(), dep.Logger(), dep.MimeDetector(c))
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodeDBError, "Failed to create cos driver", err)
|
||||
}
|
||||
|
||||
if err := handler.CORS(); err != nil {
|
||||
return serializer.NewError(serializer.CodeInternalSetting, "Failed to create cors: "+err.Error(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
case types.PolicyTypeS3:
|
||||
handler, err := s3.New(c, service.Policy, dep.SettingProvider(), dep.ConfigProvider(), dep.Logger(), dep.MimeDetector(c))
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodeDBError, "Failed to create s3 driver", err)
|
||||
}
|
||||
|
||||
if err := handler.CORS(); err != nil {
|
||||
return serializer.NewError(serializer.CodeInternalSetting, "Failed to create cors: "+err.Error(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
case types.PolicyTypeObs:
|
||||
handler, err := obs.New(c, service.Policy, dep.SettingProvider(), dep.ConfigProvider(), dep.Logger(), dep.MimeDetector(c))
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodeDBError, "Failed to create obs driver", err)
|
||||
}
|
||||
|
||||
if err := handler.CORS(); err != nil {
|
||||
return serializer.NewError(serializer.CodeInternalSetting, "Failed to create cors: "+err.Error(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
return serializer.NewError(serializer.CodeParamErr, "Unsupported policy type", nil)
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
GetOauthRedirectService struct {
|
||||
ID int `json:"id" binding:"required"`
|
||||
Secret string `json:"secret" binding:"required"`
|
||||
AppID string `json:"app_id" binding:"required"`
|
||||
}
|
||||
GetOauthRedirectParamCtx struct{}
|
||||
)
|
||||
|
||||
// GetOAuth 获取 OneDrive OAuth 地址
|
||||
func (service *GetOauthRedirectService) GetOAuth(c *gin.Context) (string, error) {
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
policy, err := storagePolicyClient.GetPolicyByID(c, service.ID)
|
||||
if err != nil || policy.Type != types.PolicyTypeOd {
|
||||
return "", serializer.NewError(serializer.CodePolicyNotExist, "", nil)
|
||||
}
|
||||
|
||||
// Update to latest redirect url
|
||||
policy.Settings.OauthRedirect = routes.MasterPolicyOAuthCallback(dep.SettingProvider().SiteURL(c)).String()
|
||||
policy.SecretKey = service.Secret
|
||||
policy.BucketName = service.AppID
|
||||
policy, err = storagePolicyClient.Upsert(c, policy)
|
||||
if err != nil {
|
||||
return "", serializer.NewError(serializer.CodeDBError, "Failed to update policy", err)
|
||||
}
|
||||
|
||||
client := onedrive.NewClient(policy, dep.RequestClient(), dep.CredManager(), dep.Logger(), dep.SettingProvider(), 0)
|
||||
redirect := client.OAuthURL(context.Background(), []string{
|
||||
"offline_access",
|
||||
"files.readwrite.all",
|
||||
})
|
||||
|
||||
return redirect, nil
|
||||
}
|
||||
|
||||
func GetPolicyOAuthURL(c *gin.Context) string {
|
||||
dep := dependency.FromContext(c)
|
||||
return routes.MasterPolicyOAuthCallback(dep.SettingProvider().SiteURL(c)).String()
|
||||
}
|
||||
|
||||
// GetOauthCredentialStatus returns last refresh time of oauth credential
|
||||
func (service *SingleStoragePolicyService) GetOauthCredentialStatus(c *gin.Context) (*OauthCredentialStatus, error) {
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
policy, err := storagePolicyClient.GetPolicyByID(c, service.ID)
|
||||
if err != nil || policy.Type != types.PolicyTypeOd {
|
||||
return nil, serializer.NewError(serializer.CodePolicyNotExist, "", nil)
|
||||
}
|
||||
|
||||
if policy.AccessKey == "" {
|
||||
return &OauthCredentialStatus{Valid: false}, nil
|
||||
}
|
||||
|
||||
token, err := dep.CredManager().Obtain(c, onedrive.CredentialKey(policy.ID))
|
||||
if err != nil {
|
||||
if errors.Is(err, credmanager.ErrNotFound) {
|
||||
return &OauthCredentialStatus{Valid: false}, nil
|
||||
}
|
||||
|
||||
return nil, serializer.NewError(serializer.CodeDBError, "Failed to get credential", err)
|
||||
}
|
||||
|
||||
return &OauthCredentialStatus{Valid: true, LastRefreshTime: token.RefreshedAt()}, nil
|
||||
}
|
||||
|
||||
type (
|
||||
FinishOauthCallbackService struct {
|
||||
Code string `json:"code" binding:"required"`
|
||||
State string `json:"state" binding:"required"`
|
||||
}
|
||||
FinishOauthCallbackParamCtx struct{}
|
||||
)
|
||||
|
||||
func (service *FinishOauthCallbackService) Finish(c *gin.Context) error {
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
policyId, err := strconv.Atoi(service.State)
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodeParamErr, "Invalid state", err)
|
||||
}
|
||||
|
||||
policy, err := storagePolicyClient.GetPolicyByID(c, policyId)
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodePolicyNotExist, "", nil)
|
||||
}
|
||||
|
||||
if policy.Type != types.PolicyTypeOd {
|
||||
return serializer.NewError(serializer.CodeParamErr, "Invalid policy type", nil)
|
||||
}
|
||||
|
||||
client := onedrive.NewClient(policy, dep.RequestClient(), dep.CredManager(), dep.Logger(), dep.SettingProvider(), 0)
|
||||
credential, err := client.ObtainToken(c, onedrive.WithCode(service.Code))
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodeIncorrectPassword, "Failed to obtain token", err)
|
||||
}
|
||||
|
||||
credManager := dep.CredManager()
|
||||
err = credManager.Upsert(c, credential)
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodeInternalSetting, "Failed to upsert credential", err)
|
||||
}
|
||||
|
||||
_, err = credManager.Obtain(c, onedrive.CredentialKey(policy.ID))
|
||||
if err != nil {
|
||||
return serializer.NewError(serializer.CodeInternalSetting, "Failed to obtain credential", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service *SingleStoragePolicyService) GetSharePointDriverRoot(c *gin.Context) (string, error) {
|
||||
dep := dependency.FromContext(c)
|
||||
storagePolicyClient := dep.StoragePolicyClient()
|
||||
|
||||
policy, err := storagePolicyClient.GetPolicyByID(c, service.ID)
|
||||
if err != nil {
|
||||
return "", serializer.NewError(serializer.CodePolicyNotExist, "", nil)
|
||||
}
|
||||
|
||||
if policy.Type != types.PolicyTypeOd {
|
||||
return "", serializer.NewError(serializer.CodeParamErr, "Invalid policy type", nil)
|
||||
}
|
||||
|
||||
client := onedrive.NewClient(policy, dep.RequestClient(), dep.CredManager(), dep.Logger(), dep.SettingProvider(), 0)
|
||||
root, err := client.GetSiteIDByURL(c, c.Query("url"))
|
||||
if err != nil {
|
||||
return "", serializer.NewError(serializer.CodeInternalSetting, "Failed to get site id", err)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("sites/%s/drive", root), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user