mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 02:35:49 +08:00
feat: add local file system storage provider (#224)
Signed-off-by: sh1luo <690898835@qq.com>
This commit is contained in:
parent
44150a6781
commit
c55fa4f452
1
.gitignore
vendored
1
.gitignore
vendored
@ -22,5 +22,6 @@ tmp/
|
||||
tmpFiles/
|
||||
*.tmp
|
||||
logs/
|
||||
files/
|
||||
lastupdate.tmp
|
||||
commentsRouter*.go
|
||||
|
@ -256,13 +256,13 @@ func (c *ApiController) UploadAvatar() {
|
||||
}
|
||||
|
||||
dist, _ := base64.StdEncoding.DecodeString(avatarBase64[index+1:])
|
||||
err := object.UploadAvatar(provider, user.GetId(), dist)
|
||||
fileUrl, err := object.UploadAvatar(provider, user.GetId(), dist)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
user.Avatar = fmt.Sprintf("%s/%s.png?time=%s", util.UrlJoin(provider.Domain, "/avatar"), user.GetId(), util.GetCurrentUnixTime())
|
||||
user.Avatar = fileUrl
|
||||
object.UpdateUser(user.GetId(), user)
|
||||
|
||||
resp = Response{Status: "ok", Msg: ""}
|
||||
|
1
main.go
1
main.go
@ -45,6 +45,7 @@ func main() {
|
||||
beego.SetStaticPath("/static", "web/build/static")
|
||||
beego.BConfig.WebConfig.DirectoryIndex = true
|
||||
beego.SetStaticPath("/swagger", "swagger")
|
||||
beego.SetStaticPath("/files", "files")
|
||||
// https://studygolang.com/articles/2303
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.StaticFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
|
||||
|
@ -17,14 +17,16 @@ package object
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casdoor/storage"
|
||||
"github.com/casbin/casdoor/util"
|
||||
)
|
||||
|
||||
func UploadAvatar(provider *Provider, username string, avatar []byte) error {
|
||||
func UploadAvatar(provider *Provider, username string, avatar []byte) (string, error) {
|
||||
storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint)
|
||||
if storageProvider == nil {
|
||||
return fmt.Errorf("the provider type: %s is not supported", provider.Type)
|
||||
return "", fmt.Errorf("the provider type: %s is not supported", provider.Type)
|
||||
}
|
||||
|
||||
if provider.Domain == "" {
|
||||
@ -34,5 +36,22 @@ func UploadAvatar(provider *Provider, username string, avatar []byte) error {
|
||||
|
||||
path := fmt.Sprintf("%s/%s.png", util.UrlJoin(util.GetUrlPath(provider.Domain), "/avatar"), username)
|
||||
_, err := storageProvider.Put(path, bytes.NewReader(avatar))
|
||||
return err
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
host := ""
|
||||
if provider.Type != "Local File System" {
|
||||
// provider.Domain = "https://cdn.casbin.com/casdoor/"
|
||||
host = util.GetUrlHost(provider.Domain)
|
||||
if !strings.HasPrefix(host, "http://") && !strings.HasPrefix(host, "https://") {
|
||||
host = fmt.Sprintf("https://%s", host)
|
||||
}
|
||||
} else {
|
||||
// provider.Domain = "http://localhost:8000" or "https://door.casbin.com"
|
||||
host = util.UrlJoin(provider.Domain, "/files")
|
||||
}
|
||||
|
||||
fileUrl := fmt.Sprintf("%s?time=%s", util.UrlJoin(host, path), util.GetCurrentUnixTime())
|
||||
return fileUrl, nil
|
||||
}
|
||||
|
129
storage/local_file_system.go
Normal file
129
storage/local_file_system.go
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright 2021 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 (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/qor/oss"
|
||||
)
|
||||
|
||||
var baseFolder = "files"
|
||||
|
||||
// FileSystem file system storage
|
||||
type FileSystem struct {
|
||||
Base string
|
||||
}
|
||||
|
||||
// NewFileSystem initialize the local file system storage
|
||||
func NewFileSystem(base string) *FileSystem {
|
||||
absBase, err := filepath.Abs(base)
|
||||
if err != nil {
|
||||
panic("local file system storage's base folder is not initialized")
|
||||
}
|
||||
|
||||
return &FileSystem{Base: absBase}
|
||||
}
|
||||
|
||||
// GetFullPath get full path from absolute/relative path
|
||||
func (fileSystem FileSystem) GetFullPath(path string) string {
|
||||
fullPath := path
|
||||
if !strings.HasPrefix(path, fileSystem.Base) {
|
||||
fullPath, _ = filepath.Abs(filepath.Join(fileSystem.Base, path))
|
||||
}
|
||||
return fullPath
|
||||
}
|
||||
|
||||
// Get receive file with given path
|
||||
func (fileSystem FileSystem) Get(path string) (*os.File, error) {
|
||||
return os.Open(fileSystem.GetFullPath(path))
|
||||
}
|
||||
|
||||
// GetStream get file as stream
|
||||
func (fileSystem FileSystem) GetStream(path string) (io.ReadCloser, error) {
|
||||
return os.Open(fileSystem.GetFullPath(path))
|
||||
}
|
||||
|
||||
// Put store a reader into given path
|
||||
func (fileSystem FileSystem) Put(path string, reader io.Reader) (*oss.Object, error) {
|
||||
var (
|
||||
fullPath = fileSystem.GetFullPath(path)
|
||||
err = os.MkdirAll(filepath.Dir(fullPath), os.ModePerm)
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dst, err := os.Create(fullPath)
|
||||
|
||||
if err == nil {
|
||||
if seeker, ok := reader.(io.ReadSeeker); ok {
|
||||
seeker.Seek(0, 0)
|
||||
}
|
||||
_, err = io.Copy(dst, reader)
|
||||
}
|
||||
|
||||
return &oss.Object{Path: path, Name: filepath.Base(path), StorageInterface: fileSystem}, err
|
||||
}
|
||||
|
||||
// Delete delete file
|
||||
func (fileSystem FileSystem) Delete(path string) error {
|
||||
return os.Remove(fileSystem.GetFullPath(path))
|
||||
}
|
||||
|
||||
// List list all objects under current path
|
||||
func (fileSystem FileSystem) List(path string) ([]*oss.Object, error) {
|
||||
var (
|
||||
objects []*oss.Object
|
||||
fullPath = fileSystem.GetFullPath(path)
|
||||
)
|
||||
|
||||
filepath.Walk(fullPath, func(path string, info os.FileInfo, err error) error {
|
||||
if path == fullPath {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err == nil && !info.IsDir() {
|
||||
modTime := info.ModTime()
|
||||
objects = append(objects, &oss.Object{
|
||||
Path: strings.TrimPrefix(path, fileSystem.Base),
|
||||
Name: info.Name(),
|
||||
LastModified: &modTime,
|
||||
StorageInterface: fileSystem,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return objects, nil
|
||||
}
|
||||
|
||||
// GetEndpoint get endpoint, FileSystem's endpoint is /
|
||||
func (fileSystem FileSystem) GetEndpoint() string {
|
||||
return "/"
|
||||
}
|
||||
|
||||
// GetURL get public accessible URL
|
||||
func (fileSystem FileSystem) GetURL(path string) (url string, err error) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func NewLocalFileSystemStorageProvider(clientId string, clientSecret string, region string, bucket string, endpoint string) oss.StorageInterface {
|
||||
return NewFileSystem(baseFolder)
|
||||
}
|
@ -18,6 +18,8 @@ import "github.com/qor/oss"
|
||||
|
||||
func GetStorageProvider(providerType string, clientId string, clientSecret string, region string, bucket string, endpoint string) oss.StorageInterface {
|
||||
switch providerType {
|
||||
case "Local File System":
|
||||
return NewLocalFileSystemStorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||
case "AWS S3":
|
||||
return NewAwsS3StorageProvider(clientId, clientSecret, region, bucket, endpoint)
|
||||
case "Aliyun OSS":
|
||||
|
@ -29,10 +29,6 @@ func FileExist(path string) bool {
|
||||
}
|
||||
|
||||
func UrlJoin(base string, path string) string {
|
||||
if !strings.HasPrefix(base, "http://") && !strings.HasPrefix(base, "https://") {
|
||||
base = fmt.Sprintf("https://%s", base)
|
||||
}
|
||||
|
||||
res := fmt.Sprintf("%s/%s", strings.TrimRight(base, "/"), strings.TrimLeft(path, "/"))
|
||||
return res
|
||||
}
|
||||
@ -41,3 +37,8 @@ func GetUrlPath(urlString string) string {
|
||||
u, _ := url.Parse(urlString)
|
||||
return u.Path
|
||||
}
|
||||
|
||||
func GetUrlHost(urlString string) string {
|
||||
u, _ := url.Parse(urlString)
|
||||
return fmt.Sprintf("%s://%s", u.Scheme, u.Host)
|
||||
}
|
||||
|
@ -148,7 +148,8 @@ class ProviderEditPage extends React.Component {
|
||||
} else if (value === "SMS") {
|
||||
this.updateProviderField('type', 'Aliyun SMS');
|
||||
} else if (value === "Storage") {
|
||||
this.updateProviderField('type', 'Aliyun OSS');
|
||||
this.updateProviderField('type', 'Local File System');
|
||||
this.updateProviderField('domain', Setting.getFullServerUrl());
|
||||
}
|
||||
})}>
|
||||
{
|
||||
@ -167,7 +168,12 @@ class ProviderEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("provider:Type"), i18next.t("provider:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.provider.type} onChange={(value => {this.updateProviderField('type', value);})}>
|
||||
<Select virtual={false} style={{width: '100%'}} value={this.state.provider.type} onChange={(value => {
|
||||
this.updateProviderField('type', value);
|
||||
if (value === "Local File System") {
|
||||
this.updateProviderField('domain', Setting.getFullServerUrl());
|
||||
}
|
||||
})}>
|
||||
{
|
||||
this.getProviderTypeOptions(this.state.provider).map((providerType, index) => <Option key={index} value={providerType.id}>{providerType.name}</Option>)
|
||||
}
|
||||
|
@ -48,6 +48,14 @@ function isLocalhost() {
|
||||
return hostname === "localhost";
|
||||
}
|
||||
|
||||
export function getFullServerUrl() {
|
||||
let fullServerUrl = window.location.origin;
|
||||
if (fullServerUrl === "http://localhost:7001") {
|
||||
fullServerUrl = "http://localhost:8000";
|
||||
}
|
||||
return fullServerUrl;
|
||||
}
|
||||
|
||||
export function isProviderVisible(providerItem) {
|
||||
if (providerItem.provider === undefined || providerItem.provider === null) {
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user