mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-10-29 00:55:51 +08:00
228 lines
6.4 KiB
Go
228 lines
6.4 KiB
Go
package plg_backend_dropbox
|
|
|
|
import (
|
|
"encoding/json"
|
|
. "github.com/mickael-kerjean/filestash/server/common"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func init() {
|
|
Backend.Register("dropbox", Dropbox{})
|
|
}
|
|
|
|
type Dropbox struct {
|
|
ClientId string
|
|
Hostname string
|
|
Bearer string
|
|
}
|
|
|
|
func (d Dropbox) Init(params map[string]string, app *App) (IBackend, error) {
|
|
backend := &Dropbox{}
|
|
if env := os.Getenv("DROPBOX_CLIENT_ID"); env != "" {
|
|
backend.ClientId = env
|
|
} else {
|
|
backend.ClientId = Config.Get("auth.dropbox.client_id").Default("").String()
|
|
}
|
|
backend.Hostname = Config.Get("general.host").String()
|
|
backend.Bearer = params["access_token"]
|
|
|
|
if backend.ClientId == "" {
|
|
return backend, NewError("Missing ClientID: Contact your admin", 502)
|
|
} else if backend.Hostname == "" {
|
|
return backend, NewError("Missing Hostname: Contact your admin", 502)
|
|
}
|
|
return backend, nil
|
|
}
|
|
|
|
func (d Dropbox) LoginForm() Form {
|
|
return Form{
|
|
Elmnts: []FormElement{
|
|
FormElement{
|
|
Name: "type",
|
|
Type: "hidden",
|
|
Value: "dropbox",
|
|
},
|
|
FormElement{
|
|
ReadOnly: true,
|
|
Name: "oauth2",
|
|
Type: "text",
|
|
Value: "/api/session/auth/dropbox",
|
|
},
|
|
FormElement{
|
|
ReadOnly: true,
|
|
Name: "image",
|
|
Type: "image",
|
|
Value: "data:image/svg+xml;utf8;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDIuNCAzOS41IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4KICA8cG9seWdvbiBmaWxsPSIjMDA3RUU1IiBwb2ludHM9IjEyLjUsMCAwLDguMSA4LjcsMTUuMSAyMS4yLDcuMyIvPgo8cG9seWdvbiBmaWxsPSIjMDA3RUU1IiBwb2ludHM9IjAsMjEuOSAxMi41LDMwLjEgMjEuMiwyMi44IDguNywxNS4xIi8+Cjxwb2x5Z29uIGZpbGw9IiMwMDdFRTUiIHBvaW50cz0iMjEuMiwyMi44IDMwLDMwLjEgNDIuNCwyMiAzMy44LDE1LjEiLz4KPHBvbHlnb24gZmlsbD0iIzAwN0VFNSIgcG9pbnRzPSI0Mi40LDguMSAzMCwwIDIxLjIsNy4zIDMzLjgsMTUuMSIvPgo8cG9seWdvbiBmaWxsPSIjMDA3RUU1IiBwb2ludHM9IjIxLjMsMjQuNCAxMi41LDMxLjcgOC44LDI5LjIgOC44LDMyIDIxLjMsMzkuNSAzMy44LDMyIDMzLjgsMjkuMiAzMCwzMS43Ii8+Cjwvc3ZnPgo=",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (d Dropbox) OAuthURL() string {
|
|
url := "https://www.dropbox.com/oauth2/authorize?"
|
|
url += "client_id=" + d.ClientId
|
|
url += "&redirect_uri=https://" + d.Hostname + "/login"
|
|
url += "&response_type=token"
|
|
return url
|
|
}
|
|
|
|
func (d Dropbox) Ls(path string) ([]os.FileInfo, error) {
|
|
files := make([]os.FileInfo, 0)
|
|
|
|
args := struct {
|
|
Path string `json:"path"`
|
|
Recursive bool `json:"recursive"`
|
|
IncludeDeleted bool `json:"include_deleted"`
|
|
IncludeMediaInfo bool `json:"include_media_info"`
|
|
}{d.path(path), false, false, true}
|
|
res, err := d.request("POST", "https://api.dropboxapi.com/2/files/list_folder", d.toReader(args), nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer res.Body.Close()
|
|
if res.StatusCode >= 400 {
|
|
return nil, NewError(HTTPFriendlyStatus(res.StatusCode)+": can't get things in"+filepath.Base(path), res.StatusCode)
|
|
}
|
|
|
|
var r struct {
|
|
Files []struct {
|
|
Type string `json:".tag"`
|
|
Name string `json:"name"`
|
|
Time time.Time `json:"client_modified"`
|
|
Size uint `json:"size"`
|
|
} `json:"entries"`
|
|
}
|
|
decoder := json.NewDecoder(res.Body)
|
|
decoder.Decode(&r)
|
|
|
|
for _, obj := range r.Files {
|
|
files = append(files, File{
|
|
FName: obj.Name,
|
|
FType: func(p string) string {
|
|
if p == "folder" {
|
|
return "directory"
|
|
}
|
|
return "file"
|
|
}(obj.Type),
|
|
FTime: obj.Time.UnixNano() / 1000,
|
|
FSize: int64(obj.Size),
|
|
})
|
|
}
|
|
return files, nil
|
|
}
|
|
|
|
func (d Dropbox) Cat(path string) (io.ReadCloser, error) {
|
|
res, err := d.request("POST", "https://content.dropboxapi.com/2/files/download", nil, func(req *http.Request) {
|
|
arg := struct {
|
|
Path string `json:"path"`
|
|
}{d.path(path)}
|
|
json, _ := io.ReadAll(d.toReader(arg))
|
|
req.Header.Set("Dropbox-API-Arg", string(json))
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return res.Body, nil
|
|
}
|
|
|
|
func (d Dropbox) Mkdir(path string) error {
|
|
args := struct {
|
|
Path string `json:"path"`
|
|
Autorename bool `json:"autorename"`
|
|
}{d.path(path), false}
|
|
res, err := d.request("POST", "https://api.dropboxapi.com/2/files/create_folder_v2", d.toReader(args), nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res.Body.Close()
|
|
if res.StatusCode >= 400 {
|
|
return NewError(HTTPFriendlyStatus(res.StatusCode)+": can't create "+filepath.Base(path), res.StatusCode)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d Dropbox) Rm(path string) error {
|
|
args := struct {
|
|
Path string `json:"path"`
|
|
}{d.path(path)}
|
|
res, err := d.request("POST", "https://api.dropboxapi.com/2/files/delete_v2", d.toReader(args), nil)
|
|
if res.StatusCode >= 400 {
|
|
return NewError(HTTPFriendlyStatus(res.StatusCode)+": can't remove "+filepath.Base(path), res.StatusCode)
|
|
}
|
|
res.Body.Close()
|
|
return err
|
|
}
|
|
|
|
func (d Dropbox) Mv(from string, to string) error {
|
|
args := struct {
|
|
FromPath string `json:"from_path"`
|
|
ToPath string `json:"to_path"`
|
|
}{d.path(from), d.path(to)}
|
|
res, err := d.request("POST", "https://api.dropboxapi.com/2/files/move_v2", d.toReader(args), nil)
|
|
if res.StatusCode >= 400 {
|
|
return NewError(HTTPFriendlyStatus(res.StatusCode)+": can't do that", res.StatusCode)
|
|
}
|
|
res.Body.Close()
|
|
return err
|
|
}
|
|
|
|
func (d Dropbox) Touch(path string) error {
|
|
return d.Save(path, strings.NewReader(""))
|
|
}
|
|
|
|
func (d Dropbox) Save(path string, file io.Reader) error {
|
|
res, err := d.request("POST", "https://content.dropboxapi.com/2/files/upload", file, func(req *http.Request) {
|
|
arg := struct {
|
|
Path string `json:"path"`
|
|
AutoRename bool `json:"autorename"`
|
|
Mode string `json:"mode"`
|
|
}{d.path(path), false, "overwrite"}
|
|
json, _ := io.ReadAll(d.toReader(arg))
|
|
req.Header.Set("Dropbox-API-Arg", string(json))
|
|
req.Header.Set("Content-Type", "application/octet-stream")
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res.Body.Close()
|
|
if res.StatusCode >= 400 {
|
|
return NewError(HTTPFriendlyStatus(res.StatusCode)+": can't do that", res.StatusCode)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (d Dropbox) request(method string, url string, body io.Reader, fn func(*http.Request)) (*http.Response, error) {
|
|
req, err := http.NewRequest(method, url, body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Authorization", "Bearer "+d.Bearer)
|
|
if fn == nil {
|
|
req.Header.Set("Content-Type", "application/json")
|
|
} else {
|
|
fn(req)
|
|
}
|
|
if req.Body != nil {
|
|
defer req.Body.Close()
|
|
}
|
|
return HTTPClient.Do(req)
|
|
}
|
|
|
|
func (d Dropbox) toReader(a interface{}) io.Reader {
|
|
j, err := json.Marshal(a)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return strings.NewReader(string(j))
|
|
}
|
|
|
|
func (d Dropbox) path(path string) string {
|
|
return regexp.MustCompile(`\/$`).ReplaceAllString(path, "")
|
|
}
|