| @@ -20,8 +20,6 @@ import ( | |||||
| "io" | "io" | ||||
| "mime/multipart" | "mime/multipart" | ||||
| "strings" | "strings" | ||||
| "github.com/casbin/casibase/storage" | |||||
| ) | ) | ||||
| func UpdateFile(storeId string, key string, file *File) bool { | func UpdateFile(storeId string, key string, file *File) bool { | ||||
| @@ -37,6 +35,11 @@ func AddFile(storeId string, userName string, key string, isLeaf bool, filename | |||||
| return false, nil, nil | return false, nil, nil | ||||
| } | } | ||||
| storageProviderObj, err := store.GetStorageProviderObj() | |||||
| if err != nil { | |||||
| return false, nil, err | |||||
| } | |||||
| var objectKey string | var objectKey string | ||||
| var fileBuffer *bytes.Buffer | var fileBuffer *bytes.Buffer | ||||
| if isLeaf { | if isLeaf { | ||||
| @@ -49,7 +52,7 @@ func AddFile(storeId string, userName string, key string, isLeaf bool, filename | |||||
| } | } | ||||
| bs := fileBuffer.Bytes() | bs := fileBuffer.Bytes() | ||||
| err = storage.PutObject(store.StorageProvider, userName, store.Name, objectKey, fileBuffer) | |||||
| err = storageProviderObj.PutObject(userName, store.Name, objectKey, fileBuffer) | |||||
| if err != nil { | if err != nil { | ||||
| return false, nil, err | return false, nil, err | ||||
| } | } | ||||
| @@ -60,7 +63,7 @@ func AddFile(storeId string, userName string, key string, isLeaf bool, filename | |||||
| objectKey = strings.TrimLeft(objectKey, "/") | objectKey = strings.TrimLeft(objectKey, "/") | ||||
| fileBuffer = bytes.NewBuffer(nil) | fileBuffer = bytes.NewBuffer(nil) | ||||
| bs := fileBuffer.Bytes() | bs := fileBuffer.Bytes() | ||||
| err = storage.PutObject(store.StorageProvider, userName, store.Name, objectKey, fileBuffer) | |||||
| err = storageProviderObj.PutObject(userName, store.Name, objectKey, fileBuffer) | |||||
| if err != nil { | if err != nil { | ||||
| return false, nil, err | return false, nil, err | ||||
| } | } | ||||
| @@ -78,19 +81,24 @@ func DeleteFile(storeId string, key string, isLeaf bool) (bool, error) { | |||||
| return false, nil | return false, nil | ||||
| } | } | ||||
| storageProviderObj, err := store.GetStorageProviderObj() | |||||
| if err != nil { | |||||
| return false, err | |||||
| } | |||||
| if isLeaf { | if isLeaf { | ||||
| err = storage.DeleteObject(store.StorageProvider, key) | |||||
| err = storageProviderObj.DeleteObject(key) | |||||
| if err != nil { | if err != nil { | ||||
| return false, err | return false, err | ||||
| } | } | ||||
| } else { | } else { | ||||
| objects, err := storage.ListObjects(store.StorageProvider, key) | |||||
| objects, err := storageProviderObj.ListObjects(key) | |||||
| if err != nil { | if err != nil { | ||||
| return false, err | return false, err | ||||
| } | } | ||||
| for _, object := range objects { | for _, object := range objects { | ||||
| err = storage.DeleteObject(store.StorageProvider, object.Key) | |||||
| err = storageProviderObj.DeleteObject(object.Key) | |||||
| if err != nil { | if err != nil { | ||||
| return false, err | return false, err | ||||
| } | } | ||||
| @@ -24,7 +24,7 @@ func InitDb() { | |||||
| } | } | ||||
| func initBuiltInStore() bool { | func initBuiltInStore() bool { | ||||
| store, err := getStore("admin", "built-in") | |||||
| store, err := getStore("admin", "store-built-in") | |||||
| if err != nil { | if err != nil { | ||||
| panic(err) | panic(err) | ||||
| } | } | ||||
| @@ -35,10 +35,10 @@ func initBuiltInStore() bool { | |||||
| store = &Store{ | store = &Store{ | ||||
| Owner: "admin", | Owner: "admin", | ||||
| Name: "store-default", | |||||
| Name: "store-built-in", | |||||
| CreatedTime: util.GetCurrentTime(), | CreatedTime: util.GetCurrentTime(), | ||||
| DisplayName: "Data Store - Default", | |||||
| StorageProvider: "", | |||||
| DisplayName: "Built-in Store", | |||||
| StorageProvider: "provider-storage-built-in", | |||||
| ModelProvider: "", | ModelProvider: "", | ||||
| EmbeddingProvider: "", | EmbeddingProvider: "", | ||||
| } | } | ||||
| @@ -51,7 +51,7 @@ func initBuiltInStore() bool { | |||||
| } | } | ||||
| func initBuiltInProvider() { | func initBuiltInProvider() { | ||||
| provider, err := GetProvider(util.GetId("admin", "provider_captcha_default")) | |||||
| provider, err := GetProvider(util.GetId("admin", "provider-storage-local-built-in")) | |||||
| if err != nil { | if err != nil { | ||||
| panic(err) | panic(err) | ||||
| } | } | ||||
| @@ -62,11 +62,12 @@ func initBuiltInProvider() { | |||||
| provider = &Provider{ | provider = &Provider{ | ||||
| Owner: "admin", | Owner: "admin", | ||||
| Name: "provider_captcha_default", | |||||
| Name: "provider-storage-built-in", | |||||
| CreatedTime: util.GetCurrentTime(), | CreatedTime: util.GetCurrentTime(), | ||||
| DisplayName: "Captcha Default", | |||||
| Category: "Captcha", | |||||
| Type: "Default", | |||||
| DisplayName: "Built-in Storage Provider", | |||||
| Category: "Storage", | |||||
| Type: "Local File System", | |||||
| ClientId: "F:/github_repos/casdoor-website", | |||||
| } | } | ||||
| _, err = AddProvider(provider) | _, err = AddProvider(provider) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -19,6 +19,7 @@ import ( | |||||
| "github.com/casbin/casibase/embedding" | "github.com/casbin/casibase/embedding" | ||||
| "github.com/casbin/casibase/model" | "github.com/casbin/casibase/model" | ||||
| "github.com/casbin/casibase/storage" | |||||
| "github.com/casbin/casibase/util" | "github.com/casbin/casibase/util" | ||||
| "xorm.io/core" | "xorm.io/core" | ||||
| ) | ) | ||||
| @@ -103,6 +104,20 @@ func GetProvider(id string) (*Provider, error) { | |||||
| return getProvider(owner, name) | return getProvider(owner, name) | ||||
| } | } | ||||
| func GetDefaultStorageProvider() (*Provider, error) { | |||||
| provider := Provider{Owner: "admin", Category: "Storage"} | |||||
| existed, err := adapter.engine.Get(&provider) | |||||
| if err != nil { | |||||
| return &provider, err | |||||
| } | |||||
| if !existed { | |||||
| return nil, nil | |||||
| } | |||||
| return &provider, nil | |||||
| } | |||||
| func GetDefaultModelProvider() (*Provider, error) { | func GetDefaultModelProvider() (*Provider, error) { | ||||
| provider := Provider{Owner: "admin", Category: "Model"} | provider := Provider{Owner: "admin", Category: "Model"} | ||||
| existed, err := adapter.engine.Get(&provider) | existed, err := adapter.engine.Get(&provider) | ||||
| @@ -176,6 +191,19 @@ func (provider *Provider) GetId() string { | |||||
| return fmt.Sprintf("%s/%s", provider.Owner, provider.Name) | return fmt.Sprintf("%s/%s", provider.Owner, provider.Name) | ||||
| } | } | ||||
| func (p *Provider) GetStorageProviderObj() (storage.StorageProvider, error) { | |||||
| pProvider, err := storage.GetStorageProvider(p.Type, p.ClientId, p.Name) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if pProvider == nil { | |||||
| return nil, fmt.Errorf("the storage provider type: %s is not supported", p.Type) | |||||
| } | |||||
| return pProvider, nil | |||||
| } | |||||
| func (p *Provider) GetModelProvider() (model.ModelProvider, error) { | func (p *Provider) GetModelProvider() (model.ModelProvider, error) { | ||||
| pProvider, err := model.GetModelProvider(p.Type, p.SubType, p.ClientId, p.ClientSecret) | pProvider, err := model.GetModelProvider(p.Type, p.SubType, p.ClientId, p.ClientSecret) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -17,6 +17,7 @@ package object | |||||
| import ( | import ( | ||||
| "fmt" | "fmt" | ||||
| "github.com/casbin/casibase/storage" | |||||
| "github.com/casbin/casibase/util" | "github.com/casbin/casibase/util" | ||||
| "xorm.io/core" | "xorm.io/core" | ||||
| ) | ) | ||||
| @@ -151,6 +152,26 @@ func (store *Store) GetId() string { | |||||
| return fmt.Sprintf("%s/%s", store.Owner, store.Name) | return fmt.Sprintf("%s/%s", store.Owner, store.Name) | ||||
| } | } | ||||
| func (store *Store) GetStorageProviderObj() (storage.StorageProvider, error) { | |||||
| var provider *Provider | |||||
| var err error | |||||
| if store.StorageProvider == "" { | |||||
| provider, err = GetDefaultStorageProvider() | |||||
| } else { | |||||
| providerId := util.GetIdFromOwnerAndName(store.Owner, store.StorageProvider) | |||||
| provider, err = GetProvider(providerId) | |||||
| } | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if provider != nil { | |||||
| return provider.GetStorageProviderObj() | |||||
| } else { | |||||
| return storage.NewCasdoorProvider(store.StorageProvider) | |||||
| } | |||||
| } | |||||
| func (store *Store) GetEmbeddingProvider() (*Provider, error) { | func (store *Store) GetEmbeddingProvider() (*Provider, error) { | ||||
| if store.EmbeddingProvider == "" { | if store.EmbeddingProvider == "" { | ||||
| return GetDefaultEmbeddingProvider() | return GetDefaultEmbeddingProvider() | ||||
| @@ -161,6 +182,11 @@ func (store *Store) GetEmbeddingProvider() (*Provider, error) { | |||||
| } | } | ||||
| func RefreshStoreVectors(store *Store) (bool, error) { | func RefreshStoreVectors(store *Store) (bool, error) { | ||||
| storageProviderObj, err := store.GetStorageProviderObj() | |||||
| if err != nil { | |||||
| return false, err | |||||
| } | |||||
| embeddingProvider, err := store.GetEmbeddingProvider() | embeddingProvider, err := store.GetEmbeddingProvider() | ||||
| if err != nil { | if err != nil { | ||||
| return false, err | return false, err | ||||
| @@ -171,6 +197,6 @@ func RefreshStoreVectors(store *Store) (bool, error) { | |||||
| return false, err | return false, err | ||||
| } | } | ||||
| ok, err := addVectorsForStore(embeddingProviderObj, store.StorageProvider, "", store.Name) | |||||
| ok, err := addVectorsForStore(storageProviderObj, embeddingProviderObj, "", store.Name) | |||||
| return ok, err | return ok, err | ||||
| } | } | ||||
| @@ -80,7 +80,12 @@ func isObjectLeaf(object *storage.Object) bool { | |||||
| } | } | ||||
| func (store *Store) Populate() error { | func (store *Store) Populate() error { | ||||
| objects, err := storage.ListObjects(store.StorageProvider, "") | |||||
| storageProviderObj, err := store.GetStorageProviderObj() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| objects, err := storageProviderObj.ListObjects("") | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| @@ -125,7 +130,12 @@ func (store *Store) Populate() error { | |||||
| } | } | ||||
| func (store *Store) GetVideoData() ([]string, error) { | func (store *Store) GetVideoData() ([]string, error) { | ||||
| objects, err := storage.ListObjects(store.StorageProvider, "2023/视频附件") | |||||
| storageProviderObj, err := store.GetStorageProviderObj() | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| objects, err := storageProviderObj.ListObjects("2023/视频附件") | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -44,15 +44,6 @@ func filterTextFiles(files []*storage.Object) []*storage.Object { | |||||
| return res | return res | ||||
| } | } | ||||
| func getFilteredFileObjects(provider string, prefix string) ([]*storage.Object, error) { | |||||
| files, err := storage.ListObjects(provider, prefix) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return filterTextFiles(files), nil | |||||
| } | |||||
| func addEmbeddedVector(embeddingProviderObj embedding.EmbeddingProvider, text string, storeName string, fileName string) (bool, error) { | func addEmbeddedVector(embeddingProviderObj embedding.EmbeddingProvider, text string, storeName string, fileName string) (bool, error) { | ||||
| data, err := queryVectorSafe(embeddingProviderObj, text) | data, err := queryVectorSafe(embeddingProviderObj, text) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -77,20 +68,21 @@ func addEmbeddedVector(embeddingProviderObj embedding.EmbeddingProvider, text st | |||||
| return AddVector(vector) | return AddVector(vector) | ||||
| } | } | ||||
| func addVectorsForStore(embeddingProviderObj embedding.EmbeddingProvider, storageProviderName string, key string, storeName string) (bool, error) { | |||||
| func addVectorsForStore(storageProviderObj storage.StorageProvider, embeddingProviderObj embedding.EmbeddingProvider, prefix string, storeName string) (bool, error) { | |||||
| var affected bool | var affected bool | ||||
| var err error | |||||
| objs, err := getFilteredFileObjects(storageProviderName, key) | |||||
| files, err := storageProviderObj.ListObjects(prefix) | |||||
| if err != nil { | if err != nil { | ||||
| return false, err | return false, err | ||||
| } | } | ||||
| files = filterTextFiles(files) | |||||
| timeLimiter := rate.NewLimiter(rate.Every(time.Minute), 3) | timeLimiter := rate.NewLimiter(rate.Every(time.Minute), 3) | ||||
| for _, obj := range objs { | |||||
| for _, file := range files { | |||||
| var text string | var text string | ||||
| fileExt := filepath.Ext(obj.Key) | |||||
| text, err = txt.GetParsedTextFromUrl(obj.Url, fileExt) | |||||
| fileExt := filepath.Ext(file.Key) | |||||
| text, err = txt.GetParsedTextFromUrl(file.Url, fileExt) | |||||
| if err != nil { | if err != nil { | ||||
| return false, err | return false, err | ||||
| } | } | ||||
| @@ -99,7 +91,7 @@ func addVectorsForStore(embeddingProviderObj embedding.EmbeddingProvider, storag | |||||
| for i, textSection := range textSections { | for i, textSection := range textSections { | ||||
| if timeLimiter.Allow() { | if timeLimiter.Allow() { | ||||
| fmt.Printf("[%d/%d] Generating embedding for store: [%s]'s text section: %s\n", i+1, len(textSections), storeName, textSection) | fmt.Printf("[%d/%d] Generating embedding for store: [%s]'s text section: %s\n", i+1, len(textSections), storeName, textSection) | ||||
| affected, err = addEmbeddedVector(embeddingProviderObj, textSection, storeName, obj.Key) | |||||
| affected, err = addEmbeddedVector(embeddingProviderObj, textSection, storeName, file.Key) | |||||
| } else { | } else { | ||||
| err = timeLimiter.Wait(context.Background()) | err = timeLimiter.Wait(context.Background()) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -107,7 +99,7 @@ func addVectorsForStore(embeddingProviderObj embedding.EmbeddingProvider, storag | |||||
| } | } | ||||
| fmt.Printf("[%d/%d] Generating embedding for store: [%s]'s text section: %s\n", i+1, len(textSections), storeName, textSection) | fmt.Printf("[%d/%d] Generating embedding for store: [%s]'s text section: %s\n", i+1, len(textSections), storeName, textSection) | ||||
| affected, err = addEmbeddedVector(embeddingProviderObj, textSection, storeName, obj.Key) | |||||
| affected, err = addEmbeddedVector(embeddingProviderObj, textSection, storeName, file.Key) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -22,21 +22,22 @@ import ( | |||||
| "github.com/casdoor/casdoor-go-sdk/casdoorsdk" | "github.com/casdoor/casdoor-go-sdk/casdoorsdk" | ||||
| ) | ) | ||||
| type Object struct { | |||||
| Key string | |||||
| LastModified string | |||||
| Size int64 | |||||
| Url string | |||||
| type CasdoorProvider struct { | |||||
| providerName string | |||||
| } | } | ||||
| func ListObjects(provider string, prefix string) ([]*Object, error) { | |||||
| if provider == "" { | |||||
| return nil, fmt.Errorf("storage provider is empty") | |||||
| func NewCasdoorProvider(providerName string) (*CasdoorProvider, error) { | |||||
| if providerName == "" { | |||||
| return nil, fmt.Errorf("storage provider name: [%s] doesn't exist", providerName) | |||||
| } | } | ||||
| return &CasdoorProvider{providerName: providerName}, nil | |||||
| } | |||||
| func (p *CasdoorProvider) ListObjects(prefix string) ([]*Object, error) { | |||||
| casdoorOrganization := beego.AppConfig.String("casdoorOrganization") | casdoorOrganization := beego.AppConfig.String("casdoorOrganization") | ||||
| casdoorApplication := beego.AppConfig.String("casdoorApplication") | casdoorApplication := beego.AppConfig.String("casdoorApplication") | ||||
| resources, err := casdoorsdk.GetResources(casdoorOrganization, casdoorApplication, "provider", provider, "Direct", prefix) | |||||
| resources, err := casdoorsdk.GetResources(casdoorOrganization, casdoorApplication, "provider", p.providerName, "Direct", prefix) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -53,24 +54,16 @@ func ListObjects(provider string, prefix string) ([]*Object, error) { | |||||
| return res, nil | return res, nil | ||||
| } | } | ||||
| func PutObject(provider string, user string, parent string, key string, fileBuffer *bytes.Buffer) error { | |||||
| if provider == "" { | |||||
| return fmt.Errorf("storage provider is empty") | |||||
| } | |||||
| _, _, err := casdoorsdk.UploadResource(user, "Casibase", parent, fmt.Sprintf("Direct/%s/%s", provider, key), fileBuffer.Bytes()) | |||||
| func (p *CasdoorProvider) PutObject(user string, parent string, key string, fileBuffer *bytes.Buffer) error { | |||||
| _, _, err := casdoorsdk.UploadResource(user, "Casibase", parent, fmt.Sprintf("Direct/%s/%s", &p.providerName, key), fileBuffer.Bytes()) | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| return nil | return nil | ||||
| } | } | ||||
| func DeleteObject(provider string, key string) error { | |||||
| if provider == "" { | |||||
| return fmt.Errorf("storage provider is empty") | |||||
| } | |||||
| _, err := casdoorsdk.DeleteResource(fmt.Sprintf("Direct/%s/%s", provider, key)) | |||||
| func (p *CasdoorProvider) DeleteObject(key string) error { | |||||
| _, err := casdoorsdk.DeleteResource(fmt.Sprintf("Direct/%s/%s", p.providerName, key)) | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| @@ -0,0 +1,85 @@ | |||||
| // Copyright 2023 The casbin Authors. All Rights Reserved. | |||||
| // | |||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| // you may not use this file except in compliance with the License. | |||||
| // You may obtain a copy of the License at | |||||
| // | |||||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||||
| // | |||||
| // Unless required by applicable law or agreed to in writing, software | |||||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| // See the License for the specific language governing permissions and | |||||
| // limitations under the License. | |||||
| package storage | |||||
| import ( | |||||
| "bytes" | |||||
| "fmt" | |||||
| "io" | |||||
| "os" | |||||
| "path/filepath" | |||||
| "strings" | |||||
| "time" | |||||
| ) | |||||
| type LocalFileSystemStorageProvider struct { | |||||
| path string | |||||
| } | |||||
| func NewLocalFileSystemStorageProvider(path string) (*LocalFileSystemStorageProvider, error) { | |||||
| path = strings.ReplaceAll(path, "\\", "/") | |||||
| return &LocalFileSystemStorageProvider{path: path}, nil | |||||
| } | |||||
| func (p *LocalFileSystemStorageProvider) ListObjects(prefix string) ([]*Object, error) { | |||||
| objects := []*Object{} | |||||
| fullPath := p.path | |||||
| filepath.Walk(fullPath, func(path string, info os.FileInfo, err error) error { | |||||
| if path == fullPath { | |||||
| return nil | |||||
| } | |||||
| base := filepath.Base(path) | |||||
| if info.IsDir() && (strings.HasPrefix(base, ".") || base == "node_modules") { | |||||
| return filepath.SkipDir | |||||
| } | |||||
| if err == nil && !info.IsDir() { | |||||
| modTime := info.ModTime() | |||||
| path = strings.ReplaceAll(path, "\\", "/") | |||||
| relativePath := strings.TrimPrefix(path, fullPath) | |||||
| relativePath = strings.TrimPrefix(relativePath, "/") | |||||
| objects = append(objects, &Object{ | |||||
| Key: relativePath, | |||||
| LastModified: modTime.Format(time.RFC3339), | |||||
| Size: info.Size(), | |||||
| Url: "", | |||||
| }) | |||||
| } | |||||
| return nil | |||||
| }) | |||||
| return objects, nil | |||||
| } | |||||
| func (p *LocalFileSystemStorageProvider) PutObject(user string, parent string, key string, fileBuffer *bytes.Buffer) error { | |||||
| fullPath := p.path | |||||
| err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm) | |||||
| if err != nil { | |||||
| return fmt.Errorf("Casdoor fails to create folder: \"%s\" for local file system storage provider: %s. Make sure Casdoor process has correct permission to create/access it, or you can create it manually in advance", filepath.Dir(fullPath), err.Error()) | |||||
| } | |||||
| dst, err := os.Create(filepath.Clean(fullPath)) | |||||
| if err == nil { | |||||
| _, err = io.Copy(dst, fileBuffer) | |||||
| } | |||||
| return err | |||||
| } | |||||
| func (p *LocalFileSystemStorageProvider) DeleteObject(key string) error { | |||||
| return os.Remove(filepath.Join(p.path, key)) | |||||
| } | |||||
| @@ -0,0 +1,45 @@ | |||||
| // Copyright 2023 The casbin Authors. All Rights Reserved. | |||||
| // | |||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| // you may not use this file except in compliance with the License. | |||||
| // You may obtain a copy of the License at | |||||
| // | |||||
| // http://www.apache.org/licenses/LICENSE-2.0 | |||||
| // | |||||
| // Unless required by applicable law or agreed to in writing, software | |||||
| // distributed under the License is distributed on an "AS IS" BASIS, | |||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| // See the License for the specific language governing permissions and | |||||
| // limitations under the License. | |||||
| package storage | |||||
| import "bytes" | |||||
| type Object struct { | |||||
| Key string | |||||
| LastModified string | |||||
| Size int64 | |||||
| Url string | |||||
| } | |||||
| type StorageProvider interface { | |||||
| ListObjects(prefix string) ([]*Object, error) | |||||
| PutObject(user string, parent string, key string, fileBuffer *bytes.Buffer) error | |||||
| DeleteObject(key string) error | |||||
| } | |||||
| func GetStorageProvider(typ string, clientId string, providerName string) (StorageProvider, error) { | |||||
| var p StorageProvider | |||||
| var err error | |||||
| if typ == "Local File System" { | |||||
| p, err = NewLocalFileSystemStorageProvider(clientId) | |||||
| } else { | |||||
| p, err = NewCasdoorProvider(providerName) | |||||
| } | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return p, nil | |||||
| } | |||||
| @@ -31,7 +31,8 @@ func TestStorage(t *testing.T) { | |||||
| controllers.InitAuthConfig() | controllers.InitAuthConfig() | ||||
| provider := "provider_storage_casibase" | provider := "provider_storage_casibase" | ||||
| objects, err := storage.ListObjects(provider, "") | |||||
| providerObj, err := storage.NewCasdoorProvider(provider) | |||||
| objects, err := providerObj.ListObjects("") | |||||
| if err != nil { | if err != nil { | ||||
| panic(err) | panic(err) | ||||
| } | } | ||||
| @@ -101,6 +101,7 @@ class ProviderEditPage extends React.Component { | |||||
| <Select virtual={false} style={{width: "100%"}} value={this.state.provider.category} onChange={(value => {this.updateProviderField("category", value);})}> | <Select virtual={false} style={{width: "100%"}} value={this.state.provider.category} onChange={(value => {this.updateProviderField("category", value);})}> | ||||
| { | { | ||||
| [ | [ | ||||
| {id: "Storage", name: "Storage"}, | |||||
| {id: "Model", name: "Model"}, | {id: "Model", name: "Model"}, | ||||
| {id: "Embedding", name: "Embedding"}, | {id: "Embedding", name: "Embedding"}, | ||||
| ].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>) | ].map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>) | ||||
| @@ -122,25 +123,31 @@ class ProviderEditPage extends React.Component { | |||||
| </Select> | </Select> | ||||
| </Col> | </Col> | ||||
| </Row> | </Row> | ||||
| <Row style={{marginTop: "20px"}} > | |||||
| <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
| {i18next.t("provider:Sub type")}: | |||||
| </Col> | |||||
| <Col span={22} > | |||||
| <Select virtual={false} style={{width: "100%"}} value={this.state.provider.subType} onChange={(value => {this.updateProviderField("subType", value);})}> | |||||
| { | |||||
| Setting.getProviderSubTypeOptions(this.state.provider.category, this.state.provider.type) | |||||
| // .sort((a, b) => a.name.localeCompare(b.name)) | |||||
| .map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>) | |||||
| } | |||||
| </Select> | |||||
| </Col> | |||||
| </Row> | |||||
| { | { | ||||
| this.state.provider.type !== "Ernie" ? null : ( | |||||
| this.state.provider.category === "Storage" ? null : ( | |||||
| <Row style={{marginTop: "20px"}} > | <Row style={{marginTop: "20px"}} > | ||||
| <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | ||||
| {i18next.t("provider:API key")}: | |||||
| {i18next.t("provider:Sub type")}: | |||||
| </Col> | |||||
| <Col span={22} > | |||||
| <Select virtual={false} style={{width: "100%"}} value={this.state.provider.subType} onChange={(value => {this.updateProviderField("subType", value);})}> | |||||
| { | |||||
| Setting.getProviderSubTypeOptions(this.state.provider.category, this.state.provider.type) | |||||
| // .sort((a, b) => a.name.localeCompare(b.name)) | |||||
| .map((item, index) => <Option key={index} value={item.id}>{item.name}</Option>) | |||||
| } | |||||
| </Select> | |||||
| </Col> | |||||
| </Row> | |||||
| ) | |||||
| } | |||||
| { | |||||
| (this.state.provider.type !== "Ernie" && this.state.provider.category !== "Storage") ? null : ( | |||||
| <Row style={{marginTop: "20px"}} > | |||||
| <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
| { | |||||
| (this.state.provider.category !== "Storage") ? i18next.t("provider:API key") : | |||||
| i18next.t("provider:Path")}: | |||||
| </Col> | </Col> | ||||
| <Col span={22} > | <Col span={22} > | ||||
| <Input value={this.state.provider.clientId} onChange={e => { | <Input value={this.state.provider.clientId} onChange={e => { | ||||
| @@ -150,16 +157,20 @@ class ProviderEditPage extends React.Component { | |||||
| </Row> | </Row> | ||||
| ) | ) | ||||
| } | } | ||||
| <Row style={{marginTop: "20px"}} > | |||||
| <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
| {i18next.t("provider:Secret key")}: | |||||
| </Col> | |||||
| <Col span={22} > | |||||
| <Input value={this.state.provider.clientSecret} onChange={e => { | |||||
| this.updateProviderField("clientSecret", e.target.value); | |||||
| }} /> | |||||
| </Col> | |||||
| </Row> | |||||
| { | |||||
| this.state.provider.category === "Storage" ? null : ( | |||||
| <Row style={{marginTop: "20px"}} > | |||||
| <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | |||||
| {i18next.t("provider:Secret key")}: | |||||
| </Col> | |||||
| <Col span={22} > | |||||
| <Input value={this.state.provider.clientSecret} onChange={e => { | |||||
| this.updateProviderField("clientSecret", e.target.value); | |||||
| }} /> | |||||
| </Col> | |||||
| </Row> | |||||
| ) | |||||
| } | |||||
| <Row style={{marginTop: "20px"}} > | <Row style={{marginTop: "20px"}} > | ||||
| <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> | ||||
| {i18next.t("general:Provider URL")}: | {i18next.t("general:Provider URL")}: | ||||
| @@ -103,7 +103,7 @@ class ProviderListPage extends React.Component { | |||||
| title: i18next.t("general:Name"), | title: i18next.t("general:Name"), | ||||
| dataIndex: "name", | dataIndex: "name", | ||||
| key: "name", | key: "name", | ||||
| width: "160px", | |||||
| width: "180px", | |||||
| sorter: (a, b) => a.name.localeCompare(b.name), | sorter: (a, b) => a.name.localeCompare(b.name), | ||||
| render: (text, record, index) => { | render: (text, record, index) => { | ||||
| return ( | return ( | ||||
| @@ -131,7 +131,7 @@ class ProviderListPage extends React.Component { | |||||
| title: i18next.t("provider:Type"), | title: i18next.t("provider:Type"), | ||||
| dataIndex: "type", | dataIndex: "type", | ||||
| key: "type", | key: "type", | ||||
| width: "120px", | |||||
| width: "150px", | |||||
| sorter: (a, b) => a.type.localeCompare(b.type), | sorter: (a, b) => a.type.localeCompare(b.type), | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -145,7 +145,7 @@ class ProviderListPage extends React.Component { | |||||
| title: i18next.t("provider:API key"), | title: i18next.t("provider:API key"), | ||||
| dataIndex: "clientId", | dataIndex: "clientId", | ||||
| key: "clientId", | key: "clientId", | ||||
| width: "160px", | |||||
| width: "240px", | |||||
| sorter: (a, b) => a.clientId.localeCompare(b.clientId), | sorter: (a, b) => a.clientId.localeCompare(b.clientId), | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -625,7 +625,13 @@ export function isResponseDenied(data) { | |||||
| } | } | ||||
| export function getProviderTypeOptions(category) { | export function getProviderTypeOptions(category) { | ||||
| if (category === "Model") { | |||||
| if (category === "Storage") { | |||||
| return ( | |||||
| [ | |||||
| {id: "Local File System", name: "Local File System"}, | |||||
| ] | |||||
| ); | |||||
| } else if (category === "Model") { | |||||
| return ( | return ( | ||||
| [ | [ | ||||
| {id: "OpenAI", name: "OpenAI"}, | {id: "OpenAI", name: "OpenAI"}, | ||||