mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 23:49:15 +01:00
vendor: add github.com/ncw/dropbox-sdk-go-unofficial and remove github.com/stacktic/dropbox
In due course this will become github.com/dropbox/dropbox-sdk-go-unofficial when the fate of https://github.com/dropbox/dropbox-sdk-go-unofficial/pull/14 has been decided.
This commit is contained in:
parent
9d335eb5cb
commit
178ff62d6a
14
Gopkg.lock
generated
14
Gopkg.lock
generated
@ -1,4 +1,4 @@
|
||||
memo = "73fcf12d2ac21c6ada1f1c0d63c636506e4f576081d0509e38d53086f6f67447"
|
||||
memo = "e0227ed773a9f6c56d1bfac9de1d87c2a74ce142e418b661b74931d2e2b20945"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@ -96,6 +96,12 @@ memo = "73fcf12d2ac21c6ada1f1c0d63c636506e4f576081d0509e38d53086f6f67447"
|
||||
packages = ["."]
|
||||
revision = "2788f0dbd16903de03cb8186e5c7d97b69ad387b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/ncw/dropbox-sdk-go-unofficial"
|
||||
packages = ["dropbox","dropbox/async","dropbox/files","dropbox/properties"]
|
||||
revision = "5d9f46f9862ae5f65e264e178de6ce2c41a32d40"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/ncw/go-acd"
|
||||
@ -162,12 +168,6 @@ memo = "73fcf12d2ac21c6ada1f1c0d63c636506e4f576081d0509e38d53086f6f67447"
|
||||
packages = ["."]
|
||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/stacktic/dropbox"
|
||||
packages = ["."]
|
||||
revision = "58f839b21094d5e0af7caf613599830589233d20"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/stretchr/testify"
|
||||
|
@ -134,3 +134,7 @@
|
||||
[[dependencies]]
|
||||
branch = "master"
|
||||
name = "google.golang.org/api"
|
||||
|
||||
[[dependencies]]
|
||||
branch = "master"
|
||||
name = "github.com/ncw/dropbox-sdk-go-unofficial"
|
||||
|
@ -28,8 +28,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dropbox/dropbox-sdk-go-unofficial/dropbox"
|
||||
"github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/files"
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox/files"
|
||||
"github.com/ncw/rclone/fs"
|
||||
"github.com/ncw/rclone/oauthutil"
|
||||
"github.com/ncw/rclone/pacer"
|
||||
@ -50,10 +50,11 @@ var (
|
||||
// Description of how to auth for this app
|
||||
dropboxConfig = &oauth2.Config{
|
||||
Scopes: []string{},
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: "https://www.dropbox.com/1/oauth2/authorize",
|
||||
TokenURL: "https://api.dropboxapi.com/1/oauth2/token",
|
||||
}, // FIXME replace with this once vendored dropbox.OAuthEndpoint(""),
|
||||
// Endpoint: oauth2.Endpoint{
|
||||
// AuthURL: "https://www.dropbox.com/1/oauth2/authorize",
|
||||
// TokenURL: "https://api.dropboxapi.com/1/oauth2/token",
|
||||
// },
|
||||
Endpoint: dropbox.OAuthEndpoint(""),
|
||||
ClientID: rcloneClientID,
|
||||
ClientSecret: fs.MustReveal(rcloneEncryptedClientSecret),
|
||||
RedirectURL: oauthutil.RedirectLocalhostURL,
|
||||
|
6
vendor/github.com/ncw/dropbox-sdk-go-unofficial/.gitignore
generated
vendored
Normal file
6
vendor/github.com/ncw/dropbox-sdk-go-unofficial/.gitignore
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# swap
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
|
||||
.pyc
|
||||
__pycache__
|
3
vendor/github.com/ncw/dropbox-sdk-go-unofficial/.gitmodules
generated
vendored
Normal file
3
vendor/github.com/ncw/dropbox-sdk-go-unofficial/.gitmodules
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "generator/dropbox-api-spec"]
|
||||
path = generator/dropbox-api-spec
|
||||
url = https://github.com/dropbox/dropbox-api-spec
|
15
vendor/github.com/ncw/dropbox-sdk-go-unofficial/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/ncw/dropbox-sdk-go-unofficial/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.6.4
|
||||
- 1.7.5
|
||||
- 1.8
|
||||
|
||||
install:
|
||||
- go get -u golang.org/x/oauth2
|
||||
|
||||
before_script:
|
||||
- go get -u github.com/mitchellh/gox
|
||||
|
||||
script:
|
||||
- gox -osarch="darwin/amd64 linux/amd64 windows/amd64" ./dropbox/...
|
20
vendor/github.com/ncw/dropbox-sdk-go-unofficial/LICENSE
generated
vendored
Normal file
20
vendor/github.com/ncw/dropbox-sdk-go-unofficial/LICENSE
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2009-2016 Dropbox Inc., http://www.dropbox.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
95
vendor/github.com/ncw/dropbox-sdk-go-unofficial/README.md
generated
vendored
Normal file
95
vendor/github.com/ncw/dropbox-sdk-go-unofficial/README.md
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
# Dropbox SDK for Go [UNOFFICIAL] [![GoDoc](https://godoc.org/github.com/dropbox/dropbox-sdk-go-unofficial/dropbox?status.svg)](https://godoc.org/github.com/dropbox/dropbox-sdk-go-unofficial/dropbox) [![Build Status](https://travis-ci.org/dropbox/dropbox-sdk-go-unofficial.svg?branch=master)](https://travis-ci.org/dropbox/dropbox-sdk-go-unofficial)
|
||||
|
||||
An **UNOFFICIAL** Go SDK for integrating with the Dropbox API v2. Tested with Go 1.5+
|
||||
|
||||
:warning: WARNING: This SDK is **NOT yet official**. What does this mean?
|
||||
|
||||
* There is no formal Dropbox [support](https://www.dropbox.com/developers/support) for this SDK at this point
|
||||
* Bugs may or may not get fixed
|
||||
* Not all SDK features may be implemented and implemented features may be buggy or incorrect
|
||||
|
||||
|
||||
### Uh OK, so why are you releasing this?
|
||||
|
||||
* the SDK, while unofficial, _is_ usable. See [dbxcli](https://github.com/dropbox/dbxcli) for an example application built using the SDK
|
||||
* we would like to get feedback from the community and evaluate the level of interest/enthusiasm before investing into official supporting one more SDK
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ go get github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/...
|
||||
```
|
||||
|
||||
For most applications, you should just import the relevant namespace(s) only. The SDK exports the following sub-packages:
|
||||
|
||||
* `github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/auth`
|
||||
* `github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/files`
|
||||
* `github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/sharing`
|
||||
* `github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/team`
|
||||
* `github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/users`
|
||||
|
||||
Additionally, the base `github.com/dropbox/dropbox-sdk-go-unofficial/dropbox` package exports some configuration and helper methods.
|
||||
|
||||
## Usage
|
||||
|
||||
First, you need to [register a new "app"](https://dropbox.com/developers/apps) to start making API requests. Once you have created an app, you can either use the SDK via an access token (useful for testing) or via the regular OAuth2 flow (recommended for production).
|
||||
|
||||
### Using OAuth token
|
||||
|
||||
Once you've created an app, you can get an access token from the app's console. Note that this token will only work for the Dropbox account the token is associated with.
|
||||
|
||||
```go
|
||||
import "github.com/dropbox/dropbox-sdk-go-unofficial/dropbox"
|
||||
import "github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/users"
|
||||
|
||||
func main() {
|
||||
config := dropbox.Config{Token: token, Verbose: true} // second arg enables verbose logging in the SDK
|
||||
dbx := users.New(config)
|
||||
// start making API calls
|
||||
}
|
||||
```
|
||||
|
||||
### Using OAuth2 flow
|
||||
|
||||
For this, you will need your `APP_KEY` and `APP_SECRET` from the developers console. Your app will then have to take users though the oauth flow, as part of which users will explicitly grant permissions to your app. At the end of this process, users will get a token that the app can then use for subsequent authentication. See [this](https://godoc.org/golang.org/x/oauth2#example-Config) for an example of oauth2 flow in Go.
|
||||
|
||||
Once you have the token, usage is same as above.
|
||||
|
||||
### Making API calls
|
||||
|
||||
Each Dropbox API takes in a request type and returns a response type. For instance, [/users/get_account](https://www.dropbox.com/developers/documentation/http/documentation#users-get_account) takes as input a `GetAccountArg` and returns a `BasicAccount`. The typical pattern for making API calls is:
|
||||
|
||||
* Instantiate the argument via the `New*` convenience functions in the SDK
|
||||
* Invoke the API
|
||||
* Process the response (or handle error, as below)
|
||||
|
||||
Here's an example:
|
||||
|
||||
```go
|
||||
arg := users.NewGetAccountArg(accountId)
|
||||
if resp, err := dbx.GetAccount(arg); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Name: %v", resp.Name)
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
As described in the [API docs](https://www.dropbox.com/developers/documentation/http/documentation#error-handling), all HTTP errors _except_ 409 are returned as-is to the client (with a helpful text message where possible). In case of a 409, the SDK will return an endpoint-specific error as described in the API. This will be made available as `EndpointError` member in the error.
|
||||
|
||||
## Note on using the Teams API
|
||||
|
||||
To use the Team API, you will need to create a Dropbox Business App. The OAuth token from this app will _only_ work for the Team API.
|
||||
|
||||
Please read the [API docs](https://www.dropbox.com/developers/documentation/http/teams) carefully to appropriate secure your apps and tokens when using the Team API.
|
||||
|
||||
## Code Generation
|
||||
|
||||
This SDK is automatically generated using the public [Dropbox API spec](https://github.com/dropbox/dropbox-api-spec) and [Stone](https://github.com/dropbox/stone). See this [README](https://github.com/dropbox/dropbox-sdk-go-unofficial/blob/master/generator/README.md)
|
||||
for more details on how code is generated.
|
||||
|
||||
## Caveats
|
||||
|
||||
* To re-iterate, this is an **UNOFFICIAL** SDK and thus has no official support from Dropbox
|
||||
* Only supports the v2 API. Parts of the v2 API are still in beta, and thus subject to change
|
||||
* This SDK itself is in beta, and so interfaces may change at any point
|
132
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/async/types.go
generated
vendored
Normal file
132
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/async/types.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package async : has no documentation (yet)
|
||||
package async
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
)
|
||||
|
||||
// LaunchResultBase : Result returned by methods that launch an asynchronous
|
||||
// job. A method who may either launch an asynchronous job, or complete the
|
||||
// request synchronously, can use this union by extending it, and adding a
|
||||
// 'complete' field with the type of the synchronous response. See
|
||||
// `LaunchEmptyResult` for an example.
|
||||
type LaunchResultBase struct {
|
||||
dropbox.Tagged
|
||||
// AsyncJobId : This response indicates that the processing is asynchronous.
|
||||
// The string is an id that can be used to obtain the status of the
|
||||
// asynchronous job.
|
||||
AsyncJobId string `json:"async_job_id,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for LaunchResultBase
|
||||
const (
|
||||
LaunchResultBaseAsyncJobId = "async_job_id"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a LaunchResultBase instance
|
||||
func (u *LaunchResultBase) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "async_job_id":
|
||||
err = json.Unmarshal(body, &u.AsyncJobId)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LaunchEmptyResult : Result returned by methods that may either launch an
|
||||
// asynchronous job or complete synchronously. Upon synchronous completion of
|
||||
// the job, no additional information is returned.
|
||||
type LaunchEmptyResult struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for LaunchEmptyResult
|
||||
const (
|
||||
LaunchEmptyResultComplete = "complete"
|
||||
)
|
||||
|
||||
// PollArg : Arguments for methods that poll the status of an asynchronous job.
|
||||
type PollArg struct {
|
||||
// AsyncJobId : Id of the asynchronous job. This is the value of a response
|
||||
// returned from the method that launched the job.
|
||||
AsyncJobId string `json:"async_job_id"`
|
||||
}
|
||||
|
||||
// NewPollArg returns a new PollArg instance
|
||||
func NewPollArg(AsyncJobId string) *PollArg {
|
||||
s := new(PollArg)
|
||||
s.AsyncJobId = AsyncJobId
|
||||
return s
|
||||
}
|
||||
|
||||
// PollResultBase : Result returned by methods that poll for the status of an
|
||||
// asynchronous job. Unions that extend this union should add a 'complete' field
|
||||
// with a type of the information returned upon job completion. See
|
||||
// `PollEmptyResult` for an example.
|
||||
type PollResultBase struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for PollResultBase
|
||||
const (
|
||||
PollResultBaseInProgress = "in_progress"
|
||||
)
|
||||
|
||||
// PollEmptyResult : Result returned by methods that poll for the status of an
|
||||
// asynchronous job. Upon completion of the job, no additional information is
|
||||
// returned.
|
||||
type PollEmptyResult struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for PollEmptyResult
|
||||
const (
|
||||
PollEmptyResultComplete = "complete"
|
||||
)
|
||||
|
||||
// PollError : Error returned by methods for polling the status of asynchronous
|
||||
// job.
|
||||
type PollError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for PollError
|
||||
const (
|
||||
PollErrorInvalidAsyncJobId = "invalid_async_job_id"
|
||||
PollErrorInternalError = "internal_error"
|
||||
PollErrorOther = "other"
|
||||
)
|
193
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/auth/client.go
generated
vendored
Normal file
193
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/auth/client.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
)
|
||||
|
||||
// Client interface describes all routes in this namespace
|
||||
type Client interface {
|
||||
// TokenFromOauth1 : Creates an OAuth 2.0 access token from the supplied
|
||||
// OAuth 1.0 access token.
|
||||
TokenFromOauth1(arg *TokenFromOAuth1Arg) (res *TokenFromOAuth1Result, err error)
|
||||
// TokenRevoke : Disables the access token used to authenticate the call.
|
||||
TokenRevoke() (err error)
|
||||
}
|
||||
|
||||
type apiImpl dropbox.Context
|
||||
|
||||
//TokenFromOauth1APIError is an error-wrapper for the token/from_oauth1 route
|
||||
type TokenFromOauth1APIError struct {
|
||||
dropbox.APIError
|
||||
EndpointError *TokenFromOAuth1Error `json:"error"`
|
||||
}
|
||||
|
||||
func (dbx *apiImpl) TokenFromOauth1(arg *TokenFromOAuth1Arg) (res *TokenFromOAuth1Result, err error) {
|
||||
cli := dbx.Client
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("arg: %v", arg)
|
||||
}
|
||||
b, err := json.Marshal(arg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
if dbx.Config.AsMemberID != "" {
|
||||
headers["Dropbox-API-Select-User"] = dbx.Config.AsMemberID
|
||||
}
|
||||
|
||||
req, err := (*dropbox.Context)(dbx).NewRequest("api", "rpc", true, "auth", "token/from_oauth1", headers, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("req: %v", req)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("resp: %v", resp)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("body: %s", body)
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
var apiError TokenFromOauth1APIError
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
var apiError dropbox.APIError
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
apiError.ErrorSummary = string(body)
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
|
||||
//TokenRevokeAPIError is an error-wrapper for the token/revoke route
|
||||
type TokenRevokeAPIError struct {
|
||||
dropbox.APIError
|
||||
EndpointError struct{} `json:"error"`
|
||||
}
|
||||
|
||||
func (dbx *apiImpl) TokenRevoke() (err error) {
|
||||
cli := dbx.Client
|
||||
|
||||
headers := map[string]string{}
|
||||
if dbx.Config.AsMemberID != "" {
|
||||
headers["Dropbox-API-Select-User"] = dbx.Config.AsMemberID
|
||||
}
|
||||
|
||||
req, err := (*dropbox.Context)(dbx).NewRequest("api", "rpc", true, "auth", "token/revoke", headers, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("req: %v", req)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("resp: %v", resp)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("body: %s", body)
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
var apiError TokenRevokeAPIError
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
var apiError dropbox.APIError
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
apiError.ErrorSummary = string(body)
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
|
||||
// New returns a Client implementation for this namespace
|
||||
func New(c dropbox.Config) *apiImpl {
|
||||
ctx := apiImpl(dropbox.NewContext(c))
|
||||
return &ctx
|
||||
}
|
187
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/auth/types.go
generated
vendored
Normal file
187
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/auth/types.go
generated
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package auth : has no documentation (yet)
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
)
|
||||
|
||||
// AccessError : Error occurred because the account doesn't have permission to
|
||||
// access the resource.
|
||||
type AccessError struct {
|
||||
dropbox.Tagged
|
||||
// InvalidAccountType : Current account type cannot access the resource.
|
||||
InvalidAccountType *InvalidAccountTypeError `json:"invalid_account_type,omitempty"`
|
||||
// PaperAccessDenied : Current account cannot access Paper.
|
||||
PaperAccessDenied *PaperAccessError `json:"paper_access_denied,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for AccessError
|
||||
const (
|
||||
AccessErrorInvalidAccountType = "invalid_account_type"
|
||||
AccessErrorPaperAccessDenied = "paper_access_denied"
|
||||
AccessErrorOther = "other"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a AccessError instance
|
||||
func (u *AccessError) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
// InvalidAccountType : Current account type cannot access the resource.
|
||||
InvalidAccountType json.RawMessage `json:"invalid_account_type,omitempty"`
|
||||
// PaperAccessDenied : Current account cannot access Paper.
|
||||
PaperAccessDenied json.RawMessage `json:"paper_access_denied,omitempty"`
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "invalid_account_type":
|
||||
err = json.Unmarshal(w.InvalidAccountType, &u.InvalidAccountType)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "paper_access_denied":
|
||||
err = json.Unmarshal(w.PaperAccessDenied, &u.PaperAccessDenied)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AuthError : Errors occurred during authentication.
|
||||
type AuthError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for AuthError
|
||||
const (
|
||||
AuthErrorInvalidAccessToken = "invalid_access_token"
|
||||
AuthErrorInvalidSelectUser = "invalid_select_user"
|
||||
AuthErrorInvalidSelectAdmin = "invalid_select_admin"
|
||||
AuthErrorUserSuspended = "user_suspended"
|
||||
AuthErrorOther = "other"
|
||||
)
|
||||
|
||||
// InvalidAccountTypeError : has no documentation (yet)
|
||||
type InvalidAccountTypeError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for InvalidAccountTypeError
|
||||
const (
|
||||
InvalidAccountTypeErrorEndpoint = "endpoint"
|
||||
InvalidAccountTypeErrorFeature = "feature"
|
||||
InvalidAccountTypeErrorOther = "other"
|
||||
)
|
||||
|
||||
// PaperAccessError : has no documentation (yet)
|
||||
type PaperAccessError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for PaperAccessError
|
||||
const (
|
||||
PaperAccessErrorPaperDisabled = "paper_disabled"
|
||||
PaperAccessErrorNotPaperUser = "not_paper_user"
|
||||
PaperAccessErrorOther = "other"
|
||||
)
|
||||
|
||||
// RateLimitError : Error occurred because the app is being rate limited.
|
||||
type RateLimitError struct {
|
||||
// Reason : The reason why the app is being rate limited.
|
||||
Reason *RateLimitReason `json:"reason"`
|
||||
// RetryAfter : The number of seconds that the app should wait before making
|
||||
// another request.
|
||||
RetryAfter uint64 `json:"retry_after"`
|
||||
}
|
||||
|
||||
// NewRateLimitError returns a new RateLimitError instance
|
||||
func NewRateLimitError(Reason *RateLimitReason) *RateLimitError {
|
||||
s := new(RateLimitError)
|
||||
s.Reason = Reason
|
||||
s.RetryAfter = 1
|
||||
return s
|
||||
}
|
||||
|
||||
// RateLimitReason : has no documentation (yet)
|
||||
type RateLimitReason struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for RateLimitReason
|
||||
const (
|
||||
RateLimitReasonTooManyRequests = "too_many_requests"
|
||||
RateLimitReasonTooManyWriteOperations = "too_many_write_operations"
|
||||
RateLimitReasonOther = "other"
|
||||
)
|
||||
|
||||
// TokenFromOAuth1Arg : has no documentation (yet)
|
||||
type TokenFromOAuth1Arg struct {
|
||||
// Oauth1Token : The supplied OAuth 1.0 access token.
|
||||
Oauth1Token string `json:"oauth1_token"`
|
||||
// Oauth1TokenSecret : The token secret associated with the supplied access
|
||||
// token.
|
||||
Oauth1TokenSecret string `json:"oauth1_token_secret"`
|
||||
}
|
||||
|
||||
// NewTokenFromOAuth1Arg returns a new TokenFromOAuth1Arg instance
|
||||
func NewTokenFromOAuth1Arg(Oauth1Token string, Oauth1TokenSecret string) *TokenFromOAuth1Arg {
|
||||
s := new(TokenFromOAuth1Arg)
|
||||
s.Oauth1Token = Oauth1Token
|
||||
s.Oauth1TokenSecret = Oauth1TokenSecret
|
||||
return s
|
||||
}
|
||||
|
||||
// TokenFromOAuth1Error : has no documentation (yet)
|
||||
type TokenFromOAuth1Error struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for TokenFromOAuth1Error
|
||||
const (
|
||||
TokenFromOAuth1ErrorInvalidOauth1TokenInfo = "invalid_oauth1_token_info"
|
||||
TokenFromOAuth1ErrorAppIdMismatch = "app_id_mismatch"
|
||||
TokenFromOAuth1ErrorOther = "other"
|
||||
)
|
||||
|
||||
// TokenFromOAuth1Result : has no documentation (yet)
|
||||
type TokenFromOAuth1Result struct {
|
||||
// Oauth2Token : The OAuth 2.0 token generated from the supplied OAuth 1.0
|
||||
// token.
|
||||
Oauth2Token string `json:"oauth2_token"`
|
||||
}
|
||||
|
||||
// NewTokenFromOAuth1Result returns a new TokenFromOAuth1Result instance
|
||||
func NewTokenFromOAuth1Result(Oauth2Token string) *TokenFromOAuth1Result {
|
||||
s := new(TokenFromOAuth1Result)
|
||||
s.Oauth2Token = Oauth2Token
|
||||
return s
|
||||
}
|
132
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/common/types.go
generated
vendored
Normal file
132
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/common/types.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package common : has no documentation (yet)
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
)
|
||||
|
||||
// InvalidPathRootError : has no documentation (yet)
|
||||
type InvalidPathRootError struct {
|
||||
// PathRoot : The latest path root id for user's team if the user is still
|
||||
// in a team.
|
||||
PathRoot string `json:"path_root,omitempty"`
|
||||
}
|
||||
|
||||
// NewInvalidPathRootError returns a new InvalidPathRootError instance
|
||||
func NewInvalidPathRootError() *InvalidPathRootError {
|
||||
s := new(InvalidPathRootError)
|
||||
return s
|
||||
}
|
||||
|
||||
// PathRoot : has no documentation (yet)
|
||||
type PathRoot struct {
|
||||
dropbox.Tagged
|
||||
// Team : Paths are relative to the given team directory. (This results in
|
||||
// `PathRootError.invalid` if the user is not a member of the team
|
||||
// associated with that path root id.)
|
||||
Team string `json:"team,omitempty"`
|
||||
// SharedFolder : Paths are relative to given shared folder id (This results
|
||||
// in `PathRootError.no_permission` if you don't have access to this shared
|
||||
// folder.)
|
||||
SharedFolder string `json:"shared_folder,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for PathRoot
|
||||
const (
|
||||
PathRootHome = "home"
|
||||
PathRootMemberHome = "member_home"
|
||||
PathRootTeam = "team"
|
||||
PathRootUserHome = "user_home"
|
||||
PathRootSharedFolder = "shared_folder"
|
||||
PathRootOther = "other"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a PathRoot instance
|
||||
func (u *PathRoot) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "team":
|
||||
err = json.Unmarshal(body, &u.Team)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "shared_folder":
|
||||
err = json.Unmarshal(body, &u.SharedFolder)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PathRootError : has no documentation (yet)
|
||||
type PathRootError struct {
|
||||
dropbox.Tagged
|
||||
// Invalid : The path root id value in Dropbox-API-Path-Root header is no
|
||||
// longer valid.
|
||||
Invalid *InvalidPathRootError `json:"invalid,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for PathRootError
|
||||
const (
|
||||
PathRootErrorInvalid = "invalid"
|
||||
PathRootErrorNoPermission = "no_permission"
|
||||
PathRootErrorOther = "other"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a PathRootError instance
|
||||
func (u *PathRootError) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
// Invalid : The path root id value in Dropbox-API-Path-Root header is
|
||||
// no longer valid.
|
||||
Invalid json.RawMessage `json:"invalid,omitempty"`
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "invalid":
|
||||
err = json.Unmarshal(body, &u.Invalid)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
3614
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/files/client.go
generated
vendored
Normal file
3614
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/files/client.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
75
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/files/metadata.go
generated
vendored
Normal file
75
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/files/metadata.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package files
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type listFolderResult struct {
|
||||
Entries []metadataUnion `json:"entries"`
|
||||
Cursor string `json:"cursor"`
|
||||
HasMore bool `json:"has_more"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes into a ListFolderResult instance
|
||||
func (r *ListFolderResult) UnmarshalJSON(b []byte) error {
|
||||
var l listFolderResult
|
||||
if err := json.Unmarshal(b, &l); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Cursor = l.Cursor
|
||||
r.HasMore = l.HasMore
|
||||
r.Entries = make([]IsMetadata, len(l.Entries))
|
||||
for i, e := range l.Entries {
|
||||
switch e.Tag {
|
||||
case "file":
|
||||
r.Entries[i] = e.File
|
||||
case "folder":
|
||||
r.Entries[i] = e.Folder
|
||||
case "deleted":
|
||||
r.Entries[i] = e.Deleted
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type searchMatch struct {
|
||||
MatchType *SearchMatchType `json:"match_type"`
|
||||
Metadata metadataUnion `json:"metadata"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes into a SearchMatch instance
|
||||
func (s *SearchMatch) UnmarshalJSON(b []byte) error {
|
||||
var m searchMatch
|
||||
if err := json.Unmarshal(b, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
s.MatchType = m.MatchType
|
||||
e := m.Metadata
|
||||
switch e.Tag {
|
||||
case "file":
|
||||
s.Metadata = e.File
|
||||
case "folder":
|
||||
s.Metadata = e.Folder
|
||||
case "deleted":
|
||||
s.Metadata = e.Deleted
|
||||
}
|
||||
return nil
|
||||
}
|
2983
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/files/types.go
generated
vendored
Normal file
2983
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/files/types.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1199
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/paper/client.go
generated
vendored
Normal file
1199
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/paper/client.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
729
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/paper/types.go
generated
vendored
Normal file
729
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/paper/types.go
generated
vendored
Normal file
@ -0,0 +1,729 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package paper : This namespace contains endpoints and data types for managing
|
||||
// docs and folders in Dropbox Paper.
|
||||
package paper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sharing"
|
||||
)
|
||||
|
||||
// AddMember : has no documentation (yet)
|
||||
type AddMember struct {
|
||||
// PermissionLevel : Permission for the user.
|
||||
PermissionLevel *PaperDocPermissionLevel `json:"permission_level"`
|
||||
// Member : User which should be added to the Paper doc. Specify only email
|
||||
// address or Dropbox account ID.
|
||||
Member *sharing.MemberSelector `json:"member"`
|
||||
}
|
||||
|
||||
// NewAddMember returns a new AddMember instance
|
||||
func NewAddMember(Member *sharing.MemberSelector) *AddMember {
|
||||
s := new(AddMember)
|
||||
s.Member = Member
|
||||
s.PermissionLevel = &PaperDocPermissionLevel{Tagged: dropbox.Tagged{"edit"}}
|
||||
return s
|
||||
}
|
||||
|
||||
// RefPaperDoc : has no documentation (yet)
|
||||
type RefPaperDoc struct {
|
||||
// DocId : The Paper doc ID.
|
||||
DocId string `json:"doc_id"`
|
||||
}
|
||||
|
||||
// NewRefPaperDoc returns a new RefPaperDoc instance
|
||||
func NewRefPaperDoc(DocId string) *RefPaperDoc {
|
||||
s := new(RefPaperDoc)
|
||||
s.DocId = DocId
|
||||
return s
|
||||
}
|
||||
|
||||
// AddPaperDocUser : has no documentation (yet)
|
||||
type AddPaperDocUser struct {
|
||||
RefPaperDoc
|
||||
// Members : User which should be added to the Paper doc. Specify only email
|
||||
// address or Dropbox account ID.
|
||||
Members []*AddMember `json:"members"`
|
||||
// CustomMessage : A personal message that will be emailed to each
|
||||
// successfully added member.
|
||||
CustomMessage string `json:"custom_message,omitempty"`
|
||||
// Quiet : Clients should set this to true if no email message shall be sent
|
||||
// to added users.
|
||||
Quiet bool `json:"quiet"`
|
||||
}
|
||||
|
||||
// NewAddPaperDocUser returns a new AddPaperDocUser instance
|
||||
func NewAddPaperDocUser(DocId string, Members []*AddMember) *AddPaperDocUser {
|
||||
s := new(AddPaperDocUser)
|
||||
s.DocId = DocId
|
||||
s.Members = Members
|
||||
s.Quiet = false
|
||||
return s
|
||||
}
|
||||
|
||||
// AddPaperDocUserMemberResult : Per-member result for `docsUsersAdd`.
|
||||
type AddPaperDocUserMemberResult struct {
|
||||
// Member : One of specified input members.
|
||||
Member *sharing.MemberSelector `json:"member"`
|
||||
// Result : The outcome of the action on this member.
|
||||
Result *AddPaperDocUserResult `json:"result"`
|
||||
}
|
||||
|
||||
// NewAddPaperDocUserMemberResult returns a new AddPaperDocUserMemberResult instance
|
||||
func NewAddPaperDocUserMemberResult(Member *sharing.MemberSelector, Result *AddPaperDocUserResult) *AddPaperDocUserMemberResult {
|
||||
s := new(AddPaperDocUserMemberResult)
|
||||
s.Member = Member
|
||||
s.Result = Result
|
||||
return s
|
||||
}
|
||||
|
||||
// AddPaperDocUserResult : has no documentation (yet)
|
||||
type AddPaperDocUserResult struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for AddPaperDocUserResult
|
||||
const (
|
||||
AddPaperDocUserResultSuccess = "success"
|
||||
AddPaperDocUserResultUnknownError = "unknown_error"
|
||||
AddPaperDocUserResultSharingOutsideTeamDisabled = "sharing_outside_team_disabled"
|
||||
AddPaperDocUserResultDailyLimitReached = "daily_limit_reached"
|
||||
AddPaperDocUserResultUserIsOwner = "user_is_owner"
|
||||
AddPaperDocUserResultFailedUserDataRetrieval = "failed_user_data_retrieval"
|
||||
AddPaperDocUserResultPermissionAlreadyGranted = "permission_already_granted"
|
||||
AddPaperDocUserResultOther = "other"
|
||||
)
|
||||
|
||||
// Cursor : has no documentation (yet)
|
||||
type Cursor struct {
|
||||
// Value : The actual cursor value.
|
||||
Value string `json:"value"`
|
||||
// Expiration : Expiration time of `value`. Some cursors might have
|
||||
// expiration time assigned. This is a UTC value after which the cursor is
|
||||
// no longer valid and the API starts returning an error. If cursor expires
|
||||
// a new one needs to be obtained and pagination needs to be restarted. Some
|
||||
// cursors might be short-lived some cursors might be long-lived. This
|
||||
// really depends on the sorting type and order, e.g.: 1. on one hand,
|
||||
// listing docs created by the user, sorted by the created time ascending
|
||||
// will have undefinite expiration because the results cannot change while
|
||||
// the iteration is happening. This cursor would be suitable for long term
|
||||
// polling. 2. on the other hand, listing docs sorted by the last modified
|
||||
// time will have a very short expiration as docs do get modified very often
|
||||
// and the modified time can be changed while the iteration is happening
|
||||
// thus altering the results.
|
||||
Expiration time.Time `json:"expiration,omitempty"`
|
||||
}
|
||||
|
||||
// NewCursor returns a new Cursor instance
|
||||
func NewCursor(Value string) *Cursor {
|
||||
s := new(Cursor)
|
||||
s.Value = Value
|
||||
return s
|
||||
}
|
||||
|
||||
// PaperApiBaseError : has no documentation (yet)
|
||||
type PaperApiBaseError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for PaperApiBaseError
|
||||
const (
|
||||
PaperApiBaseErrorInsufficientPermissions = "insufficient_permissions"
|
||||
PaperApiBaseErrorOther = "other"
|
||||
)
|
||||
|
||||
// DocLookupError : has no documentation (yet)
|
||||
type DocLookupError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for DocLookupError
|
||||
const (
|
||||
DocLookupErrorDocNotFound = "doc_not_found"
|
||||
)
|
||||
|
||||
// DocSubscriptionLevel : The subscription level of a Paper doc.
|
||||
type DocSubscriptionLevel struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for DocSubscriptionLevel
|
||||
const (
|
||||
DocSubscriptionLevelDefault = "default"
|
||||
DocSubscriptionLevelIgnore = "ignore"
|
||||
DocSubscriptionLevelEvery = "every"
|
||||
DocSubscriptionLevelNoEmail = "no_email"
|
||||
)
|
||||
|
||||
// ExportFormat : The desired export format of the Paper doc.
|
||||
type ExportFormat struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for ExportFormat
|
||||
const (
|
||||
ExportFormatHtml = "html"
|
||||
ExportFormatMarkdown = "markdown"
|
||||
ExportFormatOther = "other"
|
||||
)
|
||||
|
||||
// Folder : Data structure representing a Paper folder.
|
||||
type Folder struct {
|
||||
// Id : Paper folder ID. This ID uniquely identifies the folder.
|
||||
Id string `json:"id"`
|
||||
// Name : Paper folder name.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// NewFolder returns a new Folder instance
|
||||
func NewFolder(Id string, Name string) *Folder {
|
||||
s := new(Folder)
|
||||
s.Id = Id
|
||||
s.Name = Name
|
||||
return s
|
||||
}
|
||||
|
||||
// FolderSharingPolicyType : The sharing policy of a Paper folder. Note: The
|
||||
// sharing policy of subfolders is inherited from the root folder.
|
||||
type FolderSharingPolicyType struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for FolderSharingPolicyType
|
||||
const (
|
||||
FolderSharingPolicyTypeTeam = "team"
|
||||
FolderSharingPolicyTypeInviteOnly = "invite_only"
|
||||
)
|
||||
|
||||
// FolderSubscriptionLevel : The subscription level of a Paper folder.
|
||||
type FolderSubscriptionLevel struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for FolderSubscriptionLevel
|
||||
const (
|
||||
FolderSubscriptionLevelNone = "none"
|
||||
FolderSubscriptionLevelActivityOnly = "activity_only"
|
||||
FolderSubscriptionLevelDailyEmails = "daily_emails"
|
||||
FolderSubscriptionLevelWeeklyEmails = "weekly_emails"
|
||||
)
|
||||
|
||||
// FoldersContainingPaperDoc : Metadata about Paper folders containing the
|
||||
// specififed Paper doc.
|
||||
type FoldersContainingPaperDoc struct {
|
||||
// FolderSharingPolicyType : The sharing policy of the folder containing the
|
||||
// Paper doc.
|
||||
FolderSharingPolicyType *FolderSharingPolicyType `json:"folder_sharing_policy_type,omitempty"`
|
||||
// Folders : The folder path. If present the first folder is the root
|
||||
// folder.
|
||||
Folders []*Folder `json:"folders,omitempty"`
|
||||
}
|
||||
|
||||
// NewFoldersContainingPaperDoc returns a new FoldersContainingPaperDoc instance
|
||||
func NewFoldersContainingPaperDoc() *FoldersContainingPaperDoc {
|
||||
s := new(FoldersContainingPaperDoc)
|
||||
return s
|
||||
}
|
||||
|
||||
// InviteeInfoWithPermissionLevel : has no documentation (yet)
|
||||
type InviteeInfoWithPermissionLevel struct {
|
||||
// Invitee : Email address invited to the Paper doc.
|
||||
Invitee *sharing.InviteeInfo `json:"invitee"`
|
||||
// PermissionLevel : Permission level for the invitee.
|
||||
PermissionLevel *PaperDocPermissionLevel `json:"permission_level"`
|
||||
}
|
||||
|
||||
// NewInviteeInfoWithPermissionLevel returns a new InviteeInfoWithPermissionLevel instance
|
||||
func NewInviteeInfoWithPermissionLevel(Invitee *sharing.InviteeInfo, PermissionLevel *PaperDocPermissionLevel) *InviteeInfoWithPermissionLevel {
|
||||
s := new(InviteeInfoWithPermissionLevel)
|
||||
s.Invitee = Invitee
|
||||
s.PermissionLevel = PermissionLevel
|
||||
return s
|
||||
}
|
||||
|
||||
// ListDocsCursorError : has no documentation (yet)
|
||||
type ListDocsCursorError struct {
|
||||
dropbox.Tagged
|
||||
// CursorError : has no documentation (yet)
|
||||
CursorError *PaperApiCursorError `json:"cursor_error,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for ListDocsCursorError
|
||||
const (
|
||||
ListDocsCursorErrorCursorError = "cursor_error"
|
||||
ListDocsCursorErrorOther = "other"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a ListDocsCursorError instance
|
||||
func (u *ListDocsCursorError) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
// CursorError : has no documentation (yet)
|
||||
CursorError json.RawMessage `json:"cursor_error,omitempty"`
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "cursor_error":
|
||||
err = json.Unmarshal(w.CursorError, &u.CursorError)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListPaperDocsArgs : has no documentation (yet)
|
||||
type ListPaperDocsArgs struct {
|
||||
// FilterBy : Allows user to specify how the Paper docs should be filtered.
|
||||
FilterBy *ListPaperDocsFilterBy `json:"filter_by"`
|
||||
// SortBy : Allows user to specify how the Paper docs should be sorted.
|
||||
SortBy *ListPaperDocsSortBy `json:"sort_by"`
|
||||
// SortOrder : Allows user to specify the sort order of the result.
|
||||
SortOrder *ListPaperDocsSortOrder `json:"sort_order"`
|
||||
// Limit : Size limit per batch. The maximum number of docs that can be
|
||||
// retrieved per batch is 1000. Higher value results in invalid arguments
|
||||
// error.
|
||||
Limit int32 `json:"limit"`
|
||||
}
|
||||
|
||||
// NewListPaperDocsArgs returns a new ListPaperDocsArgs instance
|
||||
func NewListPaperDocsArgs() *ListPaperDocsArgs {
|
||||
s := new(ListPaperDocsArgs)
|
||||
s.FilterBy = &ListPaperDocsFilterBy{Tagged: dropbox.Tagged{"docs_accessed"}}
|
||||
s.SortBy = &ListPaperDocsSortBy{Tagged: dropbox.Tagged{"accessed"}}
|
||||
s.SortOrder = &ListPaperDocsSortOrder{Tagged: dropbox.Tagged{"ascending"}}
|
||||
s.Limit = 1000
|
||||
return s
|
||||
}
|
||||
|
||||
// ListPaperDocsContinueArgs : has no documentation (yet)
|
||||
type ListPaperDocsContinueArgs struct {
|
||||
// Cursor : The cursor obtained from `docsList` or `docsListContinue`.
|
||||
// Allows for pagination.
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
// NewListPaperDocsContinueArgs returns a new ListPaperDocsContinueArgs instance
|
||||
func NewListPaperDocsContinueArgs(Cursor string) *ListPaperDocsContinueArgs {
|
||||
s := new(ListPaperDocsContinueArgs)
|
||||
s.Cursor = Cursor
|
||||
return s
|
||||
}
|
||||
|
||||
// ListPaperDocsFilterBy : has no documentation (yet)
|
||||
type ListPaperDocsFilterBy struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for ListPaperDocsFilterBy
|
||||
const (
|
||||
ListPaperDocsFilterByDocsAccessed = "docs_accessed"
|
||||
ListPaperDocsFilterByDocsCreated = "docs_created"
|
||||
ListPaperDocsFilterByOther = "other"
|
||||
)
|
||||
|
||||
// ListPaperDocsResponse : has no documentation (yet)
|
||||
type ListPaperDocsResponse struct {
|
||||
// DocIds : The list of Paper doc IDs that can be used to access the given
|
||||
// Paper docs or supplied to other API methods. The list is sorted in the
|
||||
// order specified by the initial call to `docsList`.
|
||||
DocIds []string `json:"doc_ids"`
|
||||
// Cursor : Pass the cursor into `docsListContinue` to paginate through all
|
||||
// files. The cursor preserves all properties as specified in the original
|
||||
// call to `docsList`.
|
||||
Cursor *Cursor `json:"cursor"`
|
||||
// HasMore : Will be set to True if a subsequent call with the provided
|
||||
// cursor to `docsListContinue` returns immediately with some results. If
|
||||
// set to False please allow some delay before making another call to
|
||||
// `docsListContinue`.
|
||||
HasMore bool `json:"has_more"`
|
||||
}
|
||||
|
||||
// NewListPaperDocsResponse returns a new ListPaperDocsResponse instance
|
||||
func NewListPaperDocsResponse(DocIds []string, Cursor *Cursor, HasMore bool) *ListPaperDocsResponse {
|
||||
s := new(ListPaperDocsResponse)
|
||||
s.DocIds = DocIds
|
||||
s.Cursor = Cursor
|
||||
s.HasMore = HasMore
|
||||
return s
|
||||
}
|
||||
|
||||
// ListPaperDocsSortBy : has no documentation (yet)
|
||||
type ListPaperDocsSortBy struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for ListPaperDocsSortBy
|
||||
const (
|
||||
ListPaperDocsSortByAccessed = "accessed"
|
||||
ListPaperDocsSortByModified = "modified"
|
||||
ListPaperDocsSortByCreated = "created"
|
||||
ListPaperDocsSortByOther = "other"
|
||||
)
|
||||
|
||||
// ListPaperDocsSortOrder : has no documentation (yet)
|
||||
type ListPaperDocsSortOrder struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for ListPaperDocsSortOrder
|
||||
const (
|
||||
ListPaperDocsSortOrderAscending = "ascending"
|
||||
ListPaperDocsSortOrderDescending = "descending"
|
||||
ListPaperDocsSortOrderOther = "other"
|
||||
)
|
||||
|
||||
// ListUsersCursorError : has no documentation (yet)
|
||||
type ListUsersCursorError struct {
|
||||
dropbox.Tagged
|
||||
// CursorError : has no documentation (yet)
|
||||
CursorError *PaperApiCursorError `json:"cursor_error,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for ListUsersCursorError
|
||||
const (
|
||||
ListUsersCursorErrorDocNotFound = "doc_not_found"
|
||||
ListUsersCursorErrorCursorError = "cursor_error"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a ListUsersCursorError instance
|
||||
func (u *ListUsersCursorError) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
// CursorError : has no documentation (yet)
|
||||
CursorError json.RawMessage `json:"cursor_error,omitempty"`
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "cursor_error":
|
||||
err = json.Unmarshal(w.CursorError, &u.CursorError)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListUsersOnFolderArgs : has no documentation (yet)
|
||||
type ListUsersOnFolderArgs struct {
|
||||
RefPaperDoc
|
||||
// Limit : Size limit per batch. The maximum number of users that can be
|
||||
// retrieved per batch is 1000. Higher value results in invalid arguments
|
||||
// error.
|
||||
Limit int32 `json:"limit"`
|
||||
}
|
||||
|
||||
// NewListUsersOnFolderArgs returns a new ListUsersOnFolderArgs instance
|
||||
func NewListUsersOnFolderArgs(DocId string) *ListUsersOnFolderArgs {
|
||||
s := new(ListUsersOnFolderArgs)
|
||||
s.DocId = DocId
|
||||
s.Limit = 1000
|
||||
return s
|
||||
}
|
||||
|
||||
// ListUsersOnFolderContinueArgs : has no documentation (yet)
|
||||
type ListUsersOnFolderContinueArgs struct {
|
||||
RefPaperDoc
|
||||
// Cursor : The cursor obtained from `docsFolderUsersList` or
|
||||
// `docsFolderUsersListContinue`. Allows for pagination.
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
// NewListUsersOnFolderContinueArgs returns a new ListUsersOnFolderContinueArgs instance
|
||||
func NewListUsersOnFolderContinueArgs(DocId string, Cursor string) *ListUsersOnFolderContinueArgs {
|
||||
s := new(ListUsersOnFolderContinueArgs)
|
||||
s.DocId = DocId
|
||||
s.Cursor = Cursor
|
||||
return s
|
||||
}
|
||||
|
||||
// ListUsersOnFolderResponse : has no documentation (yet)
|
||||
type ListUsersOnFolderResponse struct {
|
||||
// Invitees : List of email addresses that are invited on the Paper folder.
|
||||
Invitees []*sharing.InviteeInfo `json:"invitees"`
|
||||
// Users : List of users that are invited on the Paper folder.
|
||||
Users []*sharing.UserInfo `json:"users"`
|
||||
// Cursor : Pass the cursor into `docsFolderUsersListContinue` to paginate
|
||||
// through all users. The cursor preserves all properties as specified in
|
||||
// the original call to `docsFolderUsersList`.
|
||||
Cursor *Cursor `json:"cursor"`
|
||||
// HasMore : Will be set to True if a subsequent call with the provided
|
||||
// cursor to `docsFolderUsersListContinue` returns immediately with some
|
||||
// results. If set to False please allow some delay before making another
|
||||
// call to `docsFolderUsersListContinue`.
|
||||
HasMore bool `json:"has_more"`
|
||||
}
|
||||
|
||||
// NewListUsersOnFolderResponse returns a new ListUsersOnFolderResponse instance
|
||||
func NewListUsersOnFolderResponse(Invitees []*sharing.InviteeInfo, Users []*sharing.UserInfo, Cursor *Cursor, HasMore bool) *ListUsersOnFolderResponse {
|
||||
s := new(ListUsersOnFolderResponse)
|
||||
s.Invitees = Invitees
|
||||
s.Users = Users
|
||||
s.Cursor = Cursor
|
||||
s.HasMore = HasMore
|
||||
return s
|
||||
}
|
||||
|
||||
// ListUsersOnPaperDocArgs : has no documentation (yet)
|
||||
type ListUsersOnPaperDocArgs struct {
|
||||
RefPaperDoc
|
||||
// Limit : Size limit per batch. The maximum number of users that can be
|
||||
// retrieved per batch is 1000. Higher value results in invalid arguments
|
||||
// error.
|
||||
Limit int32 `json:"limit"`
|
||||
// FilterBy : Specify this attribute if you want to obtain users that have
|
||||
// already accessed the Paper doc.
|
||||
FilterBy *UserOnPaperDocFilter `json:"filter_by"`
|
||||
}
|
||||
|
||||
// NewListUsersOnPaperDocArgs returns a new ListUsersOnPaperDocArgs instance
|
||||
func NewListUsersOnPaperDocArgs(DocId string) *ListUsersOnPaperDocArgs {
|
||||
s := new(ListUsersOnPaperDocArgs)
|
||||
s.DocId = DocId
|
||||
s.Limit = 1000
|
||||
s.FilterBy = &UserOnPaperDocFilter{Tagged: dropbox.Tagged{"shared"}}
|
||||
return s
|
||||
}
|
||||
|
||||
// ListUsersOnPaperDocContinueArgs : has no documentation (yet)
|
||||
type ListUsersOnPaperDocContinueArgs struct {
|
||||
RefPaperDoc
|
||||
// Cursor : The cursor obtained from `docsUsersList` or
|
||||
// `docsUsersListContinue`. Allows for pagination.
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
// NewListUsersOnPaperDocContinueArgs returns a new ListUsersOnPaperDocContinueArgs instance
|
||||
func NewListUsersOnPaperDocContinueArgs(DocId string, Cursor string) *ListUsersOnPaperDocContinueArgs {
|
||||
s := new(ListUsersOnPaperDocContinueArgs)
|
||||
s.DocId = DocId
|
||||
s.Cursor = Cursor
|
||||
return s
|
||||
}
|
||||
|
||||
// ListUsersOnPaperDocResponse : has no documentation (yet)
|
||||
type ListUsersOnPaperDocResponse struct {
|
||||
// Invitees : List of email addresses with their respective permission
|
||||
// levels that are invited on the Paper doc.
|
||||
Invitees []*InviteeInfoWithPermissionLevel `json:"invitees"`
|
||||
// Users : List of users with their respective permission levels that are
|
||||
// invited on the Paper folder.
|
||||
Users []*UserInfoWithPermissionLevel `json:"users"`
|
||||
// DocOwner : The Paper doc owner. This field is populated on every single
|
||||
// response.
|
||||
DocOwner *sharing.UserInfo `json:"doc_owner"`
|
||||
// Cursor : Pass the cursor into `docsUsersListContinue` to paginate through
|
||||
// all users. The cursor preserves all properties as specified in the
|
||||
// original call to `docsUsersList`.
|
||||
Cursor *Cursor `json:"cursor"`
|
||||
// HasMore : Will be set to True if a subsequent call with the provided
|
||||
// cursor to `docsUsersListContinue` returns immediately with some results.
|
||||
// If set to False please allow some delay before making another call to
|
||||
// `docsUsersListContinue`.
|
||||
HasMore bool `json:"has_more"`
|
||||
}
|
||||
|
||||
// NewListUsersOnPaperDocResponse returns a new ListUsersOnPaperDocResponse instance
|
||||
func NewListUsersOnPaperDocResponse(Invitees []*InviteeInfoWithPermissionLevel, Users []*UserInfoWithPermissionLevel, DocOwner *sharing.UserInfo, Cursor *Cursor, HasMore bool) *ListUsersOnPaperDocResponse {
|
||||
s := new(ListUsersOnPaperDocResponse)
|
||||
s.Invitees = Invitees
|
||||
s.Users = Users
|
||||
s.DocOwner = DocOwner
|
||||
s.Cursor = Cursor
|
||||
s.HasMore = HasMore
|
||||
return s
|
||||
}
|
||||
|
||||
// PaperApiCursorError : has no documentation (yet)
|
||||
type PaperApiCursorError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for PaperApiCursorError
|
||||
const (
|
||||
PaperApiCursorErrorExpiredCursor = "expired_cursor"
|
||||
PaperApiCursorErrorInvalidCursor = "invalid_cursor"
|
||||
PaperApiCursorErrorWrongUserInCursor = "wrong_user_in_cursor"
|
||||
PaperApiCursorErrorReset = "reset"
|
||||
PaperApiCursorErrorOther = "other"
|
||||
)
|
||||
|
||||
// PaperDocExport : has no documentation (yet)
|
||||
type PaperDocExport struct {
|
||||
RefPaperDoc
|
||||
// ExportFormat : has no documentation (yet)
|
||||
ExportFormat *ExportFormat `json:"export_format"`
|
||||
}
|
||||
|
||||
// NewPaperDocExport returns a new PaperDocExport instance
|
||||
func NewPaperDocExport(DocId string, ExportFormat *ExportFormat) *PaperDocExport {
|
||||
s := new(PaperDocExport)
|
||||
s.DocId = DocId
|
||||
s.ExportFormat = ExportFormat
|
||||
return s
|
||||
}
|
||||
|
||||
// PaperDocExportResult : has no documentation (yet)
|
||||
type PaperDocExportResult struct {
|
||||
// Owner : The Paper doc owner's email address.
|
||||
Owner string `json:"owner"`
|
||||
// Title : The Paper doc title.
|
||||
Title string `json:"title"`
|
||||
// Revision : The Paper doc revision. Simply an ever increasing number.
|
||||
Revision int64 `json:"revision"`
|
||||
// MimeType : MIME type of the export. This corresponds to `ExportFormat`
|
||||
// specified in the request.
|
||||
MimeType string `json:"mime_type"`
|
||||
}
|
||||
|
||||
// NewPaperDocExportResult returns a new PaperDocExportResult instance
|
||||
func NewPaperDocExportResult(Owner string, Title string, Revision int64, MimeType string) *PaperDocExportResult {
|
||||
s := new(PaperDocExportResult)
|
||||
s.Owner = Owner
|
||||
s.Title = Title
|
||||
s.Revision = Revision
|
||||
s.MimeType = MimeType
|
||||
return s
|
||||
}
|
||||
|
||||
// PaperDocPermissionLevel : has no documentation (yet)
|
||||
type PaperDocPermissionLevel struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for PaperDocPermissionLevel
|
||||
const (
|
||||
PaperDocPermissionLevelEdit = "edit"
|
||||
PaperDocPermissionLevelViewAndComment = "view_and_comment"
|
||||
PaperDocPermissionLevelOther = "other"
|
||||
)
|
||||
|
||||
// PaperDocSharingPolicy : has no documentation (yet)
|
||||
type PaperDocSharingPolicy struct {
|
||||
RefPaperDoc
|
||||
// SharingPolicy : The default sharing policy to be set for the Paper doc.
|
||||
SharingPolicy *SharingPolicy `json:"sharing_policy"`
|
||||
}
|
||||
|
||||
// NewPaperDocSharingPolicy returns a new PaperDocSharingPolicy instance
|
||||
func NewPaperDocSharingPolicy(DocId string, SharingPolicy *SharingPolicy) *PaperDocSharingPolicy {
|
||||
s := new(PaperDocSharingPolicy)
|
||||
s.DocId = DocId
|
||||
s.SharingPolicy = SharingPolicy
|
||||
return s
|
||||
}
|
||||
|
||||
// RemovePaperDocUser : has no documentation (yet)
|
||||
type RemovePaperDocUser struct {
|
||||
RefPaperDoc
|
||||
// Member : User which should be removed from the Paper doc. Specify only
|
||||
// email address or Dropbox account ID.
|
||||
Member *sharing.MemberSelector `json:"member"`
|
||||
}
|
||||
|
||||
// NewRemovePaperDocUser returns a new RemovePaperDocUser instance
|
||||
func NewRemovePaperDocUser(DocId string, Member *sharing.MemberSelector) *RemovePaperDocUser {
|
||||
s := new(RemovePaperDocUser)
|
||||
s.DocId = DocId
|
||||
s.Member = Member
|
||||
return s
|
||||
}
|
||||
|
||||
// SharingPolicy : Sharing policy of Paper doc.
|
||||
type SharingPolicy struct {
|
||||
// PublicSharingPolicy : This value applies to the non-team members.
|
||||
PublicSharingPolicy *SharingPublicPolicyType `json:"public_sharing_policy,omitempty"`
|
||||
// TeamSharingPolicy : This value applies to the team members only. The
|
||||
// value is null for all personal accounts.
|
||||
TeamSharingPolicy *SharingTeamPolicyType `json:"team_sharing_policy,omitempty"`
|
||||
}
|
||||
|
||||
// NewSharingPolicy returns a new SharingPolicy instance
|
||||
func NewSharingPolicy() *SharingPolicy {
|
||||
s := new(SharingPolicy)
|
||||
return s
|
||||
}
|
||||
|
||||
// SharingTeamPolicyType : The sharing policy type of the Paper doc.
|
||||
type SharingTeamPolicyType struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for SharingTeamPolicyType
|
||||
const (
|
||||
SharingTeamPolicyTypePeopleWithLinkCanEdit = "people_with_link_can_edit"
|
||||
SharingTeamPolicyTypePeopleWithLinkCanViewAndComment = "people_with_link_can_view_and_comment"
|
||||
SharingTeamPolicyTypeInviteOnly = "invite_only"
|
||||
)
|
||||
|
||||
// SharingPublicPolicyType : has no documentation (yet)
|
||||
type SharingPublicPolicyType struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for SharingPublicPolicyType
|
||||
const (
|
||||
SharingPublicPolicyTypeDisabled = "disabled"
|
||||
)
|
||||
|
||||
// UserInfoWithPermissionLevel : has no documentation (yet)
|
||||
type UserInfoWithPermissionLevel struct {
|
||||
// User : User shared on the Paper doc.
|
||||
User *sharing.UserInfo `json:"user"`
|
||||
// PermissionLevel : Permission level for the user.
|
||||
PermissionLevel *PaperDocPermissionLevel `json:"permission_level"`
|
||||
}
|
||||
|
||||
// NewUserInfoWithPermissionLevel returns a new UserInfoWithPermissionLevel instance
|
||||
func NewUserInfoWithPermissionLevel(User *sharing.UserInfo, PermissionLevel *PaperDocPermissionLevel) *UserInfoWithPermissionLevel {
|
||||
s := new(UserInfoWithPermissionLevel)
|
||||
s.User = User
|
||||
s.PermissionLevel = PermissionLevel
|
||||
return s
|
||||
}
|
||||
|
||||
// UserOnPaperDocFilter : has no documentation (yet)
|
||||
type UserOnPaperDocFilter struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for UserOnPaperDocFilter
|
||||
const (
|
||||
UserOnPaperDocFilterVisited = "visited"
|
||||
UserOnPaperDocFilterShared = "shared"
|
||||
UserOnPaperDocFilterOther = "other"
|
||||
)
|
213
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/properties/types.go
generated
vendored
Normal file
213
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/properties/types.go
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package properties : This namespace contains helper entities for property and
|
||||
// property/template endpoints.
|
||||
package properties
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
)
|
||||
|
||||
// GetPropertyTemplateArg : has no documentation (yet)
|
||||
type GetPropertyTemplateArg struct {
|
||||
// TemplateId : An identifier for property template added by route
|
||||
// properties/template/add.
|
||||
TemplateId string `json:"template_id"`
|
||||
}
|
||||
|
||||
// NewGetPropertyTemplateArg returns a new GetPropertyTemplateArg instance
|
||||
func NewGetPropertyTemplateArg(TemplateId string) *GetPropertyTemplateArg {
|
||||
s := new(GetPropertyTemplateArg)
|
||||
s.TemplateId = TemplateId
|
||||
return s
|
||||
}
|
||||
|
||||
// PropertyGroupTemplate : Describes property templates that can be filled and
|
||||
// associated with a file.
|
||||
type PropertyGroupTemplate struct {
|
||||
// Name : A display name for the property template. Property template names
|
||||
// can be up to 256 bytes.
|
||||
Name string `json:"name"`
|
||||
// Description : Description for new property template. Property template
|
||||
// descriptions can be up to 1024 bytes.
|
||||
Description string `json:"description"`
|
||||
// Fields : This is a list of custom properties associated with a property
|
||||
// template. There can be up to 64 properties in a single property template.
|
||||
Fields []*PropertyFieldTemplate `json:"fields"`
|
||||
}
|
||||
|
||||
// NewPropertyGroupTemplate returns a new PropertyGroupTemplate instance
|
||||
func NewPropertyGroupTemplate(Name string, Description string, Fields []*PropertyFieldTemplate) *PropertyGroupTemplate {
|
||||
s := new(PropertyGroupTemplate)
|
||||
s.Name = Name
|
||||
s.Description = Description
|
||||
s.Fields = Fields
|
||||
return s
|
||||
}
|
||||
|
||||
// GetPropertyTemplateResult : The Property template for the specified template.
|
||||
type GetPropertyTemplateResult struct {
|
||||
PropertyGroupTemplate
|
||||
}
|
||||
|
||||
// NewGetPropertyTemplateResult returns a new GetPropertyTemplateResult instance
|
||||
func NewGetPropertyTemplateResult(Name string, Description string, Fields []*PropertyFieldTemplate) *GetPropertyTemplateResult {
|
||||
s := new(GetPropertyTemplateResult)
|
||||
s.Name = Name
|
||||
s.Description = Description
|
||||
s.Fields = Fields
|
||||
return s
|
||||
}
|
||||
|
||||
// ListPropertyTemplateIds : has no documentation (yet)
|
||||
type ListPropertyTemplateIds struct {
|
||||
// TemplateIds : List of identifiers for templates added by route
|
||||
// properties/template/add.
|
||||
TemplateIds []string `json:"template_ids"`
|
||||
}
|
||||
|
||||
// NewListPropertyTemplateIds returns a new ListPropertyTemplateIds instance
|
||||
func NewListPropertyTemplateIds(TemplateIds []string) *ListPropertyTemplateIds {
|
||||
s := new(ListPropertyTemplateIds)
|
||||
s.TemplateIds = TemplateIds
|
||||
return s
|
||||
}
|
||||
|
||||
// PropertyTemplateError : has no documentation (yet)
|
||||
type PropertyTemplateError struct {
|
||||
dropbox.Tagged
|
||||
// TemplateNotFound : Property template does not exist for given identifier.
|
||||
TemplateNotFound string `json:"template_not_found,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for PropertyTemplateError
|
||||
const (
|
||||
PropertyTemplateErrorTemplateNotFound = "template_not_found"
|
||||
PropertyTemplateErrorRestrictedContent = "restricted_content"
|
||||
PropertyTemplateErrorOther = "other"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a PropertyTemplateError instance
|
||||
func (u *PropertyTemplateError) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "template_not_found":
|
||||
err = json.Unmarshal(body, &u.TemplateNotFound)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ModifyPropertyTemplateError : has no documentation (yet)
|
||||
type ModifyPropertyTemplateError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for ModifyPropertyTemplateError
|
||||
const (
|
||||
ModifyPropertyTemplateErrorConflictingPropertyNames = "conflicting_property_names"
|
||||
ModifyPropertyTemplateErrorTooManyProperties = "too_many_properties"
|
||||
ModifyPropertyTemplateErrorTooManyTemplates = "too_many_templates"
|
||||
ModifyPropertyTemplateErrorTemplateAttributeTooLarge = "template_attribute_too_large"
|
||||
)
|
||||
|
||||
// PropertyField : has no documentation (yet)
|
||||
type PropertyField struct {
|
||||
// Name : This is the name or key of a custom property in a property
|
||||
// template. File property names can be up to 256 bytes.
|
||||
Name string `json:"name"`
|
||||
// Value : Value of a custom property attached to a file. Values can be up
|
||||
// to 1024 bytes.
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// NewPropertyField returns a new PropertyField instance
|
||||
func NewPropertyField(Name string, Value string) *PropertyField {
|
||||
s := new(PropertyField)
|
||||
s.Name = Name
|
||||
s.Value = Value
|
||||
return s
|
||||
}
|
||||
|
||||
// PropertyFieldTemplate : Describe a single property field type which that can
|
||||
// be part of a property template.
|
||||
type PropertyFieldTemplate struct {
|
||||
// Name : This is the name or key of a custom property in a property
|
||||
// template. File property names can be up to 256 bytes.
|
||||
Name string `json:"name"`
|
||||
// Description : This is the description for a custom property in a property
|
||||
// template. File property description can be up to 1024 bytes.
|
||||
Description string `json:"description"`
|
||||
// Type : This is the data type of the value of this property. This type
|
||||
// will be enforced upon property creation and modifications.
|
||||
Type *PropertyType `json:"type"`
|
||||
}
|
||||
|
||||
// NewPropertyFieldTemplate returns a new PropertyFieldTemplate instance
|
||||
func NewPropertyFieldTemplate(Name string, Description string, Type *PropertyType) *PropertyFieldTemplate {
|
||||
s := new(PropertyFieldTemplate)
|
||||
s.Name = Name
|
||||
s.Description = Description
|
||||
s.Type = Type
|
||||
return s
|
||||
}
|
||||
|
||||
// PropertyGroup : Collection of custom properties in filled property templates.
|
||||
type PropertyGroup struct {
|
||||
// TemplateId : A unique identifier for a property template type.
|
||||
TemplateId string `json:"template_id"`
|
||||
// Fields : This is a list of custom properties associated with a file.
|
||||
// There can be up to 32 properties for a template.
|
||||
Fields []*PropertyField `json:"fields"`
|
||||
}
|
||||
|
||||
// NewPropertyGroup returns a new PropertyGroup instance
|
||||
func NewPropertyGroup(TemplateId string, Fields []*PropertyField) *PropertyGroup {
|
||||
s := new(PropertyGroup)
|
||||
s.TemplateId = TemplateId
|
||||
s.Fields = Fields
|
||||
return s
|
||||
}
|
||||
|
||||
// PropertyType : Data type of the given property added. This endpoint is in
|
||||
// beta and only properties of type strings is supported.
|
||||
type PropertyType struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for PropertyType
|
||||
const (
|
||||
PropertyTypeString = "string"
|
||||
PropertyTypeOther = "other"
|
||||
)
|
170
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sdk.go
generated
vendored
Normal file
170
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sdk.go
generated
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
apiVersion = 2
|
||||
defaultDomain = ".dropboxapi.com"
|
||||
hostAPI = "api"
|
||||
hostContent = "content"
|
||||
hostNotify = "notify"
|
||||
sdkVersion = "1.0.0-beta"
|
||||
specVersion = "8c790b1"
|
||||
)
|
||||
|
||||
// Version returns the current SDK version and API Spec version
|
||||
func Version() (string, string) {
|
||||
return sdkVersion, specVersion
|
||||
}
|
||||
|
||||
// Config contains parameters for configuring the SDK.
|
||||
type Config struct {
|
||||
// OAuth2 access token
|
||||
Token string
|
||||
// Enable verbose logging in SDK
|
||||
Verbose bool
|
||||
// Used with APIs that support operations as another user
|
||||
AsMemberID string
|
||||
// No need to set -- for testing only
|
||||
Domain string
|
||||
// No need to set -- for testing only
|
||||
Client *http.Client
|
||||
// No need to set -- for testing only
|
||||
HeaderGenerator func(hostType string, style string, namespace string, route string) map[string]string
|
||||
// No need to set -- for testing only
|
||||
URLGenerator func(hostType string, style string, namespace string, route string) string
|
||||
}
|
||||
|
||||
// Context is the base client context used to implement per-namespace clients.
|
||||
type Context struct {
|
||||
Config Config
|
||||
Client *http.Client
|
||||
HeaderGenerator func(hostType string, style string, namespace string, route string) map[string]string
|
||||
URLGenerator func(hostType string, style string, namespace string, route string) string
|
||||
}
|
||||
|
||||
// NewRequest returns an appropriate Request object for the given namespace/route.
|
||||
func (c *Context) NewRequest(
|
||||
hostType string,
|
||||
style string,
|
||||
authed bool,
|
||||
namespace string,
|
||||
route string,
|
||||
headers map[string]string,
|
||||
body io.Reader,
|
||||
) (*http.Request, error) {
|
||||
url := c.URLGenerator(hostType, style, namespace, route)
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
for k, v := range c.HeaderGenerator(hostType, style, namespace, route) {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
if req.Header.Get("Host") != "" {
|
||||
req.Host = req.Header.Get("Host")
|
||||
}
|
||||
if !authed {
|
||||
req.Header.Del("Authorization")
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// NewContext returns a new Context with the given Config.
|
||||
func NewContext(c Config) Context {
|
||||
domain := c.Domain
|
||||
if domain == "" {
|
||||
domain = defaultDomain
|
||||
}
|
||||
|
||||
client := c.Client
|
||||
if client == nil {
|
||||
var conf = &oauth2.Config{Endpoint: OAuthEndpoint(domain)}
|
||||
tok := &oauth2.Token{AccessToken: c.Token}
|
||||
client = conf.Client(oauth2.NoContext, tok)
|
||||
}
|
||||
|
||||
headerGenerator := c.HeaderGenerator
|
||||
if headerGenerator == nil {
|
||||
headerGenerator = func(hostType string, style string, namespace string, route string) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
}
|
||||
|
||||
urlGenerator := c.URLGenerator
|
||||
if urlGenerator == nil {
|
||||
hostMap := map[string]string{
|
||||
hostAPI: hostAPI + domain,
|
||||
hostContent: hostContent + domain,
|
||||
hostNotify: hostNotify + domain,
|
||||
}
|
||||
urlGenerator = func(hostType string, style string, namespace string, route string) string {
|
||||
fqHost := hostMap[hostType]
|
||||
return fmt.Sprintf("https://%s/%d/%s/%s", fqHost, apiVersion, namespace, route)
|
||||
}
|
||||
}
|
||||
|
||||
return Context{c, client, headerGenerator, urlGenerator}
|
||||
}
|
||||
|
||||
// OAuthEndpoint constructs an `oauth2.Endpoint` for the given domain
|
||||
func OAuthEndpoint(domain string) oauth2.Endpoint {
|
||||
if domain == "" {
|
||||
domain = defaultDomain
|
||||
}
|
||||
authURL := fmt.Sprintf("https://meta%s/1/oauth2/authorize", domain)
|
||||
tokenURL := fmt.Sprintf("https://api%s/1/oauth2/token", domain)
|
||||
if domain == defaultDomain {
|
||||
authURL = "https://www.dropbox.com/1/oauth2/authorize"
|
||||
}
|
||||
return oauth2.Endpoint{AuthURL: authURL, TokenURL: tokenURL}
|
||||
}
|
||||
|
||||
// Tagged is used for tagged unions.
|
||||
type Tagged struct {
|
||||
Tag string `json:".tag"`
|
||||
}
|
||||
|
||||
// APIError is the base type for endpoint-specific errors.
|
||||
type APIError struct {
|
||||
ErrorSummary string `json:"error_summary"`
|
||||
}
|
||||
|
||||
func (e APIError) Error() string {
|
||||
return e.ErrorSummary
|
||||
}
|
||||
|
||||
func init() {
|
||||
// These are not registered in the oauth library by default
|
||||
oauth2.RegisterBrokenAuthHeaderProvider("https://api.dropboxapi.com")
|
||||
oauth2.RegisterBrokenAuthHeaderProvider("https://api-dbdev.dev.corp.dropbox.com")
|
||||
}
|
3586
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sharing/client.go
generated
vendored
Normal file
3586
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sharing/client.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
49
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sharing/metadata.go
generated
vendored
Normal file
49
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sharing/metadata.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package sharing
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type listSharedLinksResult struct {
|
||||
Links []sharedLinkMetadataUnion `json:"links"`
|
||||
HasMore bool `json:"has_more"`
|
||||
Cursor string `json:"cursor,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes into a ListSharedLinksResult instance
|
||||
func (r *ListSharedLinksResult) UnmarshalJSON(b []byte) error {
|
||||
var l listSharedLinksResult
|
||||
if err := json.Unmarshal(b, &l); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Cursor = l.Cursor
|
||||
r.HasMore = l.HasMore
|
||||
r.Links = make([]IsSharedLinkMetadata, len(l.Links))
|
||||
for i, e := range l.Links {
|
||||
switch e.Tag {
|
||||
case "file":
|
||||
r.Links[i] = e.File
|
||||
case "folder":
|
||||
r.Links[i] = e.Folder
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
4066
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sharing/types.go
generated
vendored
Normal file
4066
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/sharing/types.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4417
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team/client.go
generated
vendored
Normal file
4417
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team/client.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3336
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team/types.go
generated
vendored
Normal file
3336
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team/types.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
91
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_common/types.go
generated
vendored
Normal file
91
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_common/types.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package team_common : has no documentation (yet)
|
||||
package team_common
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
)
|
||||
|
||||
// GroupManagementType : The group type determines how a group is managed.
|
||||
type GroupManagementType struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for GroupManagementType
|
||||
const (
|
||||
GroupManagementTypeUserManaged = "user_managed"
|
||||
GroupManagementTypeCompanyManaged = "company_managed"
|
||||
GroupManagementTypeSystemManaged = "system_managed"
|
||||
GroupManagementTypeOther = "other"
|
||||
)
|
||||
|
||||
// GroupSummary : Information about a group.
|
||||
type GroupSummary struct {
|
||||
// GroupName : has no documentation (yet)
|
||||
GroupName string `json:"group_name"`
|
||||
// GroupId : has no documentation (yet)
|
||||
GroupId string `json:"group_id"`
|
||||
// GroupExternalId : External ID of group. This is an arbitrary ID that an
|
||||
// admin can attach to a group.
|
||||
GroupExternalId string `json:"group_external_id,omitempty"`
|
||||
// MemberCount : The number of members in the group.
|
||||
MemberCount uint32 `json:"member_count,omitempty"`
|
||||
// GroupManagementType : Who is allowed to manage the group.
|
||||
GroupManagementType *GroupManagementType `json:"group_management_type"`
|
||||
}
|
||||
|
||||
// NewGroupSummary returns a new GroupSummary instance
|
||||
func NewGroupSummary(GroupName string, GroupId string, GroupManagementType *GroupManagementType) *GroupSummary {
|
||||
s := new(GroupSummary)
|
||||
s.GroupName = GroupName
|
||||
s.GroupId = GroupId
|
||||
s.GroupManagementType = GroupManagementType
|
||||
return s
|
||||
}
|
||||
|
||||
// GroupType : The group type determines how a group is created and managed.
|
||||
type GroupType struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for GroupType
|
||||
const (
|
||||
GroupTypeTeam = "team"
|
||||
GroupTypeUserManaged = "user_managed"
|
||||
GroupTypeOther = "other"
|
||||
)
|
||||
|
||||
// TimeRange : Time range.
|
||||
type TimeRange struct {
|
||||
// StartTime : Optional starting time (inclusive).
|
||||
StartTime time.Time `json:"start_time,omitempty"`
|
||||
// EndTime : Optional ending time (exclusive).
|
||||
EndTime time.Time `json:"end_time,omitempty"`
|
||||
}
|
||||
|
||||
// NewTimeRange returns a new TimeRange instance
|
||||
func NewTimeRange() *TimeRange {
|
||||
s := new(TimeRange)
|
||||
return s
|
||||
}
|
202
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_log/client.go
generated
vendored
Normal file
202
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_log/client.go
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package team_log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
)
|
||||
|
||||
// Client interface describes all routes in this namespace
|
||||
type Client interface {
|
||||
// GetEvents : Retrieves team events. Permission : Team Auditing.
|
||||
GetEvents(arg *GetTeamEventsArg) (res *GetTeamEventsResult, err error)
|
||||
// GetEventsContinue : Once a cursor has been retrieved from `getEvents`,
|
||||
// use this to paginate through all events. Permission : Team Auditing.
|
||||
GetEventsContinue(arg *GetTeamEventsContinueArg) (res *GetTeamEventsResult, err error)
|
||||
}
|
||||
|
||||
type apiImpl dropbox.Context
|
||||
|
||||
//GetEventsAPIError is an error-wrapper for the get_events route
|
||||
type GetEventsAPIError struct {
|
||||
dropbox.APIError
|
||||
EndpointError *GetTeamEventsError `json:"error"`
|
||||
}
|
||||
|
||||
func (dbx *apiImpl) GetEvents(arg *GetTeamEventsArg) (res *GetTeamEventsResult, err error) {
|
||||
cli := dbx.Client
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("arg: %v", arg)
|
||||
}
|
||||
b, err := json.Marshal(arg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
req, err := (*dropbox.Context)(dbx).NewRequest("api", "rpc", true, "team_log", "get_events", headers, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("req: %v", req)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("resp: %v", resp)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("body: %s", body)
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
var apiError GetEventsAPIError
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
var apiError dropbox.APIError
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
apiError.ErrorSummary = string(body)
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
|
||||
//GetEventsContinueAPIError is an error-wrapper for the get_events/continue route
|
||||
type GetEventsContinueAPIError struct {
|
||||
dropbox.APIError
|
||||
EndpointError *GetTeamEventsContinueError `json:"error"`
|
||||
}
|
||||
|
||||
func (dbx *apiImpl) GetEventsContinue(arg *GetTeamEventsContinueArg) (res *GetTeamEventsResult, err error) {
|
||||
cli := dbx.Client
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("arg: %v", arg)
|
||||
}
|
||||
b, err := json.Marshal(arg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
req, err := (*dropbox.Context)(dbx).NewRequest("api", "rpc", true, "team_log", "get_events/continue", headers, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("req: %v", req)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("resp: %v", resp)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("body: %s", body)
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
var apiError GetEventsContinueAPIError
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
var apiError dropbox.APIError
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
apiError.ErrorSummary = string(body)
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
|
||||
// New returns a Client implementation for this namespace
|
||||
func New(c dropbox.Config) *apiImpl {
|
||||
ctx := apiImpl(dropbox.NewContext(c))
|
||||
return &ctx
|
||||
}
|
8836
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_log/types.go
generated
vendored
Normal file
8836
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_log/types.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
118
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_policies/types.go
generated
vendored
Normal file
118
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_policies/types.go
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package team_policies : has no documentation (yet)
|
||||
package team_policies
|
||||
|
||||
import "github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
|
||||
// EmmState : has no documentation (yet)
|
||||
type EmmState struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for EmmState
|
||||
const (
|
||||
EmmStateDisabled = "disabled"
|
||||
EmmStateOptional = "optional"
|
||||
EmmStateRequired = "required"
|
||||
EmmStateOther = "other"
|
||||
)
|
||||
|
||||
// SharedFolderJoinPolicy : Policy governing which shared folders a team member
|
||||
// can join.
|
||||
type SharedFolderJoinPolicy struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for SharedFolderJoinPolicy
|
||||
const (
|
||||
SharedFolderJoinPolicyFromTeamOnly = "from_team_only"
|
||||
SharedFolderJoinPolicyFromAnyone = "from_anyone"
|
||||
SharedFolderJoinPolicyOther = "other"
|
||||
)
|
||||
|
||||
// SharedFolderMemberPolicy : Policy governing who can be a member of a folder
|
||||
// shared by a team member.
|
||||
type SharedFolderMemberPolicy struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for SharedFolderMemberPolicy
|
||||
const (
|
||||
SharedFolderMemberPolicyTeam = "team"
|
||||
SharedFolderMemberPolicyAnyone = "anyone"
|
||||
SharedFolderMemberPolicyOther = "other"
|
||||
)
|
||||
|
||||
// SharedLinkCreatePolicy : Policy governing the visibility of shared links.
|
||||
// This policy can apply to newly created shared links, or all shared links.
|
||||
type SharedLinkCreatePolicy struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for SharedLinkCreatePolicy
|
||||
const (
|
||||
SharedLinkCreatePolicyDefaultPublic = "default_public"
|
||||
SharedLinkCreatePolicyDefaultTeamOnly = "default_team_only"
|
||||
SharedLinkCreatePolicyTeamOnly = "team_only"
|
||||
SharedLinkCreatePolicyOther = "other"
|
||||
)
|
||||
|
||||
// TeamMemberPolicies : Policies governing team members.
|
||||
type TeamMemberPolicies struct {
|
||||
// Sharing : Policies governing sharing.
|
||||
Sharing *TeamSharingPolicies `json:"sharing"`
|
||||
// EmmState : This describes the Enterprise Mobility Management (EMM) state
|
||||
// for this team. This information can be used to understand if an
|
||||
// organization is integrating with a third-party EMM vendor to further
|
||||
// manage and apply restrictions upon the team's Dropbox usage on mobile
|
||||
// devices. This is a new feature and in the future we'll be adding more new
|
||||
// fields and additional documentation.
|
||||
EmmState *EmmState `json:"emm_state"`
|
||||
}
|
||||
|
||||
// NewTeamMemberPolicies returns a new TeamMemberPolicies instance
|
||||
func NewTeamMemberPolicies(Sharing *TeamSharingPolicies, EmmState *EmmState) *TeamMemberPolicies {
|
||||
s := new(TeamMemberPolicies)
|
||||
s.Sharing = Sharing
|
||||
s.EmmState = EmmState
|
||||
return s
|
||||
}
|
||||
|
||||
// TeamSharingPolicies : Policies governing sharing within and outside of the
|
||||
// team.
|
||||
type TeamSharingPolicies struct {
|
||||
// SharedFolderMemberPolicy : Who can join folders shared by team members.
|
||||
SharedFolderMemberPolicy *SharedFolderMemberPolicy `json:"shared_folder_member_policy"`
|
||||
// SharedFolderJoinPolicy : Which shared folders team members can join.
|
||||
SharedFolderJoinPolicy *SharedFolderJoinPolicy `json:"shared_folder_join_policy"`
|
||||
// SharedLinkCreatePolicy : Who can view shared links owned by team members.
|
||||
SharedLinkCreatePolicy *SharedLinkCreatePolicy `json:"shared_link_create_policy"`
|
||||
}
|
||||
|
||||
// NewTeamSharingPolicies returns a new TeamSharingPolicies instance
|
||||
func NewTeamSharingPolicies(SharedFolderMemberPolicy *SharedFolderMemberPolicy, SharedFolderJoinPolicy *SharedFolderJoinPolicy, SharedLinkCreatePolicy *SharedLinkCreatePolicy) *TeamSharingPolicies {
|
||||
s := new(TeamSharingPolicies)
|
||||
s.SharedFolderMemberPolicy = SharedFolderMemberPolicy
|
||||
s.SharedFolderJoinPolicy = SharedFolderJoinPolicy
|
||||
s.SharedLinkCreatePolicy = SharedLinkCreatePolicy
|
||||
return s
|
||||
}
|
353
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/users/client.go
generated
vendored
Normal file
353
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/users/client.go
generated
vendored
Normal file
@ -0,0 +1,353 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package users
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
)
|
||||
|
||||
// Client interface describes all routes in this namespace
|
||||
type Client interface {
|
||||
// GetAccount : Get information about a user's account.
|
||||
GetAccount(arg *GetAccountArg) (res *BasicAccount, err error)
|
||||
// GetAccountBatch : Get information about multiple user accounts. At most
|
||||
// 300 accounts may be queried per request.
|
||||
GetAccountBatch(arg *GetAccountBatchArg) (res []*BasicAccount, err error)
|
||||
// GetCurrentAccount : Get information about the current user's account.
|
||||
GetCurrentAccount() (res *FullAccount, err error)
|
||||
// GetSpaceUsage : Get the space usage information for the current user's
|
||||
// account.
|
||||
GetSpaceUsage() (res *SpaceUsage, err error)
|
||||
}
|
||||
|
||||
type apiImpl dropbox.Context
|
||||
|
||||
//GetAccountAPIError is an error-wrapper for the get_account route
|
||||
type GetAccountAPIError struct {
|
||||
dropbox.APIError
|
||||
EndpointError *GetAccountError `json:"error"`
|
||||
}
|
||||
|
||||
func (dbx *apiImpl) GetAccount(arg *GetAccountArg) (res *BasicAccount, err error) {
|
||||
cli := dbx.Client
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("arg: %v", arg)
|
||||
}
|
||||
b, err := json.Marshal(arg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
if dbx.Config.AsMemberID != "" {
|
||||
headers["Dropbox-API-Select-User"] = dbx.Config.AsMemberID
|
||||
}
|
||||
|
||||
req, err := (*dropbox.Context)(dbx).NewRequest("api", "rpc", true, "users", "get_account", headers, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("req: %v", req)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("resp: %v", resp)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("body: %s", body)
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
var apiError GetAccountAPIError
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
var apiError dropbox.APIError
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
apiError.ErrorSummary = string(body)
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
|
||||
//GetAccountBatchAPIError is an error-wrapper for the get_account_batch route
|
||||
type GetAccountBatchAPIError struct {
|
||||
dropbox.APIError
|
||||
EndpointError *GetAccountBatchError `json:"error"`
|
||||
}
|
||||
|
||||
func (dbx *apiImpl) GetAccountBatch(arg *GetAccountBatchArg) (res []*BasicAccount, err error) {
|
||||
cli := dbx.Client
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("arg: %v", arg)
|
||||
}
|
||||
b, err := json.Marshal(arg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
if dbx.Config.AsMemberID != "" {
|
||||
headers["Dropbox-API-Select-User"] = dbx.Config.AsMemberID
|
||||
}
|
||||
|
||||
req, err := (*dropbox.Context)(dbx).NewRequest("api", "rpc", true, "users", "get_account_batch", headers, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("req: %v", req)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("resp: %v", resp)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("body: %s", body)
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
var apiError GetAccountBatchAPIError
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
var apiError dropbox.APIError
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
apiError.ErrorSummary = string(body)
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
|
||||
//GetCurrentAccountAPIError is an error-wrapper for the get_current_account route
|
||||
type GetCurrentAccountAPIError struct {
|
||||
dropbox.APIError
|
||||
EndpointError struct{} `json:"error"`
|
||||
}
|
||||
|
||||
func (dbx *apiImpl) GetCurrentAccount() (res *FullAccount, err error) {
|
||||
cli := dbx.Client
|
||||
|
||||
headers := map[string]string{}
|
||||
if dbx.Config.AsMemberID != "" {
|
||||
headers["Dropbox-API-Select-User"] = dbx.Config.AsMemberID
|
||||
}
|
||||
|
||||
req, err := (*dropbox.Context)(dbx).NewRequest("api", "rpc", true, "users", "get_current_account", headers, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("req: %v", req)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("resp: %v", resp)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("body: %s", body)
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
var apiError GetCurrentAccountAPIError
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
var apiError dropbox.APIError
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
apiError.ErrorSummary = string(body)
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
|
||||
//GetSpaceUsageAPIError is an error-wrapper for the get_space_usage route
|
||||
type GetSpaceUsageAPIError struct {
|
||||
dropbox.APIError
|
||||
EndpointError struct{} `json:"error"`
|
||||
}
|
||||
|
||||
func (dbx *apiImpl) GetSpaceUsage() (res *SpaceUsage, err error) {
|
||||
cli := dbx.Client
|
||||
|
||||
headers := map[string]string{}
|
||||
if dbx.Config.AsMemberID != "" {
|
||||
headers["Dropbox-API-Select-User"] = dbx.Config.AsMemberID
|
||||
}
|
||||
|
||||
req, err := (*dropbox.Context)(dbx).NewRequest("api", "rpc", true, "users", "get_space_usage", headers, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("req: %v", req)
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("resp: %v", resp)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if dbx.Config.Verbose {
|
||||
log.Printf("body: %s", body)
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
var apiError GetSpaceUsageAPIError
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
var apiError dropbox.APIError
|
||||
if resp.StatusCode == http.StatusBadRequest {
|
||||
apiError.ErrorSummary = string(body)
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &apiError)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = apiError
|
||||
return
|
||||
}
|
||||
|
||||
// New returns a Client implementation for this namespace
|
||||
func New(c dropbox.Config) *apiImpl {
|
||||
ctx := apiImpl(dropbox.NewContext(c))
|
||||
return &ctx
|
||||
}
|
357
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/users/types.go
generated
vendored
Normal file
357
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/users/types.go
generated
vendored
Normal file
@ -0,0 +1,357 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package users : This namespace contains endpoints and data types for user
|
||||
// management.
|
||||
package users
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox/team_policies"
|
||||
"github.com/ncw/dropbox-sdk-go-unofficial/dropbox/users_common"
|
||||
)
|
||||
|
||||
// Account : The amount of detail revealed about an account depends on the user
|
||||
// being queried and the user making the query.
|
||||
type Account struct {
|
||||
// AccountId : The user's unique Dropbox ID.
|
||||
AccountId string `json:"account_id"`
|
||||
// Name : Details of a user's name.
|
||||
Name *Name `json:"name"`
|
||||
// Email : The user's e-mail address. Do not rely on this without checking
|
||||
// the `email_verified` field. Even then, it's possible that the user has
|
||||
// since lost access to their e-mail.
|
||||
Email string `json:"email"`
|
||||
// EmailVerified : Whether the user has verified their e-mail address.
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
// ProfilePhotoUrl : URL for the photo representing the user, if one is set.
|
||||
ProfilePhotoUrl string `json:"profile_photo_url,omitempty"`
|
||||
// Disabled : Whether the user has been disabled.
|
||||
Disabled bool `json:"disabled"`
|
||||
}
|
||||
|
||||
// NewAccount returns a new Account instance
|
||||
func NewAccount(AccountId string, Name *Name, Email string, EmailVerified bool, Disabled bool) *Account {
|
||||
s := new(Account)
|
||||
s.AccountId = AccountId
|
||||
s.Name = Name
|
||||
s.Email = Email
|
||||
s.EmailVerified = EmailVerified
|
||||
s.Disabled = Disabled
|
||||
return s
|
||||
}
|
||||
|
||||
// BasicAccount : Basic information about any account.
|
||||
type BasicAccount struct {
|
||||
Account
|
||||
// IsTeammate : Whether this user is a teammate of the current user. If this
|
||||
// account is the current user's account, then this will be true.
|
||||
IsTeammate bool `json:"is_teammate"`
|
||||
// TeamMemberId : The user's unique team member id. This field will only be
|
||||
// present if the user is part of a team and `is_teammate` is true.
|
||||
TeamMemberId string `json:"team_member_id,omitempty"`
|
||||
}
|
||||
|
||||
// NewBasicAccount returns a new BasicAccount instance
|
||||
func NewBasicAccount(AccountId string, Name *Name, Email string, EmailVerified bool, Disabled bool, IsTeammate bool) *BasicAccount {
|
||||
s := new(BasicAccount)
|
||||
s.AccountId = AccountId
|
||||
s.Name = Name
|
||||
s.Email = Email
|
||||
s.EmailVerified = EmailVerified
|
||||
s.Disabled = Disabled
|
||||
s.IsTeammate = IsTeammate
|
||||
return s
|
||||
}
|
||||
|
||||
// FullAccount : Detailed information about the current user's account.
|
||||
type FullAccount struct {
|
||||
Account
|
||||
// Country : The user's two-letter country code, if available. Country codes
|
||||
// are based on `ISO 3166-1` <http://en.wikipedia.org/wiki/ISO_3166-1>.
|
||||
Country string `json:"country,omitempty"`
|
||||
// Locale : The language that the user specified. Locale tags will be `IETF
|
||||
// language tags` <http://en.wikipedia.org/wiki/IETF_language_tag>.
|
||||
Locale string `json:"locale"`
|
||||
// ReferralLink : The user's `referral link`
|
||||
// <https://www.dropbox.com/referrals>.
|
||||
ReferralLink string `json:"referral_link"`
|
||||
// Team : If this account is a member of a team, information about that
|
||||
// team.
|
||||
Team *FullTeam `json:"team,omitempty"`
|
||||
// TeamMemberId : This account's unique team member id. This field will only
|
||||
// be present if `team` is present.
|
||||
TeamMemberId string `json:"team_member_id,omitempty"`
|
||||
// IsPaired : Whether the user has a personal and work account. If the
|
||||
// current account is personal, then `team` will always be nil, but
|
||||
// `is_paired` will indicate if a work account is linked.
|
||||
IsPaired bool `json:"is_paired"`
|
||||
// AccountType : What type of account this user has.
|
||||
AccountType *users_common.AccountType `json:"account_type"`
|
||||
}
|
||||
|
||||
// NewFullAccount returns a new FullAccount instance
|
||||
func NewFullAccount(AccountId string, Name *Name, Email string, EmailVerified bool, Disabled bool, Locale string, ReferralLink string, IsPaired bool, AccountType *users_common.AccountType) *FullAccount {
|
||||
s := new(FullAccount)
|
||||
s.AccountId = AccountId
|
||||
s.Name = Name
|
||||
s.Email = Email
|
||||
s.EmailVerified = EmailVerified
|
||||
s.Disabled = Disabled
|
||||
s.Locale = Locale
|
||||
s.ReferralLink = ReferralLink
|
||||
s.IsPaired = IsPaired
|
||||
s.AccountType = AccountType
|
||||
return s
|
||||
}
|
||||
|
||||
// Team : Information about a team.
|
||||
type Team struct {
|
||||
// Id : The team's unique ID.
|
||||
Id string `json:"id"`
|
||||
// Name : The name of the team.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// NewTeam returns a new Team instance
|
||||
func NewTeam(Id string, Name string) *Team {
|
||||
s := new(Team)
|
||||
s.Id = Id
|
||||
s.Name = Name
|
||||
return s
|
||||
}
|
||||
|
||||
// FullTeam : Detailed information about a team.
|
||||
type FullTeam struct {
|
||||
Team
|
||||
// SharingPolicies : Team policies governing sharing.
|
||||
SharingPolicies *team_policies.TeamSharingPolicies `json:"sharing_policies"`
|
||||
}
|
||||
|
||||
// NewFullTeam returns a new FullTeam instance
|
||||
func NewFullTeam(Id string, Name string, SharingPolicies *team_policies.TeamSharingPolicies) *FullTeam {
|
||||
s := new(FullTeam)
|
||||
s.Id = Id
|
||||
s.Name = Name
|
||||
s.SharingPolicies = SharingPolicies
|
||||
return s
|
||||
}
|
||||
|
||||
// GetAccountArg : has no documentation (yet)
|
||||
type GetAccountArg struct {
|
||||
// AccountId : A user's account identifier.
|
||||
AccountId string `json:"account_id"`
|
||||
}
|
||||
|
||||
// NewGetAccountArg returns a new GetAccountArg instance
|
||||
func NewGetAccountArg(AccountId string) *GetAccountArg {
|
||||
s := new(GetAccountArg)
|
||||
s.AccountId = AccountId
|
||||
return s
|
||||
}
|
||||
|
||||
// GetAccountBatchArg : has no documentation (yet)
|
||||
type GetAccountBatchArg struct {
|
||||
// AccountIds : List of user account identifiers. Should not contain any
|
||||
// duplicate account IDs.
|
||||
AccountIds []string `json:"account_ids"`
|
||||
}
|
||||
|
||||
// NewGetAccountBatchArg returns a new GetAccountBatchArg instance
|
||||
func NewGetAccountBatchArg(AccountIds []string) *GetAccountBatchArg {
|
||||
s := new(GetAccountBatchArg)
|
||||
s.AccountIds = AccountIds
|
||||
return s
|
||||
}
|
||||
|
||||
// GetAccountBatchError : has no documentation (yet)
|
||||
type GetAccountBatchError struct {
|
||||
dropbox.Tagged
|
||||
// NoAccount : The value is an account ID specified in
|
||||
// `GetAccountBatchArg.account_ids` that does not exist.
|
||||
NoAccount string `json:"no_account,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for GetAccountBatchError
|
||||
const (
|
||||
GetAccountBatchErrorNoAccount = "no_account"
|
||||
GetAccountBatchErrorOther = "other"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a GetAccountBatchError instance
|
||||
func (u *GetAccountBatchError) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "no_account":
|
||||
err = json.Unmarshal(body, &u.NoAccount)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAccountError : has no documentation (yet)
|
||||
type GetAccountError struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for GetAccountError
|
||||
const (
|
||||
GetAccountErrorNoAccount = "no_account"
|
||||
GetAccountErrorOther = "other"
|
||||
)
|
||||
|
||||
// IndividualSpaceAllocation : has no documentation (yet)
|
||||
type IndividualSpaceAllocation struct {
|
||||
// Allocated : The total space allocated to the user's account (bytes).
|
||||
Allocated uint64 `json:"allocated"`
|
||||
}
|
||||
|
||||
// NewIndividualSpaceAllocation returns a new IndividualSpaceAllocation instance
|
||||
func NewIndividualSpaceAllocation(Allocated uint64) *IndividualSpaceAllocation {
|
||||
s := new(IndividualSpaceAllocation)
|
||||
s.Allocated = Allocated
|
||||
return s
|
||||
}
|
||||
|
||||
// Name : Representations for a person's name to assist with
|
||||
// internationalization.
|
||||
type Name struct {
|
||||
// GivenName : Also known as a first name.
|
||||
GivenName string `json:"given_name"`
|
||||
// Surname : Also known as a last name or family name.
|
||||
Surname string `json:"surname"`
|
||||
// FamiliarName : Locale-dependent name. In the US, a person's familiar name
|
||||
// is their `given_name`, but elsewhere, it could be any combination of a
|
||||
// person's `given_name` and `surname`.
|
||||
FamiliarName string `json:"familiar_name"`
|
||||
// DisplayName : A name that can be used directly to represent the name of a
|
||||
// user's Dropbox account.
|
||||
DisplayName string `json:"display_name"`
|
||||
// AbbreviatedName : An abbreviated form of the person's name. Their
|
||||
// initials in most locales.
|
||||
AbbreviatedName string `json:"abbreviated_name"`
|
||||
}
|
||||
|
||||
// NewName returns a new Name instance
|
||||
func NewName(GivenName string, Surname string, FamiliarName string, DisplayName string, AbbreviatedName string) *Name {
|
||||
s := new(Name)
|
||||
s.GivenName = GivenName
|
||||
s.Surname = Surname
|
||||
s.FamiliarName = FamiliarName
|
||||
s.DisplayName = DisplayName
|
||||
s.AbbreviatedName = AbbreviatedName
|
||||
return s
|
||||
}
|
||||
|
||||
// SpaceAllocation : Space is allocated differently based on the type of
|
||||
// account.
|
||||
type SpaceAllocation struct {
|
||||
dropbox.Tagged
|
||||
// Individual : The user's space allocation applies only to their individual
|
||||
// account.
|
||||
Individual *IndividualSpaceAllocation `json:"individual,omitempty"`
|
||||
// Team : The user shares space with other members of their team.
|
||||
Team *TeamSpaceAllocation `json:"team,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for SpaceAllocation
|
||||
const (
|
||||
SpaceAllocationIndividual = "individual"
|
||||
SpaceAllocationTeam = "team"
|
||||
SpaceAllocationOther = "other"
|
||||
)
|
||||
|
||||
// UnmarshalJSON deserializes into a SpaceAllocation instance
|
||||
func (u *SpaceAllocation) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
// Individual : The user's space allocation applies only to their
|
||||
// individual account.
|
||||
Individual json.RawMessage `json:"individual,omitempty"`
|
||||
// Team : The user shares space with other members of their team.
|
||||
Team json.RawMessage `json:"team,omitempty"`
|
||||
}
|
||||
var w wrap
|
||||
var err error
|
||||
if err = json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "individual":
|
||||
err = json.Unmarshal(body, &u.Individual)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "team":
|
||||
err = json.Unmarshal(body, &u.Team)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SpaceUsage : Information about a user's space usage and quota.
|
||||
type SpaceUsage struct {
|
||||
// Used : The user's total space usage (bytes).
|
||||
Used uint64 `json:"used"`
|
||||
// Allocation : The user's space allocation.
|
||||
Allocation *SpaceAllocation `json:"allocation"`
|
||||
}
|
||||
|
||||
// NewSpaceUsage returns a new SpaceUsage instance
|
||||
func NewSpaceUsage(Used uint64, Allocation *SpaceAllocation) *SpaceUsage {
|
||||
s := new(SpaceUsage)
|
||||
s.Used = Used
|
||||
s.Allocation = Allocation
|
||||
return s
|
||||
}
|
||||
|
||||
// TeamSpaceAllocation : has no documentation (yet)
|
||||
type TeamSpaceAllocation struct {
|
||||
// Used : The total space currently used by the user's team (bytes).
|
||||
Used uint64 `json:"used"`
|
||||
// Allocated : The total space allocated to the user's team (bytes).
|
||||
Allocated uint64 `json:"allocated"`
|
||||
}
|
||||
|
||||
// NewTeamSpaceAllocation returns a new TeamSpaceAllocation instance
|
||||
func NewTeamSpaceAllocation(Used uint64, Allocated uint64) *TeamSpaceAllocation {
|
||||
s := new(TeamSpaceAllocation)
|
||||
s.Used = Used
|
||||
s.Allocated = Allocated
|
||||
return s
|
||||
}
|
37
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/users_common/types.go
generated
vendored
Normal file
37
vendor/github.com/ncw/dropbox-sdk-go-unofficial/dropbox/users_common/types.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package users_common : This namespace contains common data types used within
|
||||
// the users namespace
|
||||
package users_common
|
||||
|
||||
import "github.com/ncw/dropbox-sdk-go-unofficial/dropbox"
|
||||
|
||||
// AccountType : What type of account this user has.
|
||||
type AccountType struct {
|
||||
dropbox.Tagged
|
||||
}
|
||||
|
||||
// Valid tag values for AccountType
|
||||
const (
|
||||
AccountTypeBasic = "basic"
|
||||
AccountTypePro = "pro"
|
||||
AccountTypeBusiness = "business"
|
||||
)
|
237
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/README.md
generated
vendored
Normal file
237
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/README.md
generated
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
# Dropbox Go SDK Generator
|
||||
|
||||
This directory contains the [Stone](https://github.com/dropbox/stone) code generators
|
||||
used to programmatically generate the [Dropbox Go SDK](https://github.com/dropbox/dropbox-sdk-go).
|
||||
|
||||
## Requirements
|
||||
|
||||
* While not a hard requirement, this repo currently assumes `python3` in the path.
|
||||
* Assumes you have already installed [Stone](https://github.com/dropbox/stone)
|
||||
* Requires [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) to fix up imports in the auto-generated code
|
||||
|
||||
## Basic Setup
|
||||
|
||||
. Clone this repo
|
||||
. Run `git submodule init` followed by `git submodule update`
|
||||
. Run `./generate-sdk.sh` to generate code under `../dropbox`
|
||||
|
||||
## Generated Code
|
||||
|
||||
### Basic Types
|
||||
|
||||
Here is how Stone [basic types](https://github.com/dropbox/stone/blob/master/doc/lang_ref.rst#basic-types) map to Go types:
|
||||
|
||||
Stone Type | Go Type
|
||||
---------- | -------
|
||||
Int32/Int64/UInt32/UInt64 | int32/int64/uint32/uint64
|
||||
Float32/Float64 | float32/float64
|
||||
Boolean | bool
|
||||
String | string
|
||||
Timestamp | time.Time
|
||||
Void | struct{}
|
||||
|
||||
### Structs
|
||||
|
||||
Stone [structs](https://github.com/dropbox/stone/blob/master/doc/lang_ref.rst#struct) are represented as Go [structs](https://gobyexample.com/structs) in a relatively straight-forward manner. Each struct member is exported and also gets assigned the correct json tag. The latter is used for serializing requests and deserializing responses. Non-primitive types are represented as pointers to the corresponding type.
|
||||
|
||||
```
|
||||
struct Account
|
||||
"The amount of detail revealed about an account depends on the user
|
||||
being queried and the user making the query."
|
||||
|
||||
account_id AccountId
|
||||
"The user's unique Dropbox ID."
|
||||
name Name
|
||||
"Details of a user's name."
|
||||
```
|
||||
|
||||
```go
|
||||
// The amount of detail revealed about an account depends on the user being
|
||||
// queried and the user making the query.
|
||||
type Account struct {
|
||||
// The user's unique Dropbox ID.
|
||||
AccountId string `json:"account_id"`
|
||||
// Details of a user's name.
|
||||
Name *Name `json:"name"`
|
||||
}
|
||||
```
|
||||
|
||||
#### Inheritance
|
||||
|
||||
Stone supports [struct inheritance](https://github.com/dropbox/stone/blob/master/doc/lang_ref.rst#inheritance). In Go, we support this via [embedding](https://golang.org/doc/effective_go.html#embedding)
|
||||
|
||||
```
|
||||
struct BasicAccount extends Account
|
||||
"Basic information about any account."
|
||||
|
||||
is_teammate Boolean
|
||||
"Whether this user is a teammate of the current user. If this account
|
||||
is the current user's account, then this will be :val:`true`."
|
||||
```
|
||||
|
||||
```go
|
||||
// Basic information about any account.
|
||||
type BasicAccount struct {
|
||||
Account
|
||||
// Whether this user is a teammate of the current user. If this account is
|
||||
// the current user's account, then this will be `True`.
|
||||
IsTeammate bool `json:"is_teammate"`
|
||||
```
|
||||
|
||||
### Unions
|
||||
|
||||
Stone https://github.com/dropbox/stone/blob/master/doc/lang_ref.rst#union[unions] are bit more complex as Go doesn't have native support for union types (tagged or otherwise). We declare a union as a Go struct with all the possible fields as pointer types, and then use the tag value to populate the correct field during deserialization. This necessitates the use of an intermediate wrapper struct for the deserialization to work correctly, see below for a concrete example.
|
||||
|
||||
```
|
||||
union SpaceAllocation
|
||||
"Space is allocated differently based on the type of account."
|
||||
|
||||
individual IndividualSpaceAllocation
|
||||
"The user's space allocation applies only to their individual account."
|
||||
team TeamSpaceAllocation
|
||||
"The user shares space with other members of their team."
|
||||
```
|
||||
|
||||
```go
|
||||
// Space is allocated differently based on the type of account.
|
||||
type SpaceAllocation struct {
|
||||
dropbox.Tagged
|
||||
// The user's space allocation applies only to their individual account.
|
||||
Individual *IndividualSpaceAllocation `json:"individual,omitempty"`
|
||||
// The user shares space with other members of their team.
|
||||
Team *TeamSpaceAllocation `json:"team,omitempty"`
|
||||
}
|
||||
|
||||
// Valid tag values for `SpaceAllocation`
|
||||
const (
|
||||
SpaceAllocation_Individual = "individual"
|
||||
SpaceAllocation_Team = "team"
|
||||
SpaceAllocation_Other = "other"
|
||||
)
|
||||
|
||||
func (u *SpaceAllocation) UnmarshalJSON(body []byte) error {
|
||||
type wrap struct {
|
||||
dropbox.Tagged
|
||||
// The user's space allocation applies only to their individual account.
|
||||
Individual json.RawMessage `json:"individual,omitempty"`
|
||||
// The user shares space with other members of their team.
|
||||
Team json.RawMessage `json:"team,omitempty"`
|
||||
}
|
||||
var w wrap
|
||||
if err := json.Unmarshal(body, &w); err != nil {
|
||||
return err
|
||||
}
|
||||
u.Tag = w.Tag
|
||||
switch u.Tag {
|
||||
case "individual":
|
||||
if err := json.Unmarshal(body, &u.Individual); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case "team":
|
||||
if err := json.Unmarshal(body, &u.Team); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
### Struct with Enumerated Subtypes
|
||||
|
||||
Per the https://github.com/dropbox/stone/blob/master/doc/lang_ref.rst#struct-polymorphism[spec], structs with enumerated subtypes are a mechanism of inheritance:
|
||||
|
||||
> If a struct enumerates its subtypes, an instance of any subtype will satisfy the type constraint. This is useful when wanting to discriminate amongst types that are part of the same hierarchy while simultaneously being able to avoid discriminating when accessing common fields.
|
||||
|
||||
To represent structs with enumerated subtypes in Go, we use a combination of Go interface types and unions as implemented above. Considering the following:
|
||||
|
||||
```
|
||||
struct Metadata
|
||||
union
|
||||
file FileMetadata
|
||||
folder FolderMetadata
|
||||
deleted DeletedMetadata # Used by list_folder* and search
|
||||
|
||||
name String
|
||||
path_lower String?
|
||||
path_display String?
|
||||
parent_shared_folder_id common.SharedFolderId?
|
||||
|
||||
struct FileMetadata extends Metadata
|
||||
id Id
|
||||
client_modified common.DropboxTimestamp
|
||||
...
|
||||
```
|
||||
|
||||
In this case, `FileMetadata`, `FolderMetadata` etc are subtypes of `Metadata`. Specifically, any subtype can be used where a parent type is expected. Thus, if `list_folder` returns a list of `Metadata`s, we should be able to parse and "upcast" to one of the enumerated subtypes.
|
||||
|
||||
First, we define structs to represent the base and enumerated types as we did for inherited structs above:
|
||||
|
||||
```go
|
||||
type Metadata struct {
|
||||
Name string `json:"name"`
|
||||
PathLower string `json:"path_lower,omitempty"`
|
||||
PathDisplay string `json:"path_display,omitempty"`
|
||||
ParentSharedFolderId string `json:"parent_shared_folder_id,omitempty"`
|
||||
}
|
||||
|
||||
type FileMetadata struct {
|
||||
Metadata
|
||||
Id string `json:"id"`
|
||||
ClientModified time.Time `json:"client_modified"`
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Next, we define an interface type with a dummy method and ensure that both the base and the subtypes implement the interface:
|
||||
|
||||
```go
|
||||
type IsMetadata interface {
|
||||
IsMetadata()
|
||||
}
|
||||
|
||||
func (u *Metadata) IsMetadata() {} // Subtypes get this for free due to embedding
|
||||
```
|
||||
|
||||
At this point, types or methods that accept/return a struct with enumerated subtypes can use the interface type instead. For instance:
|
||||
|
||||
```go
|
||||
func GetMetadata(arg *GetMetadataArg) (res IsMetadata, err error) {...}
|
||||
|
||||
type ListFolderResult struct {
|
||||
// The files and (direct) subfolders in the folder.
|
||||
Entries []IsMetadata `json:"entries"`
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Finally, to actually deserialize a bag of bytes into the appropriate type or subtype, we use a trick similar to how we handle unions above.
|
||||
|
||||
```go
|
||||
type metadataUnion struct {
|
||||
dropbox.Tagged
|
||||
File *FileMetadata `json:"file,omitempty"`
|
||||
Folder *FolderMetadata `json:"folder,omitempty"`
|
||||
Deleted *DeletedMetadata `json:"deleted,omitempty"`
|
||||
}
|
||||
|
||||
func (u *metadataUnion) UnmarshalJSON(body []byte) error {...}
|
||||
|
||||
func (dbx *apiImpl) GetMetadata(arg *GetMetadataArg) (res IsMetadata, err error) {
|
||||
...
|
||||
var tmp metadataUnion
|
||||
err = json.Unmarshal(body, &tmp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch tmp.Tag {
|
||||
case "file":
|
||||
res = tmp.File
|
||||
case "folder":
|
||||
res = tmp.Folder
|
||||
case "deleted":
|
||||
res = tmp.Deleted
|
||||
}
|
||||
}
|
||||
```
|
25
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/generate-sdk.sh
generated
vendored
Executable file
25
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/generate-sdk.sh
generated
vendored
Executable file
@ -0,0 +1,25 @@
|
||||
#! /usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 0 ]]; then
|
||||
echo "$0: Not expecting any command-line arguments, got $#." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
loc=$(realpath -e $0)
|
||||
base_dir=$(dirname "$loc")
|
||||
spec_dir="$base_dir/dropbox-api-spec"
|
||||
gen_dir=$(dirname ${base_dir})/dropbox
|
||||
|
||||
stone -v -a :all go_types.stoneg.py "$gen_dir" "$spec_dir"/*.stone
|
||||
stone -v -a :all go_client.stoneg.py "$gen_dir" "$spec_dir"/*.stone
|
||||
|
||||
# Update SDK and API spec versions
|
||||
sdk_version="1.0.0-beta"
|
||||
pushd ${spec_dir}
|
||||
spec_version=$(git rev-parse --short HEAD)
|
||||
popd
|
||||
|
||||
sed -i -e "s/UNKNOWN SDK VERSION/${sdk_version}/" \
|
||||
-e "s/UNKNOWN SPEC VERSION/${spec_version}/" ${gen_dir}/sdk.go
|
||||
goimports -l -w ${gen_dir}
|
207
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_client.stoneg.py
generated
vendored
Normal file
207
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_client.stoneg.py
generated
vendored
Normal file
@ -0,0 +1,207 @@
|
||||
import os
|
||||
|
||||
from stone.generator import CodeGenerator
|
||||
from stone.data_type import (
|
||||
is_void_type,
|
||||
is_struct_type
|
||||
)
|
||||
|
||||
from go_helpers import (
|
||||
HEADER,
|
||||
fmt_type,
|
||||
fmt_var,
|
||||
generate_doc,
|
||||
)
|
||||
|
||||
|
||||
class GoClientGenerator(CodeGenerator):
|
||||
def generate(self, api):
|
||||
for namespace in api.namespaces.values():
|
||||
if len(namespace.routes) > 0:
|
||||
self._generate_client(namespace)
|
||||
|
||||
def _generate_client(self, namespace):
|
||||
file_name = os.path.join(self.target_folder_path, namespace.name,
|
||||
'client.go')
|
||||
with self.output_to_relative_path(file_name):
|
||||
self.emit_raw(HEADER)
|
||||
self.emit()
|
||||
self.emit('package %s' % namespace.name)
|
||||
self.emit()
|
||||
|
||||
self.emit('// Client interface describes all routes in this namespace')
|
||||
with self.block('type Client interface'):
|
||||
for route in namespace.routes:
|
||||
generate_doc(self, route)
|
||||
self.emit(self._generate_route_signature(namespace, route))
|
||||
self.emit()
|
||||
|
||||
self.emit('type apiImpl dropbox.Context')
|
||||
for route in namespace.routes:
|
||||
self._generate_route(namespace, route)
|
||||
self.emit('// New returns a Client implementation for this namespace')
|
||||
with self.block('func New(c dropbox.Config) *apiImpl'):
|
||||
self.emit('ctx := apiImpl(dropbox.NewContext(c))')
|
||||
self.emit('return &ctx')
|
||||
|
||||
def _generate_route_signature(self, namespace, route):
|
||||
req = fmt_type(route.arg_data_type, namespace)
|
||||
res = fmt_type(route.result_data_type, namespace, use_interface=True)
|
||||
fn = fmt_var(route.name)
|
||||
style = route.attrs.get('style', 'rpc')
|
||||
|
||||
arg = '' if is_void_type(route.arg_data_type) else 'arg {req}'
|
||||
ret = '(err error)' if is_void_type(route.result_data_type) else \
|
||||
'(res {res}, err error)'
|
||||
signature = '{fn}(' + arg + ') ' + ret
|
||||
if style == 'download':
|
||||
signature = '{fn}(' + arg + \
|
||||
') (res {res}, content io.ReadCloser, err error)'
|
||||
elif style == 'upload':
|
||||
signature = '{fn}(' + arg + ', content io.Reader) ' + ret
|
||||
if is_void_type(route.arg_data_type):
|
||||
signature = '{fn}(content io.Reader) ' + ret
|
||||
return signature.format(fn=fn, req=req, res=res)
|
||||
|
||||
|
||||
def _generate_route(self, namespace, route):
|
||||
out = self.emit
|
||||
fn = fmt_var(route.name)
|
||||
err = fmt_type(route.error_data_type, namespace)
|
||||
out('//%sAPIError is an error-wrapper for the %s route' %
|
||||
(fn, route.name))
|
||||
with self.block('type {fn}APIError struct'.format(fn=fn)):
|
||||
out('dropbox.APIError')
|
||||
out('EndpointError {err} `json:"error"`'.format(err=err))
|
||||
out()
|
||||
|
||||
signature = 'func (dbx *apiImpl) ' + self._generate_route_signature(
|
||||
namespace, route)
|
||||
with self.block(signature):
|
||||
out('cli := dbx.Client')
|
||||
out()
|
||||
|
||||
self._generate_request(namespace, route)
|
||||
self._generate_post()
|
||||
self._generate_response(route)
|
||||
ok_check = 'if resp.StatusCode == http.StatusOK'
|
||||
if fn == "Download":
|
||||
ok_check += ' || resp.StatusCode == http.StatusPartialContent'
|
||||
with self.block(ok_check):
|
||||
self._generate_result(route)
|
||||
self._generate_error_handling(route)
|
||||
|
||||
out()
|
||||
|
||||
def _generate_request(self, namespace, route):
|
||||
out = self.emit
|
||||
auth = route.attrs.get('auth', '')
|
||||
host = route.attrs.get('host', 'api')
|
||||
style = route.attrs.get('style', 'rpc')
|
||||
|
||||
body = 'nil'
|
||||
if not is_void_type(route.arg_data_type):
|
||||
with self.block('if dbx.Config.Verbose'):
|
||||
out('log.Printf("arg: %v", arg)')
|
||||
out('b, err := json.Marshal(arg)')
|
||||
with self.block('if err != nil'):
|
||||
out('return')
|
||||
out()
|
||||
if host != 'content':
|
||||
body = 'bytes.NewReader(b)'
|
||||
if style == 'upload':
|
||||
body = 'content'
|
||||
|
||||
headers = {}
|
||||
if not is_void_type(route.arg_data_type):
|
||||
if host == 'content':
|
||||
headers["Dropbox-API-Arg"] = "string(b)"
|
||||
else:
|
||||
headers["Content-Type"] = '"application/json"'
|
||||
if style == 'upload':
|
||||
headers["Content-Type"] = '"application/octet-stream"'
|
||||
|
||||
out('headers := map[string]string{')
|
||||
for k, v in sorted(headers.items()):
|
||||
out('\t"{}": {},'.format(k, v))
|
||||
out('}')
|
||||
if fmt_var(route.name) == "Download":
|
||||
out('for k, v := range arg.ExtraHeaders { headers[k] = v }')
|
||||
if auth != 'noauth' and auth != 'team':
|
||||
with self.block('if dbx.Config.AsMemberID != ""'):
|
||||
out('headers["Dropbox-API-Select-User"] = dbx.Config.AsMemberID')
|
||||
out()
|
||||
|
||||
authed = 'false' if auth == 'noauth' else 'true'
|
||||
out('req, err := (*dropbox.Context)(dbx).NewRequest("{}", "{}", {}, "{}", "{}", headers, {})'.format(
|
||||
host, style, authed, namespace.name, route.name, body))
|
||||
with self.block('if err != nil'):
|
||||
out('return')
|
||||
with self.block('if dbx.Config.Verbose'):
|
||||
out('log.Printf("req: %v", req)')
|
||||
out()
|
||||
|
||||
def _generate_post(self):
|
||||
out = self.emit
|
||||
|
||||
out('resp, err := cli.Do(req)')
|
||||
with self.block('if dbx.Config.Verbose'):
|
||||
out('log.Printf("resp: %v", resp)')
|
||||
|
||||
with self.block('if err != nil'):
|
||||
out('return')
|
||||
out()
|
||||
|
||||
def _generate_response(self, route):
|
||||
out = self.emit
|
||||
style = route.attrs.get('style', 'rpc')
|
||||
if style == 'download':
|
||||
out('body := []byte(resp.Header.Get("Dropbox-API-Result"))')
|
||||
out('content = resp.Body')
|
||||
else:
|
||||
out('defer resp.Body.Close()')
|
||||
with self.block('body, err := ioutil.ReadAll(resp.Body);'
|
||||
'if err != nil'):
|
||||
out('return')
|
||||
out()
|
||||
with self.block('if dbx.Config.Verbose'):
|
||||
out('log.Printf("body: %s", body)')
|
||||
|
||||
def _generate_error_handling(self, route):
|
||||
out = self.emit
|
||||
with self.block('if resp.StatusCode == http.StatusConflict'):
|
||||
out('var apiError %sAPIError' % fmt_var(route.name))
|
||||
with self.block('err = json.Unmarshal(body, &apiError);'
|
||||
'if err != nil'):
|
||||
out('return')
|
||||
out('err = apiError')
|
||||
out('return')
|
||||
out('var apiError dropbox.APIError')
|
||||
with self.block('if resp.StatusCode == http.StatusBadRequest'):
|
||||
out('apiError.ErrorSummary = string(body)')
|
||||
out('err = apiError')
|
||||
out('return')
|
||||
with self.block('err = json.Unmarshal(body, &apiError);'
|
||||
'if err != nil'):
|
||||
out('return')
|
||||
out('err = apiError')
|
||||
out('return')
|
||||
|
||||
def _generate_result(self, route):
|
||||
out = self.emit
|
||||
if is_struct_type(route.result_data_type) and \
|
||||
route.result_data_type.has_enumerated_subtypes():
|
||||
out('var tmp %sUnion' % fmt_var(route.result_data_type.name, export=False))
|
||||
with self.block('err = json.Unmarshal(body, &tmp);'
|
||||
'if err != nil'):
|
||||
out('return')
|
||||
with self.block('switch tmp.Tag'):
|
||||
for t in route.result_data_type.get_enumerated_subtypes():
|
||||
with self.block('case "%s":' % t.name, delim=(None, None)):
|
||||
self.emit('res = tmp.%s' % fmt_var(t.name))
|
||||
elif not is_void_type(route.result_data_type):
|
||||
with self.block('err = json.Unmarshal(body, &res);'
|
||||
'if err != nil'):
|
||||
out('return')
|
||||
out()
|
||||
out('return')
|
134
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_helpers.py
generated
vendored
Normal file
134
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_helpers.py
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
from stone.api import ApiNamespace
|
||||
from stone.data_type import (
|
||||
Boolean,
|
||||
Float32,
|
||||
Float64,
|
||||
Int32,
|
||||
Int64,
|
||||
String,
|
||||
Timestamp,
|
||||
UInt32,
|
||||
UInt64,
|
||||
unwrap_nullable,
|
||||
is_composite_type,
|
||||
is_list_type,
|
||||
is_struct_type,
|
||||
Void,
|
||||
)
|
||||
from stone.target import helpers
|
||||
|
||||
HEADER = """\
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
"""
|
||||
|
||||
_reserved_keywords = {
|
||||
'break', 'default', 'func', 'interface', 'select',
|
||||
'case', 'defer', 'go', 'map', 'struct',
|
||||
'chan', 'else', 'goto', 'package', 'switch',
|
||||
'const', 'fallthrough', 'if', 'range', 'type',
|
||||
'continue', 'for', 'import', 'return', 'var',
|
||||
}
|
||||
|
||||
_type_table = {
|
||||
UInt64: 'uint64',
|
||||
Int64: 'int64',
|
||||
UInt32: 'uint32',
|
||||
Int32: 'int32',
|
||||
Float64: 'float64',
|
||||
Float32: 'float32',
|
||||
Boolean: 'bool',
|
||||
String: 'string',
|
||||
Timestamp: 'time.Time',
|
||||
Void: 'struct{}',
|
||||
}
|
||||
|
||||
|
||||
def _rename_if_reserved(s):
|
||||
if s in _reserved_keywords:
|
||||
return s + '_'
|
||||
else:
|
||||
return s
|
||||
|
||||
|
||||
def fmt_type(data_type, namespace=None, use_interface=False):
|
||||
data_type, nullable = unwrap_nullable(data_type)
|
||||
if is_list_type(data_type):
|
||||
return '[]%s' % fmt_type(data_type.data_type, namespace, use_interface)
|
||||
type_name = data_type.name
|
||||
if use_interface and _needs_base_type(data_type):
|
||||
type_name = 'Is' + type_name
|
||||
if is_composite_type(data_type) and namespace is not None and \
|
||||
namespace.name != data_type.namespace.name:
|
||||
type_name = data_type.namespace.name + '.' + type_name
|
||||
if use_interface and _needs_base_type(data_type):
|
||||
return _type_table.get(data_type.__class__, type_name)
|
||||
else:
|
||||
return _type_table.get(data_type.__class__, '*' + type_name)
|
||||
|
||||
|
||||
def fmt_var(name, export=True, check_reserved=False):
|
||||
s = helpers.fmt_pascal(name) if export else helpers.fmt_camel(name)
|
||||
return _rename_if_reserved(s) if check_reserved else s
|
||||
|
||||
|
||||
def _doc_handler(tag, val):
|
||||
if tag == 'type':
|
||||
return '`{}`'.format(val)
|
||||
elif tag == 'route':
|
||||
return '`{}`'.format(helpers.fmt_camel(val))
|
||||
elif tag == 'link':
|
||||
anchor, link = val.rsplit(' ', 1)
|
||||
return '`{}` <{}>'.format(anchor, link)
|
||||
elif tag == 'val':
|
||||
if val == 'null':
|
||||
return 'nil'
|
||||
else:
|
||||
return val
|
||||
elif tag == 'field':
|
||||
return '`{}`'.format(val)
|
||||
else:
|
||||
raise RuntimeError('Unknown doc ref tag %r' % tag)
|
||||
|
||||
|
||||
def generate_doc(code_generator, t):
|
||||
doc = t.doc
|
||||
if doc is None:
|
||||
doc = 'has no documentation (yet)'
|
||||
doc = code_generator.process_doc(doc, _doc_handler)
|
||||
d = '%s : %s' % (fmt_var(t.name), doc)
|
||||
if isinstance(t, ApiNamespace):
|
||||
d = 'Package %s : %s' % (t.name, doc)
|
||||
code_generator.emit_wrapped_text(d, prefix='// ')
|
||||
|
||||
|
||||
def _needs_base_type(data_type):
|
||||
if is_struct_type(data_type) and data_type.has_enumerated_subtypes():
|
||||
return True
|
||||
if is_list_type(data_type):
|
||||
return _needs_base_type(data_type.data_type)
|
||||
return False
|
||||
|
||||
|
||||
def needs_base_type(struct):
|
||||
for field in struct.fields:
|
||||
if _needs_base_type(field.data_type):
|
||||
return True
|
||||
return False
|
75
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_rsrc/files/metadata.go
generated
vendored
Normal file
75
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_rsrc/files/metadata.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package files
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type listFolderResult struct {
|
||||
Entries []metadataUnion `json:"entries"`
|
||||
Cursor string `json:"cursor"`
|
||||
HasMore bool `json:"has_more"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes into a ListFolderResult instance
|
||||
func (r *ListFolderResult) UnmarshalJSON(b []byte) error {
|
||||
var l listFolderResult
|
||||
if err := json.Unmarshal(b, &l); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Cursor = l.Cursor
|
||||
r.HasMore = l.HasMore
|
||||
r.Entries = make([]IsMetadata, len(l.Entries))
|
||||
for i, e := range l.Entries {
|
||||
switch e.Tag {
|
||||
case "file":
|
||||
r.Entries[i] = e.File
|
||||
case "folder":
|
||||
r.Entries[i] = e.Folder
|
||||
case "deleted":
|
||||
r.Entries[i] = e.Deleted
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type searchMatch struct {
|
||||
MatchType *SearchMatchType `json:"match_type"`
|
||||
Metadata metadataUnion `json:"metadata"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes into a SearchMatch instance
|
||||
func (s *SearchMatch) UnmarshalJSON(b []byte) error {
|
||||
var m searchMatch
|
||||
if err := json.Unmarshal(b, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
s.MatchType = m.MatchType
|
||||
e := m.Metadata
|
||||
switch e.Tag {
|
||||
case "file":
|
||||
s.Metadata = e.File
|
||||
case "folder":
|
||||
s.Metadata = e.Folder
|
||||
case "deleted":
|
||||
s.Metadata = e.Deleted
|
||||
}
|
||||
return nil
|
||||
}
|
170
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_rsrc/sdk.go
generated
vendored
Normal file
170
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_rsrc/sdk.go
generated
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
apiVersion = 2
|
||||
defaultDomain = ".dropboxapi.com"
|
||||
hostAPI = "api"
|
||||
hostContent = "content"
|
||||
hostNotify = "notify"
|
||||
sdkVersion = "UNKNOWN SDK VERSION"
|
||||
specVersion = "UNKNOWN SPEC VERSION"
|
||||
)
|
||||
|
||||
// Version returns the current SDK version and API Spec version
|
||||
func Version() (string, string) {
|
||||
return sdkVersion, specVersion
|
||||
}
|
||||
|
||||
// Config contains parameters for configuring the SDK.
|
||||
type Config struct {
|
||||
// OAuth2 access token
|
||||
Token string
|
||||
// Enable verbose logging in SDK
|
||||
Verbose bool
|
||||
// Used with APIs that support operations as another user
|
||||
AsMemberID string
|
||||
// No need to set -- for testing only
|
||||
Domain string
|
||||
// No need to set -- for testing only
|
||||
Client *http.Client
|
||||
// No need to set -- for testing only
|
||||
HeaderGenerator func(hostType string, style string, namespace string, route string) map[string]string
|
||||
// No need to set -- for testing only
|
||||
URLGenerator func(hostType string, style string, namespace string, route string) string
|
||||
}
|
||||
|
||||
// Context is the base client context used to implement per-namespace clients.
|
||||
type Context struct {
|
||||
Config Config
|
||||
Client *http.Client
|
||||
HeaderGenerator func(hostType string, style string, namespace string, route string) map[string]string
|
||||
URLGenerator func(hostType string, style string, namespace string, route string) string
|
||||
}
|
||||
|
||||
// NewRequest returns an appropriate Request object for the given namespace/route.
|
||||
func (c *Context) NewRequest(
|
||||
hostType string,
|
||||
style string,
|
||||
authed bool,
|
||||
namespace string,
|
||||
route string,
|
||||
headers map[string]string,
|
||||
body io.Reader,
|
||||
) (*http.Request, error) {
|
||||
url := c.URLGenerator(hostType, style, namespace, route)
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
for k, v := range c.HeaderGenerator(hostType, style, namespace, route) {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
if req.Header.Get("Host") != "" {
|
||||
req.Host = req.Header.Get("Host")
|
||||
}
|
||||
if !authed {
|
||||
req.Header.Del("Authorization")
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// NewContext returns a new Context with the given Config.
|
||||
func NewContext(c Config) Context {
|
||||
domain := c.Domain
|
||||
if domain == "" {
|
||||
domain = defaultDomain
|
||||
}
|
||||
|
||||
client := c.Client
|
||||
if client == nil {
|
||||
var conf = &oauth2.Config{Endpoint: OAuthEndpoint(domain)}
|
||||
tok := &oauth2.Token{AccessToken: c.Token}
|
||||
client = conf.Client(oauth2.NoContext, tok)
|
||||
}
|
||||
|
||||
headerGenerator := c.HeaderGenerator
|
||||
if headerGenerator == nil {
|
||||
headerGenerator = func(hostType string, style string, namespace string, route string) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
}
|
||||
|
||||
urlGenerator := c.URLGenerator
|
||||
if urlGenerator == nil {
|
||||
hostMap := map[string]string{
|
||||
hostAPI: hostAPI + domain,
|
||||
hostContent: hostContent + domain,
|
||||
hostNotify: hostNotify + domain,
|
||||
}
|
||||
urlGenerator = func(hostType string, style string, namespace string, route string) string {
|
||||
fqHost := hostMap[hostType]
|
||||
return fmt.Sprintf("https://%s/%d/%s/%s", fqHost, apiVersion, namespace, route)
|
||||
}
|
||||
}
|
||||
|
||||
return Context{c, client, headerGenerator, urlGenerator}
|
||||
}
|
||||
|
||||
// OAuthEndpoint constructs an `oauth2.Endpoint` for the given domain
|
||||
func OAuthEndpoint(domain string) oauth2.Endpoint {
|
||||
if domain == "" {
|
||||
domain = defaultDomain
|
||||
}
|
||||
authURL := fmt.Sprintf("https://meta%s/1/oauth2/authorize", domain)
|
||||
tokenURL := fmt.Sprintf("https://api%s/1/oauth2/token", domain)
|
||||
if domain == defaultDomain {
|
||||
authURL = "https://www.dropbox.com/1/oauth2/authorize"
|
||||
}
|
||||
return oauth2.Endpoint{AuthURL: authURL, TokenURL: tokenURL}
|
||||
}
|
||||
|
||||
// Tagged is used for tagged unions.
|
||||
type Tagged struct {
|
||||
Tag string `json:".tag"`
|
||||
}
|
||||
|
||||
// APIError is the base type for endpoint-specific errors.
|
||||
type APIError struct {
|
||||
ErrorSummary string `json:"error_summary"`
|
||||
}
|
||||
|
||||
func (e APIError) Error() string {
|
||||
return e.ErrorSummary
|
||||
}
|
||||
|
||||
func init() {
|
||||
// These are not registered in the oauth library by default
|
||||
oauth2.RegisterBrokenAuthHeaderProvider("https://api.dropboxapi.com")
|
||||
oauth2.RegisterBrokenAuthHeaderProvider("https://api-dbdev.dev.corp.dropbox.com")
|
||||
}
|
49
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_rsrc/sharing/metadata.go
generated
vendored
Normal file
49
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_rsrc/sharing/metadata.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) Dropbox, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package sharing
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type listSharedLinksResult struct {
|
||||
Links []sharedLinkMetadataUnion `json:"links"`
|
||||
HasMore bool `json:"has_more"`
|
||||
Cursor string `json:"cursor,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes into a ListSharedLinksResult instance
|
||||
func (r *ListSharedLinksResult) UnmarshalJSON(b []byte) error {
|
||||
var l listSharedLinksResult
|
||||
if err := json.Unmarshal(b, &l); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Cursor = l.Cursor
|
||||
r.HasMore = l.HasMore
|
||||
r.Links = make([]IsSharedLinkMetadata, len(l.Links))
|
||||
for i, e := range l.Links {
|
||||
switch e.Tag {
|
||||
case "file":
|
||||
r.Links[i] = e.File
|
||||
case "folder":
|
||||
r.Links[i] = e.Folder
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
198
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_types.stoneg.py
generated
vendored
Normal file
198
vendor/github.com/ncw/dropbox-sdk-go-unofficial/generator/go_types.stoneg.py
generated
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from stone.generator import CodeGenerator
|
||||
from stone.data_type import (
|
||||
is_boolean_type,
|
||||
is_nullable_type,
|
||||
is_primitive_type,
|
||||
is_struct_type,
|
||||
is_union_type,
|
||||
is_void_type,
|
||||
)
|
||||
|
||||
from go_helpers import (
|
||||
HEADER,
|
||||
fmt_type,
|
||||
fmt_var,
|
||||
generate_doc,
|
||||
)
|
||||
|
||||
|
||||
class GoTypesGenerator(CodeGenerator):
|
||||
def generate(self, api):
|
||||
rsrc_folder = os.path.join(os.path.dirname(__file__), 'go_rsrc')
|
||||
shutil.copy(os.path.join(rsrc_folder, 'sdk.go'),
|
||||
self.target_folder_path)
|
||||
for namespace in api.namespaces.values():
|
||||
self._generate_namespace(namespace)
|
||||
if namespace.name == 'files' or namespace.name == 'sharing':
|
||||
self.logger.info('Copying metadata.go to files')
|
||||
shutil.copy(os.path.join(rsrc_folder, namespace.name, 'metadata.go'),
|
||||
os.path.join(self.target_folder_path, namespace.name))
|
||||
|
||||
def _generate_namespace(self, namespace):
|
||||
file_name = os.path.join(self.target_folder_path, namespace.name,
|
||||
'types.go')
|
||||
with self.output_to_relative_path(file_name):
|
||||
self.emit_raw(HEADER)
|
||||
self.emit()
|
||||
generate_doc(self, namespace)
|
||||
self.emit('package %s' % namespace.name)
|
||||
self.emit()
|
||||
|
||||
for data_type in namespace.linearize_data_types():
|
||||
self._generate_data_type(data_type)
|
||||
|
||||
def _generate_data_type(self, data_type):
|
||||
generate_doc(self, data_type)
|
||||
if is_struct_type(data_type):
|
||||
self._generate_struct(data_type)
|
||||
if data_type.has_enumerated_subtypes():
|
||||
self._generate_base_type(data_type)
|
||||
elif is_union_type(data_type):
|
||||
self._generate_union(data_type)
|
||||
else:
|
||||
self.logger.info("Unhandled data type", data_type)
|
||||
|
||||
def _generate_base_type(self, base):
|
||||
t = fmt_type(base).lstrip('*')
|
||||
self.emit('// Is{0} is the interface type for {0} and its subtypes'.format(t))
|
||||
with self.block('type Is%s interface' % t):
|
||||
self.emit('Is%s()' % t)
|
||||
self.emit()
|
||||
self.emit('// Is{0} implements the Is{0} interface'.format(t))
|
||||
self.emit("func (u *{0}) Is{0}() {{}}".format(t))
|
||||
self.emit()
|
||||
self._generate_union_helper(base)
|
||||
|
||||
self.emit("// Is{0}FromJSON converts JSON to a concrete Is{0} instance".format(t))
|
||||
with self.block("func Is{0}FromJSON(data []byte) (Is{0}, error)".format(t)):
|
||||
name = fmt_var(t, export=False) + 'Union'
|
||||
self.emit("var t {0}".format(name))
|
||||
with self.block("if err := json.Unmarshal(data, &t); err != nil"):
|
||||
self.emit("return nil, err")
|
||||
with self.block("switch t.Tag"):
|
||||
fields = base.get_enumerated_subtypes()
|
||||
for field in fields:
|
||||
with self.block('case "%s":' % field.name, delim=(None, None)):
|
||||
self.emit("return t.{0}, nil".format(fmt_var(field.name)))
|
||||
# FIX THIS
|
||||
self.emit("return nil, nil")
|
||||
|
||||
def _generate_struct(self, struct):
|
||||
with self.block('type %s struct' % struct.name):
|
||||
if struct.parent_type:
|
||||
self.emit(fmt_type(struct.parent_type, struct.namespace).lstrip('*'))
|
||||
for field in struct.fields:
|
||||
self._generate_field(field, namespace=struct.namespace)
|
||||
if struct.name in ('DownloadArg',):
|
||||
self.emit('// ExtraHeaders can be used to pass Range, If-None-Match headers')
|
||||
self.emit('ExtraHeaders map[string]string `json:"-"`')
|
||||
self._generate_struct_builder(struct)
|
||||
|
||||
def _generate_struct_builder(self, struct):
|
||||
fields = ["%s %s" % (fmt_var(field.name),
|
||||
fmt_type(field.data_type, struct.namespace,
|
||||
use_interface=True))
|
||||
for field in struct.all_required_fields]
|
||||
self.emit('// New{0} returns a new {0} instance'.format(struct.name))
|
||||
signature = "func New{0}({1}) *{0}".format(struct.name, ', '.join(fields))
|
||||
with self.block(signature):
|
||||
self.emit('s := new({0})'.format(struct.name))
|
||||
for field in struct.all_required_fields:
|
||||
field_name = fmt_var(field.name)
|
||||
self.emit("s.{0} = {0}".format(field_name))
|
||||
|
||||
for field in struct.all_optional_fields:
|
||||
if field.has_default:
|
||||
if is_primitive_type(field.data_type):
|
||||
default = field.default
|
||||
if is_boolean_type(field.data_type):
|
||||
default = str(default).lower()
|
||||
self.emit('s.{0} = {1}'.format(fmt_var(field.name), default))
|
||||
elif is_union_type(field.data_type):
|
||||
self.emit('s.%s = &%s{Tagged:dropbox.Tagged{"%s"}}' %
|
||||
(fmt_var(field.name),
|
||||
fmt_type(field.data_type, struct.namespace).lstrip('*'),
|
||||
field.default.tag_name))
|
||||
self.emit('return s')
|
||||
self.emit()
|
||||
|
||||
def _generate_field(self, field, union_field=False, namespace=None, raw=False):
|
||||
generate_doc(self, field)
|
||||
field_name = fmt_var(field.name)
|
||||
type_name = fmt_type(field.data_type, namespace, use_interface=True)
|
||||
json_tag = '`json:"%s"`' % field.name
|
||||
if is_nullable_type(field.data_type) or union_field:
|
||||
json_tag = '`json:"%s,omitempty"`' % field.name
|
||||
if raw:
|
||||
self.emit('%s json.RawMessage %s' % (field_name, json_tag))
|
||||
else:
|
||||
self.emit('%s %s %s' % (field_name, type_name, json_tag))
|
||||
|
||||
def _generate_union(self, union):
|
||||
self._generate_union_helper(union)
|
||||
|
||||
def _generate_union_helper(self, u):
|
||||
name = u.name
|
||||
namespace = u.namespace
|
||||
fields = u.fields
|
||||
if is_struct_type(u) and u.has_enumerated_subtypes():
|
||||
name = fmt_var(name, export=False) + 'Union'
|
||||
fields = u.get_enumerated_subtypes()
|
||||
|
||||
with self.block('type %s struct' % name):
|
||||
self.emit('dropbox.Tagged')
|
||||
for field in fields:
|
||||
if is_void_type(field.data_type):
|
||||
continue
|
||||
self._generate_field(field, union_field=True,
|
||||
namespace=namespace)
|
||||
self.emit()
|
||||
self.emit('// Valid tag values for %s' % fmt_var(u.name))
|
||||
with self.block('const', delim=('(', ')')):
|
||||
for field in fields:
|
||||
self.emit('%s%s = "%s"' % (fmt_var(u.name), fmt_var(field.name), field.name))
|
||||
self.emit()
|
||||
|
||||
num_void_fields = sum([is_void_type(f.data_type) for f in fields])
|
||||
# Simple structure, no need in UnmarshalJSON
|
||||
if len(fields) == num_void_fields:
|
||||
return
|
||||
|
||||
self.emit('// UnmarshalJSON deserializes into a %s instance' % name)
|
||||
with self.block('func (u *%s) UnmarshalJSON(body []byte) error' % name):
|
||||
with self.block('type wrap struct'):
|
||||
self.emit('dropbox.Tagged')
|
||||
for field in fields:
|
||||
if is_void_type(field.data_type) or \
|
||||
is_primitive_type(field.data_type):
|
||||
continue
|
||||
self._generate_field(field, union_field=True,
|
||||
namespace=namespace, raw=True)
|
||||
self.emit('var w wrap')
|
||||
self.emit('var err error')
|
||||
with self.block('if err = json.Unmarshal(body, &w); err != nil'):
|
||||
self.emit('return err')
|
||||
self.emit('u.Tag = w.Tag')
|
||||
with self.block('switch u.Tag'):
|
||||
for field in fields:
|
||||
if is_void_type(field.data_type):
|
||||
continue
|
||||
field_name = fmt_var(field.name)
|
||||
with self.block('case "%s":' % field.name, delim=(None, None)):
|
||||
if is_union_type(field.data_type):
|
||||
self.emit('err = json.Unmarshal(w.{0}, &u.{0})'
|
||||
.format(field_name))
|
||||
elif is_struct_type(field.data_type) and \
|
||||
field.data_type.has_enumerated_subtypes():
|
||||
self.emit("u.{0}, err = Is{1}FromJSON(body)"
|
||||
.format(field_name, field.data_type.name))
|
||||
else:
|
||||
self.emit('err = json.Unmarshal(body, &u.{0})'
|
||||
.format(field_name))
|
||||
with self.block("if err != nil"):
|
||||
self.emit("return err")
|
||||
self.emit('return nil')
|
||||
self.emit()
|
7
vendor/github.com/stacktic/dropbox/.travis.yml
generated
vendored
7
vendor/github.com/stacktic/dropbox/.travis.yml
generated
vendored
@ -1,7 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.1.2
|
||||
- 1.2.2
|
||||
- 1.3
|
||||
- tip
|
23
vendor/github.com/stacktic/dropbox/LICENSE
generated
vendored
23
vendor/github.com/stacktic/dropbox/LICENSE
generated
vendored
@ -1,23 +0,0 @@
|
||||
Copyright (c) 2014, Arnaud Ysmal
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
79
vendor/github.com/stacktic/dropbox/README.md
generated
vendored
79
vendor/github.com/stacktic/dropbox/README.md
generated
vendored
@ -1,79 +0,0 @@
|
||||
dropbox
|
||||
=======
|
||||
Go client library for the Dropbox core and Datastore API with support for uploading and downloading encrypted files.
|
||||
|
||||
Support of the Datastore API should be considered as a beta version.
|
||||
|
||||
Prerequisite
|
||||
------------
|
||||
To use this library, you must have a valid client ID (app key) and client secret (app secret) provided by Dropbox.<br>
|
||||
To register a new client application, please visit https://www.dropbox.com/developers/apps/create
|
||||
|
||||
Installation
|
||||
------------
|
||||
This library depends on the oauth2 package, it can be installed with the go get command:
|
||||
|
||||
$ go get golang.org/x/oauth2
|
||||
|
||||
This package can be installed with the go get command:
|
||||
|
||||
$ go get github.com/stacktic/dropbox
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
This simple 4-step example will show you how to create a folder:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"dropbox"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
var db *dropbox.Dropbox
|
||||
|
||||
var clientid, clientsecret string
|
||||
var token string
|
||||
|
||||
clientid = "xxxxx"
|
||||
clientsecret = "yyyyy"
|
||||
token = "zzzz"
|
||||
|
||||
// 1. Create a new dropbox object.
|
||||
db = dropbox.NewDropbox()
|
||||
|
||||
// 2. Provide your clientid and clientsecret (see prerequisite).
|
||||
db.SetAppInfo(clientid, clientsecret)
|
||||
|
||||
// 3. Provide the user token.
|
||||
db.SetAccessToken(token)
|
||||
|
||||
// 4. Send your commands.
|
||||
// In this example, you will create a new folder named "demo".
|
||||
folder := "demo"
|
||||
if _, err = db.CreateFolder(folder); err != nil {
|
||||
fmt.Printf("Error creating folder %s: %s\n", folder, err)
|
||||
} else {
|
||||
fmt.Printf("Folder %s successfully created\n", folder)
|
||||
}
|
||||
}
|
||||
|
||||
If you do not know the user token, you can replace step 3 by a call to the Auth method:
|
||||
|
||||
// This method will ask the user to visit an URL and paste the generated code.
|
||||
if err = db.Auth(); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
// You can now retrieve the token if you want.
|
||||
token = db.AccessToken()
|
||||
|
||||
If you want a more complete example, please check the following project: https://github.com/stacktic/dbox.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
API documentation can be found here: http://godoc.org/github.com/stacktic/dropbox.
|
228
vendor/github.com/stacktic/dropbox/crypto.go
generated
vendored
228
vendor/github.com/stacktic/dropbox/crypto.go
generated
vendored
@ -1,228 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GenerateKey generates a key by reading length bytes from /dev/random
|
||||
func GenerateKey(length int) ([]byte, error) {
|
||||
var err error
|
||||
var fd io.Reader
|
||||
var rv []byte
|
||||
|
||||
if fd, err = os.Open("/dev/random"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv = make([]byte, length)
|
||||
_, err = io.ReadFull(fd, rv)
|
||||
return rv, err
|
||||
}
|
||||
|
||||
func newCrypter(key []byte, in io.Reader, size int, newCipher func(key []byte) (cipher.Block, error)) (io.ReadCloser, int, error) {
|
||||
var block cipher.Block
|
||||
var err error
|
||||
|
||||
if block, err = newCipher(key); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
outsize := size - size%block.BlockSize() + 2*block.BlockSize()
|
||||
|
||||
rd, wr := io.Pipe()
|
||||
go encrypt(block, in, size, wr)
|
||||
return rd, outsize, nil
|
||||
}
|
||||
|
||||
func newDecrypter(key []byte, in io.Reader, size int, newCipher func(key []byte) (cipher.Block, error)) (io.ReadCloser, error) {
|
||||
var block cipher.Block
|
||||
var err error
|
||||
|
||||
if block, err = newCipher(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rd, wr := io.Pipe()
|
||||
go decrypt(block, in, size, wr)
|
||||
return rd, nil
|
||||
}
|
||||
|
||||
// NewAESDecrypterReader creates and returns a new io.ReadCloser to decrypt the given io.Reader containing size bytes with the given AES key.
|
||||
// The AES key should be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
|
||||
func NewAESDecrypterReader(key []byte, input io.Reader, size int) (io.ReadCloser, error) {
|
||||
return newDecrypter(key, input, size, aes.NewCipher)
|
||||
}
|
||||
|
||||
// NewAESCrypterReader creates and returns a new io.ReadCloser to encrypt the given io.Reader containing size bytes with the given AES key.
|
||||
// The AES key should be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
|
||||
func NewAESCrypterReader(key []byte, input io.Reader, size int) (io.ReadCloser, int, error) {
|
||||
return newCrypter(key, input, size, aes.NewCipher)
|
||||
}
|
||||
|
||||
func encrypt(block cipher.Block, in io.Reader, size int, out io.WriteCloser) error {
|
||||
var err error
|
||||
var rd int
|
||||
var buf []byte
|
||||
var last bool
|
||||
var encrypter cipher.BlockMode
|
||||
|
||||
defer out.Close()
|
||||
|
||||
buf = make([]byte, block.BlockSize())
|
||||
|
||||
if _, err = io.ReadFull(rand.Reader, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
encrypter = cipher.NewCBCEncrypter(block, buf)
|
||||
|
||||
if _, err = out.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
for !last {
|
||||
if rd, err = io.ReadFull(in, buf); err != nil {
|
||||
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
||||
buf = buf[:rd]
|
||||
buf = append(buf, 0x80)
|
||||
for len(buf) < block.BlockSize() {
|
||||
buf = append(buf, 0x00)
|
||||
}
|
||||
last = true
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
encrypter.CryptBlocks(buf, buf)
|
||||
if _, err = out.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decrypt(block cipher.Block, in io.Reader, size int, out io.WriteCloser) error {
|
||||
var err error
|
||||
var buf []byte
|
||||
var count int
|
||||
var decrypter cipher.BlockMode
|
||||
|
||||
defer out.Close()
|
||||
|
||||
buf = make([]byte, block.BlockSize())
|
||||
if _, err = io.ReadFull(in, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
decrypter = cipher.NewCBCDecrypter(block, buf)
|
||||
|
||||
count = (size - block.BlockSize()) / block.BlockSize()
|
||||
for count > 0 && err == nil {
|
||||
if _, err = io.ReadFull(in, buf); err == nil {
|
||||
decrypter.CryptBlocks(buf, buf)
|
||||
if count == 1 {
|
||||
for count = block.BlockSize() - 1; buf[count] == 0x00; count-- {
|
||||
continue
|
||||
}
|
||||
if buf[count] == 0x80 {
|
||||
buf = buf[:count]
|
||||
}
|
||||
}
|
||||
_, err = out.Write(buf)
|
||||
}
|
||||
count--
|
||||
}
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// FilesPutAES uploads and encrypts size bytes from the input reader to the dst path on Dropbox.
|
||||
func (db *Dropbox) FilesPutAES(key []byte, input io.ReadCloser, size int64, dst string, overwrite bool, parentRev string) (*Entry, error) {
|
||||
var encreader io.ReadCloser
|
||||
var outsize int
|
||||
var err error
|
||||
|
||||
if encreader, outsize, err = NewAESCrypterReader(key, input, int(size)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db.FilesPut(encreader, int64(outsize), dst, overwrite, parentRev)
|
||||
}
|
||||
|
||||
// UploadFileAES uploads and encrypts the file located in the src path on the local disk to the dst path on Dropbox.
|
||||
func (db *Dropbox) UploadFileAES(key []byte, src, dst string, overwrite bool, parentRev string) (*Entry, error) {
|
||||
var err error
|
||||
var fd *os.File
|
||||
var fsize int64
|
||||
|
||||
if fd, err = os.Open(src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
if fi, err := fd.Stat(); err == nil {
|
||||
fsize = fi.Size()
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
return db.FilesPutAES(key, fd, fsize, dst, overwrite, parentRev)
|
||||
}
|
||||
|
||||
// DownloadAES downloads and decrypts the file located in the src path on Dropbox and returns a io.ReadCloser.
|
||||
func (db *Dropbox) DownloadAES(key []byte, src, rev string, offset int) (io.ReadCloser, error) {
|
||||
var in io.ReadCloser
|
||||
var size int64
|
||||
var err error
|
||||
|
||||
if in, size, err = db.Download(src, rev, int64(offset)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewAESDecrypterReader(key, in, int(size))
|
||||
}
|
||||
|
||||
// DownloadToFileAES downloads and decrypts the file located in the src path on Dropbox to the dst file on the local disk.
|
||||
func (db *Dropbox) DownloadToFileAES(key []byte, src, dst, rev string) error {
|
||||
var input io.ReadCloser
|
||||
var fd *os.File
|
||||
var err error
|
||||
|
||||
if fd, err = os.Create(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
if input, err = db.DownloadAES(key, src, rev, 0); err != nil {
|
||||
os.Remove(dst)
|
||||
return err
|
||||
}
|
||||
defer input.Close()
|
||||
if _, err = io.Copy(fd, input); err != nil {
|
||||
os.Remove(dst)
|
||||
}
|
||||
return err
|
||||
}
|
620
vendor/github.com/stacktic/dropbox/datastores.go
generated
vendored
620
vendor/github.com/stacktic/dropbox/datastores.go
generated
vendored
@ -1,620 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
// List represents a value of type list.
|
||||
type List struct {
|
||||
record *Record
|
||||
field string
|
||||
values []interface{}
|
||||
}
|
||||
|
||||
// Fields represents a record.
|
||||
type Fields map[string]value
|
||||
|
||||
// Record represents an entry in a table.
|
||||
type Record struct {
|
||||
table *Table
|
||||
recordID string
|
||||
fields Fields
|
||||
isDeleted bool
|
||||
}
|
||||
|
||||
// Table represents a list of records.
|
||||
type Table struct {
|
||||
datastore *Datastore
|
||||
tableID string
|
||||
records map[string]*Record
|
||||
}
|
||||
|
||||
// DatastoreInfo represents the information about a datastore.
|
||||
type DatastoreInfo struct {
|
||||
ID string
|
||||
handle string
|
||||
revision int
|
||||
title string
|
||||
mtime time.Time
|
||||
}
|
||||
|
||||
type datastoreDelta struct {
|
||||
Revision int `json:"rev"`
|
||||
Changes listOfChanges `json:"changes"`
|
||||
Nonce *string `json:"nonce"`
|
||||
}
|
||||
|
||||
type listOfDelta []datastoreDelta
|
||||
|
||||
// Datastore represents a datastore.
|
||||
type Datastore struct {
|
||||
manager *DatastoreManager
|
||||
info DatastoreInfo
|
||||
changes listOfChanges
|
||||
tables map[string]*Table
|
||||
isDeleted bool
|
||||
autoCommit bool
|
||||
changesQueue chan changeWork
|
||||
}
|
||||
|
||||
// DatastoreManager represents all datastores linked to the current account.
|
||||
type DatastoreManager struct {
|
||||
dropbox *Dropbox
|
||||
datastores []*Datastore
|
||||
token string
|
||||
}
|
||||
|
||||
const (
|
||||
defaultDatastoreID = "default"
|
||||
maxGlobalIDLength = 63
|
||||
maxIDLength = 64
|
||||
|
||||
localIDPattern = `[a-z0-9_-]([a-z0-9._-]{0,62}[a-z0-9_-])?`
|
||||
globalIDPattern = `.[A-Za-z0-9_-]{1,63}`
|
||||
fieldsIDPattern = `[A-Za-z0-9._+/=-]{1,64}`
|
||||
fieldsSpecialIDPattern = `:[A-Za-z0-9._+/=-]{1,63}`
|
||||
)
|
||||
|
||||
var (
|
||||
localIDRegexp *regexp.Regexp
|
||||
globalIDRegexp *regexp.Regexp
|
||||
fieldsIDRegexp *regexp.Regexp
|
||||
fieldsSpecialIDRegexp *regexp.Regexp
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
if localIDRegexp, err = regexp.Compile(localIDPattern); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if globalIDRegexp, err = regexp.Compile(globalIDPattern); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if fieldsIDRegexp, err = regexp.Compile(fieldsIDPattern); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if fieldsSpecialIDRegexp, err = regexp.Compile(fieldsSpecialIDPattern); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func isValidDatastoreID(ID string) bool {
|
||||
if ID[0] == '.' {
|
||||
return globalIDRegexp.MatchString(ID)
|
||||
}
|
||||
return localIDRegexp.MatchString(ID)
|
||||
}
|
||||
|
||||
func isValidID(ID string) bool {
|
||||
if ID[0] == ':' {
|
||||
return fieldsSpecialIDRegexp.MatchString(ID)
|
||||
}
|
||||
return fieldsIDRegexp.MatchString(ID)
|
||||
}
|
||||
|
||||
const (
|
||||
// TypeBoolean is the returned type when the value is a bool
|
||||
TypeBoolean AtomType = iota
|
||||
// TypeInteger is the returned type when the value is an int
|
||||
TypeInteger
|
||||
// TypeDouble is the returned type when the value is a float
|
||||
TypeDouble
|
||||
// TypeString is the returned type when the value is a string
|
||||
TypeString
|
||||
// TypeBytes is the returned type when the value is a []byte
|
||||
TypeBytes
|
||||
// TypeDate is the returned type when the value is a Date
|
||||
TypeDate
|
||||
// TypeList is the returned type when the value is a List
|
||||
TypeList
|
||||
)
|
||||
|
||||
// AtomType represents the type of the value.
|
||||
type AtomType int
|
||||
|
||||
// NewDatastoreManager returns a new DatastoreManager linked to the current account.
|
||||
func (db *Dropbox) NewDatastoreManager() *DatastoreManager {
|
||||
return &DatastoreManager{
|
||||
dropbox: db,
|
||||
}
|
||||
}
|
||||
|
||||
// OpenDatastore opens or creates a datastore.
|
||||
func (dmgr *DatastoreManager) OpenDatastore(dsID string) (*Datastore, error) {
|
||||
rev, handle, _, err := dmgr.dropbox.openOrCreateDatastore(dsID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rv := &Datastore{
|
||||
manager: dmgr,
|
||||
info: DatastoreInfo{
|
||||
ID: dsID,
|
||||
handle: handle,
|
||||
revision: rev,
|
||||
},
|
||||
tables: make(map[string]*Table),
|
||||
changesQueue: make(chan changeWork),
|
||||
}
|
||||
if rev > 0 {
|
||||
err = rv.LoadSnapshot()
|
||||
}
|
||||
go rv.doHandleChange()
|
||||
return rv, err
|
||||
}
|
||||
|
||||
// OpenDefaultDatastore opens the default datastore.
|
||||
func (dmgr *DatastoreManager) OpenDefaultDatastore() (*Datastore, error) {
|
||||
return dmgr.OpenDatastore(defaultDatastoreID)
|
||||
}
|
||||
|
||||
// ListDatastores lists all datastores.
|
||||
func (dmgr *DatastoreManager) ListDatastores() ([]DatastoreInfo, error) {
|
||||
info, _, err := dmgr.dropbox.listDatastores()
|
||||
return info, err
|
||||
}
|
||||
|
||||
// DeleteDatastore deletes a datastore.
|
||||
func (dmgr *DatastoreManager) DeleteDatastore(dsID string) error {
|
||||
_, err := dmgr.dropbox.deleteDatastore(dsID)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateDatastore creates a global datastore with a unique ID, empty string for a random key.
|
||||
func (dmgr *DatastoreManager) CreateDatastore(dsID string) (*Datastore, error) {
|
||||
rev, handle, _, err := dmgr.dropbox.createDatastore(dsID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Datastore{
|
||||
manager: dmgr,
|
||||
info: DatastoreInfo{
|
||||
ID: dsID,
|
||||
handle: handle,
|
||||
revision: rev,
|
||||
},
|
||||
tables: make(map[string]*Table),
|
||||
changesQueue: make(chan changeWork),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AwaitDeltas awaits for deltas and applies them.
|
||||
func (ds *Datastore) AwaitDeltas() error {
|
||||
if len(ds.changes) != 0 {
|
||||
return fmt.Errorf("changes already pending")
|
||||
}
|
||||
_, _, deltas, err := ds.manager.dropbox.await([]*Datastore{ds}, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
changes, ok := deltas[ds.info.handle]
|
||||
if !ok || len(changes) == 0 {
|
||||
return nil
|
||||
}
|
||||
return ds.applyDelta(changes)
|
||||
}
|
||||
|
||||
func (ds *Datastore) applyDelta(dds []datastoreDelta) error {
|
||||
if len(ds.changes) != 0 {
|
||||
return fmt.Errorf("changes already pending")
|
||||
}
|
||||
for _, d := range dds {
|
||||
if d.Revision < ds.info.revision {
|
||||
continue
|
||||
}
|
||||
for _, c := range d.Changes {
|
||||
ds.applyChange(c)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the datastore.
|
||||
func (ds *Datastore) Close() {
|
||||
close(ds.changesQueue)
|
||||
}
|
||||
|
||||
// Delete deletes the datastore.
|
||||
func (ds *Datastore) Delete() error {
|
||||
return ds.manager.DeleteDatastore(ds.info.ID)
|
||||
}
|
||||
|
||||
// SetTitle sets the datastore title to the given string.
|
||||
func (ds *Datastore) SetTitle(t string) error {
|
||||
if len(ds.info.title) == 0 {
|
||||
return ds.insertRecord(":info", "info", Fields{
|
||||
"title": value{
|
||||
values: []interface{}{t},
|
||||
},
|
||||
})
|
||||
}
|
||||
return ds.updateField(":info", "info", "title", t)
|
||||
}
|
||||
|
||||
// SetMTime sets the datastore mtime to the given time.
|
||||
func (ds *Datastore) SetMTime(t time.Time) error {
|
||||
if time.Time(ds.info.mtime).IsZero() {
|
||||
return ds.insertRecord(":info", "info", Fields{
|
||||
"mtime": value{
|
||||
values: []interface{}{t},
|
||||
},
|
||||
})
|
||||
}
|
||||
return ds.updateField(":info", "info", "mtime", t)
|
||||
}
|
||||
|
||||
// Rollback reverts all local changes and discards them.
|
||||
func (ds *Datastore) Rollback() error {
|
||||
if len(ds.changes) == 0 {
|
||||
return nil
|
||||
}
|
||||
for i := len(ds.changes) - 1; i >= 0; i-- {
|
||||
ds.applyChange(ds.changes[i].Revert)
|
||||
}
|
||||
ds.changes = ds.changes[:0]
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTable returns the requested table.
|
||||
func (ds *Datastore) GetTable(tableID string) (*Table, error) {
|
||||
if !isValidID(tableID) {
|
||||
return nil, fmt.Errorf("invalid table ID %s", tableID)
|
||||
}
|
||||
t, ok := ds.tables[tableID]
|
||||
if ok {
|
||||
return t, nil
|
||||
}
|
||||
t = &Table{
|
||||
datastore: ds,
|
||||
tableID: tableID,
|
||||
records: make(map[string]*Record),
|
||||
}
|
||||
ds.tables[tableID] = t
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Commit commits the changes registered by sending them to the server.
|
||||
func (ds *Datastore) Commit() error {
|
||||
rev, err := ds.manager.dropbox.putDelta(ds.info.handle, ds.info.revision, ds.changes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ds.changes = ds.changes[:0]
|
||||
ds.info.revision = rev
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadSnapshot updates the state of the datastore from the server.
|
||||
func (ds *Datastore) LoadSnapshot() error {
|
||||
if len(ds.changes) != 0 {
|
||||
return fmt.Errorf("could not load snapshot when there are pending changes")
|
||||
}
|
||||
rows, rev, err := ds.manager.dropbox.getSnapshot(ds.info.handle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ds.tables = make(map[string]*Table)
|
||||
for _, r := range rows {
|
||||
if _, ok := ds.tables[r.TID]; !ok {
|
||||
ds.tables[r.TID] = &Table{
|
||||
datastore: ds,
|
||||
tableID: r.TID,
|
||||
records: make(map[string]*Record),
|
||||
}
|
||||
}
|
||||
ds.tables[r.TID].records[r.RowID] = &Record{
|
||||
table: ds.tables[r.TID],
|
||||
recordID: r.RowID,
|
||||
fields: r.Data,
|
||||
}
|
||||
}
|
||||
ds.info.revision = rev
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDatastore returns the datastore associated with this table.
|
||||
func (t *Table) GetDatastore() *Datastore {
|
||||
return t.datastore
|
||||
}
|
||||
|
||||
// GetID returns the ID of this table.
|
||||
func (t *Table) GetID() string {
|
||||
return t.tableID
|
||||
}
|
||||
|
||||
// Get returns the record with this ID.
|
||||
func (t *Table) Get(recordID string) (*Record, error) {
|
||||
if !isValidID(recordID) {
|
||||
return nil, fmt.Errorf("invalid record ID %s", recordID)
|
||||
}
|
||||
return t.records[recordID], nil
|
||||
}
|
||||
|
||||
// GetOrInsert gets the requested record.
|
||||
func (t *Table) GetOrInsert(recordID string) (*Record, error) {
|
||||
if !isValidID(recordID) {
|
||||
return nil, fmt.Errorf("invalid record ID %s", recordID)
|
||||
}
|
||||
return t.GetOrInsertWithFields(recordID, nil)
|
||||
}
|
||||
|
||||
// GetOrInsertWithFields gets the requested table.
|
||||
func (t *Table) GetOrInsertWithFields(recordID string, fields Fields) (*Record, error) {
|
||||
if !isValidID(recordID) {
|
||||
return nil, fmt.Errorf("invalid record ID %s", recordID)
|
||||
}
|
||||
if r, ok := t.records[recordID]; ok {
|
||||
return r, nil
|
||||
}
|
||||
if fields == nil {
|
||||
fields = make(Fields)
|
||||
}
|
||||
if err := t.datastore.insertRecord(t.tableID, recordID, fields); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.records[recordID], nil
|
||||
}
|
||||
|
||||
// Query returns a list of records matching all the given fields.
|
||||
func (t *Table) Query(fields Fields) ([]*Record, error) {
|
||||
var records []*Record
|
||||
|
||||
next:
|
||||
for _, record := range t.records {
|
||||
for qf, qv := range fields {
|
||||
if rv, ok := record.fields[qf]; !ok || !reflect.DeepEqual(qv, rv) {
|
||||
continue next
|
||||
}
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// GetTable returns the table associated with this record.
|
||||
func (r *Record) GetTable() *Table {
|
||||
return r.table
|
||||
}
|
||||
|
||||
// GetID returns the ID of this record.
|
||||
func (r *Record) GetID() string {
|
||||
return r.recordID
|
||||
}
|
||||
|
||||
// IsDeleted returns whether this record was deleted.
|
||||
func (r *Record) IsDeleted() bool {
|
||||
return r.isDeleted
|
||||
}
|
||||
|
||||
// DeleteRecord deletes this record.
|
||||
func (r *Record) DeleteRecord() {
|
||||
r.table.datastore.deleteRecord(r.table.tableID, r.recordID)
|
||||
}
|
||||
|
||||
// HasField returns whether this field exists.
|
||||
func (r *Record) HasField(field string) (bool, error) {
|
||||
if !isValidID(field) {
|
||||
return false, fmt.Errorf("invalid field %s", field)
|
||||
}
|
||||
_, ok := r.fields[field]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// Get gets the current value of this field.
|
||||
func (r *Record) Get(field string) (interface{}, bool, error) {
|
||||
if !isValidID(field) {
|
||||
return nil, false, fmt.Errorf("invalid field %s", field)
|
||||
}
|
||||
v, ok := r.fields[field]
|
||||
if !ok {
|
||||
return nil, false, nil
|
||||
}
|
||||
if v.isList {
|
||||
return &List{
|
||||
record: r,
|
||||
field: field,
|
||||
values: v.values,
|
||||
}, true, nil
|
||||
}
|
||||
return v.values[0], true, nil
|
||||
}
|
||||
|
||||
// GetOrCreateList gets the current value of this field.
|
||||
func (r *Record) GetOrCreateList(field string) (*List, error) {
|
||||
if !isValidID(field) {
|
||||
return nil, fmt.Errorf("invalid field %s", field)
|
||||
}
|
||||
v, ok := r.fields[field]
|
||||
if ok && !v.isList {
|
||||
return nil, fmt.Errorf("not a list")
|
||||
}
|
||||
if !ok {
|
||||
if err := r.table.datastore.listCreate(r.table.tableID, r.recordID, field); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v = r.fields[field]
|
||||
}
|
||||
return &List{
|
||||
record: r,
|
||||
field: field,
|
||||
values: v.values,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getType(i interface{}) (AtomType, error) {
|
||||
switch i.(type) {
|
||||
case bool:
|
||||
return TypeBoolean, nil
|
||||
case int, int32, int64:
|
||||
return TypeInteger, nil
|
||||
case float32, float64:
|
||||
return TypeDouble, nil
|
||||
case string:
|
||||
return TypeString, nil
|
||||
case []byte:
|
||||
return TypeBytes, nil
|
||||
case time.Time:
|
||||
return TypeDate, nil
|
||||
}
|
||||
return 0, fmt.Errorf("type %s not supported", reflect.TypeOf(i).Name())
|
||||
}
|
||||
|
||||
// GetFieldType returns the type of the given field.
|
||||
func (r *Record) GetFieldType(field string) (AtomType, error) {
|
||||
if !isValidID(field) {
|
||||
return 0, fmt.Errorf("invalid field %s", field)
|
||||
}
|
||||
v, ok := r.fields[field]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("no such field: %s", field)
|
||||
}
|
||||
if v.isList {
|
||||
return TypeList, nil
|
||||
}
|
||||
return getType(v.values[0])
|
||||
}
|
||||
|
||||
// Set sets the value of a field.
|
||||
func (r *Record) Set(field string, value interface{}) error {
|
||||
if !isValidID(field) {
|
||||
return fmt.Errorf("invalid field %s", field)
|
||||
}
|
||||
return r.table.datastore.updateField(r.table.tableID, r.recordID, field, value)
|
||||
}
|
||||
|
||||
// DeleteField deletes the given field from this record.
|
||||
func (r *Record) DeleteField(field string) error {
|
||||
if !isValidID(field) {
|
||||
return fmt.Errorf("invalid field %s", field)
|
||||
}
|
||||
return r.table.datastore.deleteField(r.table.tableID, r.recordID, field)
|
||||
}
|
||||
|
||||
// FieldNames returns a list of fields names.
|
||||
func (r *Record) FieldNames() []string {
|
||||
var rv []string
|
||||
|
||||
rv = make([]string, 0, len(r.fields))
|
||||
for k := range r.fields {
|
||||
rv = append(rv, k)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
// IsEmpty returns whether the list contains an element.
|
||||
func (l *List) IsEmpty() bool {
|
||||
return len(l.values) == 0
|
||||
}
|
||||
|
||||
// Size returns the number of elements in the list.
|
||||
func (l *List) Size() int {
|
||||
return len(l.values)
|
||||
}
|
||||
|
||||
// GetType gets the type of the n-th element in the list.
|
||||
func (l *List) GetType(n int) (AtomType, error) {
|
||||
if n >= len(l.values) {
|
||||
return 0, fmt.Errorf("out of bound index")
|
||||
}
|
||||
return getType(l.values[n])
|
||||
}
|
||||
|
||||
// Get gets the n-th element in the list.
|
||||
func (l *List) Get(n int) (interface{}, error) {
|
||||
if n >= len(l.values) {
|
||||
return 0, fmt.Errorf("out of bound index")
|
||||
}
|
||||
return l.values[n], nil
|
||||
}
|
||||
|
||||
// AddAtPos inserts the item at the n-th position in the list.
|
||||
func (l *List) AddAtPos(n int, i interface{}) error {
|
||||
if n > len(l.values) {
|
||||
return fmt.Errorf("out of bound index")
|
||||
}
|
||||
err := l.record.table.datastore.listInsert(l.record.table.tableID, l.record.recordID, l.field, n, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.values = l.record.fields[l.field].values
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add adds the item at the end of the list.
|
||||
func (l *List) Add(i interface{}) error {
|
||||
return l.AddAtPos(len(l.values), i)
|
||||
}
|
||||
|
||||
// Set sets the value of the n-th element of the list.
|
||||
func (l *List) Set(n int, i interface{}) error {
|
||||
if n >= len(l.values) {
|
||||
return fmt.Errorf("out of bound index")
|
||||
}
|
||||
return l.record.table.datastore.listPut(l.record.table.tableID, l.record.recordID, l.field, n, i)
|
||||
}
|
||||
|
||||
// Remove removes the n-th element of the list.
|
||||
func (l *List) Remove(n int) error {
|
||||
if n >= len(l.values) {
|
||||
return fmt.Errorf("out of bound index")
|
||||
}
|
||||
err := l.record.table.datastore.listDelete(l.record.table.tableID, l.record.recordID, l.field, n)
|
||||
l.values = l.record.fields[l.field].values
|
||||
return err
|
||||
}
|
||||
|
||||
// Move moves the element from the from-th position to the to-th.
|
||||
func (l *List) Move(from, to int) error {
|
||||
if from >= len(l.values) || to >= len(l.values) {
|
||||
return fmt.Errorf("out of bound index")
|
||||
}
|
||||
return l.record.table.datastore.listMove(l.record.table.tableID, l.record.recordID, l.field, from, to)
|
||||
}
|
516
vendor/github.com/stacktic/dropbox/datastores_changes.go
generated
vendored
516
vendor/github.com/stacktic/dropbox/datastores_changes.go
generated
vendored
@ -1,516 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type value struct {
|
||||
values []interface{}
|
||||
isList bool
|
||||
}
|
||||
|
||||
type fieldOp struct {
|
||||
Op string
|
||||
Index int
|
||||
Index2 int
|
||||
Data value
|
||||
}
|
||||
|
||||
type opDict map[string]fieldOp
|
||||
|
||||
type change struct {
|
||||
Op string
|
||||
TID string
|
||||
RecordID string
|
||||
Ops opDict
|
||||
Data Fields
|
||||
Revert *change
|
||||
}
|
||||
type listOfChanges []*change
|
||||
|
||||
type changeWork struct {
|
||||
c *change
|
||||
out chan error
|
||||
}
|
||||
|
||||
const (
|
||||
recordDelete = "D"
|
||||
recordInsert = "I"
|
||||
recordUpdate = "U"
|
||||
fieldDelete = "D"
|
||||
fieldPut = "P"
|
||||
listCreate = "LC"
|
||||
listDelete = "LD"
|
||||
listInsert = "LI"
|
||||
listMove = "LM"
|
||||
listPut = "LP"
|
||||
)
|
||||
|
||||
func newValueFromInterface(i interface{}) *value {
|
||||
if a, ok := i.([]byte); ok {
|
||||
return &value{
|
||||
values: []interface{}{a},
|
||||
isList: false,
|
||||
}
|
||||
}
|
||||
if reflect.TypeOf(i).Kind() == reflect.Slice || reflect.TypeOf(i).Kind() == reflect.Array {
|
||||
val := reflect.ValueOf(i)
|
||||
v := &value{
|
||||
values: make([]interface{}, val.Len()),
|
||||
isList: true,
|
||||
}
|
||||
for i := range v.values {
|
||||
v.values[i] = val.Index(i).Interface()
|
||||
}
|
||||
return v
|
||||
}
|
||||
return &value{
|
||||
values: []interface{}{i},
|
||||
isList: false,
|
||||
}
|
||||
}
|
||||
|
||||
func newValue(v *value) *value {
|
||||
var nv *value
|
||||
|
||||
nv = &value{
|
||||
values: make([]interface{}, len(v.values)),
|
||||
isList: v.isList,
|
||||
}
|
||||
copy(nv.values, v.values)
|
||||
return nv
|
||||
}
|
||||
|
||||
func newFields(f Fields) Fields {
|
||||
var n Fields
|
||||
|
||||
n = make(Fields)
|
||||
for k, v := range f {
|
||||
n[k] = *newValue(&v)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (ds *Datastore) deleteRecord(table, record string) error {
|
||||
return ds.handleChange(&change{
|
||||
Op: recordDelete,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) insertRecord(table, record string, values Fields) error {
|
||||
return ds.handleChange(&change{
|
||||
Op: recordInsert,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
Data: newFields(values),
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) updateFields(table, record string, values map[string]interface{}) error {
|
||||
var dsval opDict
|
||||
|
||||
dsval = make(opDict)
|
||||
for k, v := range values {
|
||||
dsval[k] = fieldOp{
|
||||
Op: fieldPut,
|
||||
Data: *newValueFromInterface(v),
|
||||
}
|
||||
}
|
||||
return ds.handleChange(&change{
|
||||
Op: recordUpdate,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
Ops: dsval,
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) updateField(table, record, field string, i interface{}) error {
|
||||
return ds.updateFields(table, record, map[string]interface{}{field: i})
|
||||
}
|
||||
|
||||
func (ds *Datastore) deleteField(table, record, field string) error {
|
||||
return ds.handleChange(&change{
|
||||
Op: recordUpdate,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
Ops: opDict{
|
||||
field: fieldOp{
|
||||
Op: fieldDelete,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) listCreate(table, record, field string) error {
|
||||
return ds.handleChange(&change{
|
||||
Op: recordUpdate,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
Ops: opDict{
|
||||
field: fieldOp{
|
||||
Op: listCreate,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) listDelete(table, record, field string, pos int) error {
|
||||
return ds.handleChange(&change{
|
||||
Op: recordUpdate,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
Ops: opDict{
|
||||
field: fieldOp{
|
||||
Op: listDelete,
|
||||
Index: pos,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) listInsert(table, record, field string, pos int, i interface{}) error {
|
||||
return ds.handleChange(&change{
|
||||
Op: recordUpdate,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
Ops: opDict{
|
||||
field: fieldOp{
|
||||
Op: listInsert,
|
||||
Index: pos,
|
||||
Data: *newValueFromInterface(i),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) listMove(table, record, field string, from, to int) error {
|
||||
return ds.handleChange(&change{
|
||||
Op: recordUpdate,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
Ops: opDict{
|
||||
field: fieldOp{
|
||||
Op: listMove,
|
||||
Index: from,
|
||||
Index2: to,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) listPut(table, record, field string, pos int, i interface{}) error {
|
||||
return ds.handleChange(&change{
|
||||
Op: recordUpdate,
|
||||
TID: table,
|
||||
RecordID: record,
|
||||
Ops: opDict{
|
||||
field: fieldOp{
|
||||
Op: listPut,
|
||||
Index: pos,
|
||||
Data: *newValueFromInterface(i),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) handleChange(c *change) error {
|
||||
var out chan error
|
||||
|
||||
if ds.changesQueue == nil {
|
||||
return fmt.Errorf("datastore is closed")
|
||||
}
|
||||
out = make(chan error)
|
||||
ds.changesQueue <- changeWork{
|
||||
c: c,
|
||||
out: out,
|
||||
}
|
||||
return <-out
|
||||
}
|
||||
|
||||
func (ds *Datastore) doHandleChange() {
|
||||
var err error
|
||||
var c *change
|
||||
|
||||
q := ds.changesQueue
|
||||
for cw := range q {
|
||||
c = cw.c
|
||||
|
||||
if err = ds.validateChange(c); err != nil {
|
||||
cw.out <- err
|
||||
continue
|
||||
}
|
||||
if c.Revert, err = ds.inverseChange(c); err != nil {
|
||||
cw.out <- err
|
||||
continue
|
||||
}
|
||||
|
||||
if err = ds.applyChange(c); err != nil {
|
||||
cw.out <- err
|
||||
continue
|
||||
}
|
||||
|
||||
ds.changes = append(ds.changes, c)
|
||||
|
||||
if ds.autoCommit {
|
||||
if err = ds.Commit(); err != nil {
|
||||
cw.out <- err
|
||||
}
|
||||
}
|
||||
close(cw.out)
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *Datastore) validateChange(c *change) error {
|
||||
var t *Table
|
||||
var r *Record
|
||||
var ok bool
|
||||
|
||||
if t, ok = ds.tables[c.TID]; !ok {
|
||||
t = &Table{
|
||||
datastore: ds,
|
||||
tableID: c.TID,
|
||||
records: make(map[string]*Record),
|
||||
}
|
||||
}
|
||||
|
||||
r = t.records[c.RecordID]
|
||||
|
||||
switch c.Op {
|
||||
case recordInsert, recordDelete:
|
||||
return nil
|
||||
case recordUpdate:
|
||||
if r == nil {
|
||||
return fmt.Errorf("no such record: %s", c.RecordID)
|
||||
}
|
||||
for field, op := range c.Ops {
|
||||
if op.Op == fieldPut || op.Op == fieldDelete {
|
||||
continue
|
||||
}
|
||||
v, ok := r.fields[field]
|
||||
if op.Op == listCreate {
|
||||
if ok {
|
||||
return fmt.Errorf("field %s already exists", field)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("no such field: %s", field)
|
||||
}
|
||||
if !v.isList {
|
||||
return fmt.Errorf("field %s is not a list", field)
|
||||
}
|
||||
maxIndex := len(v.values) - 1
|
||||
if op.Op == listInsert {
|
||||
maxIndex++
|
||||
}
|
||||
if op.Index > maxIndex {
|
||||
return fmt.Errorf("out of bound access index %d on [0:%d]", op.Index, maxIndex)
|
||||
}
|
||||
if op.Index2 > maxIndex {
|
||||
return fmt.Errorf("out of bound access index %d on [0:%d]", op.Index, maxIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ds *Datastore) applyChange(c *change) error {
|
||||
var t *Table
|
||||
var r *Record
|
||||
var ok bool
|
||||
|
||||
if t, ok = ds.tables[c.TID]; !ok {
|
||||
t = &Table{
|
||||
datastore: ds,
|
||||
tableID: c.TID,
|
||||
records: make(map[string]*Record),
|
||||
}
|
||||
ds.tables[c.TID] = t
|
||||
}
|
||||
|
||||
r = t.records[c.RecordID]
|
||||
|
||||
switch c.Op {
|
||||
case recordInsert:
|
||||
t.records[c.RecordID] = &Record{
|
||||
table: t,
|
||||
recordID: c.RecordID,
|
||||
fields: newFields(c.Data),
|
||||
}
|
||||
case recordDelete:
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
r.isDeleted = true
|
||||
delete(t.records, c.RecordID)
|
||||
case recordUpdate:
|
||||
for field, op := range c.Ops {
|
||||
v, ok := r.fields[field]
|
||||
switch op.Op {
|
||||
case fieldPut:
|
||||
r.fields[field] = *newValue(&op.Data)
|
||||
case fieldDelete:
|
||||
if ok {
|
||||
delete(r.fields, field)
|
||||
}
|
||||
case listCreate:
|
||||
if !ok {
|
||||
r.fields[field] = value{isList: true}
|
||||
}
|
||||
case listDelete:
|
||||
copy(v.values[op.Index:], v.values[op.Index+1:])
|
||||
v.values = v.values[:len(v.values)-1]
|
||||
r.fields[field] = v
|
||||
case listInsert:
|
||||
v.values = append(v.values, op.Data)
|
||||
copy(v.values[op.Index+1:], v.values[op.Index:len(v.values)-1])
|
||||
v.values[op.Index] = op.Data.values[0]
|
||||
r.fields[field] = v
|
||||
case listMove:
|
||||
val := v.values[op.Index]
|
||||
if op.Index < op.Index2 {
|
||||
copy(v.values[op.Index:op.Index2], v.values[op.Index+1:op.Index2+1])
|
||||
} else {
|
||||
copy(v.values[op.Index2+1:op.Index+1], v.values[op.Index2:op.Index])
|
||||
}
|
||||
v.values[op.Index2] = val
|
||||
r.fields[field] = v
|
||||
case listPut:
|
||||
r.fields[field].values[op.Index] = op.Data.values[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ds *Datastore) inverseChange(c *change) (*change, error) {
|
||||
var t *Table
|
||||
var r *Record
|
||||
var ok bool
|
||||
var rev *change
|
||||
|
||||
if t, ok = ds.tables[c.TID]; !ok {
|
||||
t = &Table{
|
||||
datastore: ds,
|
||||
tableID: c.TID,
|
||||
records: make(map[string]*Record),
|
||||
}
|
||||
ds.tables[c.TID] = t
|
||||
}
|
||||
|
||||
r = t.records[c.RecordID]
|
||||
|
||||
switch c.Op {
|
||||
case recordInsert:
|
||||
return &change{
|
||||
Op: recordDelete,
|
||||
TID: c.TID,
|
||||
RecordID: c.RecordID,
|
||||
}, nil
|
||||
case recordDelete:
|
||||
if r == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return &change{
|
||||
Op: recordInsert,
|
||||
TID: c.TID,
|
||||
RecordID: c.RecordID,
|
||||
Data: newFields(r.fields),
|
||||
}, nil
|
||||
case recordUpdate:
|
||||
rev = &change{
|
||||
Op: recordUpdate,
|
||||
TID: c.TID,
|
||||
RecordID: c.RecordID,
|
||||
Ops: make(opDict),
|
||||
}
|
||||
for field, op := range c.Ops {
|
||||
switch op.Op {
|
||||
case fieldPut:
|
||||
if v, ok := r.fields[field]; ok {
|
||||
rev.Ops[field] = fieldOp{
|
||||
Op: fieldPut,
|
||||
Data: *newValue(&v),
|
||||
}
|
||||
} else {
|
||||
rev.Ops[field] = fieldOp{
|
||||
Op: fieldDelete,
|
||||
}
|
||||
}
|
||||
case fieldDelete:
|
||||
if v, ok := r.fields[field]; ok {
|
||||
rev.Ops[field] = fieldOp{
|
||||
Op: fieldPut,
|
||||
Data: *newValue(&v),
|
||||
}
|
||||
}
|
||||
case listCreate:
|
||||
if _, ok := r.fields[field]; !ok {
|
||||
rev.Ops[field] = fieldOp{
|
||||
Op: fieldDelete,
|
||||
}
|
||||
}
|
||||
case listDelete:
|
||||
v := r.fields[field]
|
||||
rev.Ops[field] = fieldOp{
|
||||
Op: listInsert,
|
||||
Index: op.Index,
|
||||
Data: value{
|
||||
values: []interface{}{v.values[op.Index]},
|
||||
isList: false,
|
||||
},
|
||||
}
|
||||
case listInsert:
|
||||
rev.Ops[field] = fieldOp{
|
||||
Op: listDelete,
|
||||
Index: op.Index,
|
||||
}
|
||||
case listMove:
|
||||
rev.Ops[field] = fieldOp{
|
||||
Op: listMove,
|
||||
Index: op.Index2,
|
||||
Index2: op.Index,
|
||||
}
|
||||
case listPut:
|
||||
v := r.fields[field]
|
||||
rev.Ops[field] = fieldOp{
|
||||
Op: listPut,
|
||||
Index: op.Index,
|
||||
Data: value{
|
||||
values: []interface{}{v.values[op.Index]},
|
||||
isList: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rev, nil
|
||||
}
|
303
vendor/github.com/stacktic/dropbox/datastores_parser.go
generated
vendored
303
vendor/github.com/stacktic/dropbox/datastores_parser.go
generated
vendored
@ -1,303 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type atom struct {
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func encodeDBase64(b []byte) string {
|
||||
return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
|
||||
}
|
||||
|
||||
func decodeDBase64(s string) ([]byte, error) {
|
||||
pad := 4 - len(s)%4
|
||||
if pad != 4 {
|
||||
s += strings.Repeat("=", pad)
|
||||
}
|
||||
return base64.URLEncoding.DecodeString(s)
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of a.
|
||||
func (a atom) MarshalJSON() ([]byte, error) {
|
||||
switch v := a.Value.(type) {
|
||||
case bool, string:
|
||||
return json.Marshal(v)
|
||||
case float64:
|
||||
if math.IsNaN(v) {
|
||||
return []byte(`{"N": "nan"}`), nil
|
||||
} else if math.IsInf(v, 1) {
|
||||
return []byte(`{"N": "+inf"}`), nil
|
||||
} else if math.IsInf(v, -1) {
|
||||
return []byte(`{"N": "-inf"}`), nil
|
||||
}
|
||||
return json.Marshal(v)
|
||||
case time.Time:
|
||||
return []byte(fmt.Sprintf(`{"T": "%d"}`, v.UnixNano()/int64(time.Millisecond))), nil
|
||||
case int, int32, int64:
|
||||
return []byte(fmt.Sprintf(`{"I": "%d"}`, v)), nil
|
||||
case []byte:
|
||||
return []byte(fmt.Sprintf(`{"B": "%s"}`, encodeDBase64(v))), nil
|
||||
}
|
||||
return nil, fmt.Errorf("wrong format")
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses the JSON-encoded data and stores the result in the value pointed to by a.
|
||||
func (a *atom) UnmarshalJSON(data []byte) error {
|
||||
var i interface{}
|
||||
var err error
|
||||
|
||||
if err = json.Unmarshal(data, &i); err != nil {
|
||||
return err
|
||||
}
|
||||
switch v := i.(type) {
|
||||
case bool, int, int32, int64, float32, float64, string:
|
||||
a.Value = v
|
||||
return nil
|
||||
case map[string]interface{}:
|
||||
for key, rval := range v {
|
||||
val, ok := rval.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("could not parse atom")
|
||||
}
|
||||
switch key {
|
||||
case "I":
|
||||
a.Value, err = strconv.ParseInt(val, 10, 64)
|
||||
return nil
|
||||
case "N":
|
||||
switch val {
|
||||
case "nan":
|
||||
a.Value = math.NaN()
|
||||
return nil
|
||||
case "+inf":
|
||||
a.Value = math.Inf(1)
|
||||
return nil
|
||||
case "-inf":
|
||||
a.Value = math.Inf(-1)
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown special type %s", val)
|
||||
}
|
||||
case "T":
|
||||
t, err := strconv.ParseInt(val, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse atom")
|
||||
}
|
||||
a.Value = time.Unix(t/1000, (t%1000)*int64(time.Millisecond))
|
||||
return nil
|
||||
|
||||
case "B":
|
||||
a.Value, err = decodeDBase64(val)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("could not parse atom")
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of v.
|
||||
func (v value) MarshalJSON() ([]byte, error) {
|
||||
if v.isList {
|
||||
var a []atom
|
||||
|
||||
a = make([]atom, len(v.values))
|
||||
for i := range v.values {
|
||||
a[i].Value = v.values[i]
|
||||
}
|
||||
return json.Marshal(a)
|
||||
}
|
||||
return json.Marshal(atom{Value: v.values[0]})
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses the JSON-encoded data and stores the result in the value pointed to by v.
|
||||
func (v *value) UnmarshalJSON(data []byte) error {
|
||||
var isArray bool
|
||||
var err error
|
||||
var a atom
|
||||
var as []atom
|
||||
|
||||
for _, d := range data {
|
||||
if d == ' ' {
|
||||
continue
|
||||
}
|
||||
if d == '[' {
|
||||
isArray = true
|
||||
}
|
||||
break
|
||||
}
|
||||
if isArray {
|
||||
if err = json.Unmarshal(data, &as); err != nil {
|
||||
return err
|
||||
}
|
||||
v.values = make([]interface{}, len(as))
|
||||
for i, at := range as {
|
||||
v.values[i] = at.Value
|
||||
}
|
||||
v.isList = true
|
||||
return nil
|
||||
}
|
||||
if err = json.Unmarshal(data, &a); err != nil {
|
||||
return err
|
||||
}
|
||||
v.values = make([]interface{}, 1)
|
||||
v.values[0] = a.Value
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses the JSON-encoded data and stores the result in the value pointed to by f.
|
||||
func (f *fieldOp) UnmarshalJSON(data []byte) error {
|
||||
var i []json.RawMessage
|
||||
var err error
|
||||
|
||||
if err = json.Unmarshal(data, &i); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(i[0], &f.Op); err != nil {
|
||||
return err
|
||||
}
|
||||
switch f.Op {
|
||||
case fieldPut:
|
||||
if len(i) != 2 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
return json.Unmarshal(i[1], &f.Data)
|
||||
case fieldDelete, listCreate:
|
||||
if len(i) != 1 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
case listInsert, listPut:
|
||||
if len(i) != 3 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
if err = json.Unmarshal(i[1], &f.Index); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(i[2], &f.Data)
|
||||
case listDelete:
|
||||
if len(i) != 2 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
return json.Unmarshal(i[1], &f.Index)
|
||||
case listMove:
|
||||
if len(i) != 3 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
if err = json.Unmarshal(i[1], &f.Index); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(i[2], &f.Index2)
|
||||
default:
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of f.
|
||||
func (f fieldOp) MarshalJSON() ([]byte, error) {
|
||||
switch f.Op {
|
||||
case fieldPut:
|
||||
return json.Marshal([]interface{}{f.Op, f.Data})
|
||||
case fieldDelete, listCreate:
|
||||
return json.Marshal([]interface{}{f.Op})
|
||||
case listInsert, listPut:
|
||||
return json.Marshal([]interface{}{f.Op, f.Index, f.Data})
|
||||
case listDelete:
|
||||
return json.Marshal([]interface{}{f.Op, f.Index})
|
||||
case listMove:
|
||||
return json.Marshal([]interface{}{f.Op, f.Index, f.Index2})
|
||||
}
|
||||
return nil, fmt.Errorf("could not marshal Change type")
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses the JSON-encoded data and stores the result in the value pointed to by c.
|
||||
func (c *change) UnmarshalJSON(data []byte) error {
|
||||
var i []json.RawMessage
|
||||
var err error
|
||||
|
||||
if err = json.Unmarshal(data, &i); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(i) < 3 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(i[0], &c.Op); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = json.Unmarshal(i[1], &c.TID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = json.Unmarshal(i[2], &c.RecordID); err != nil {
|
||||
return err
|
||||
}
|
||||
switch c.Op {
|
||||
case recordInsert:
|
||||
if len(i) != 4 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
if err = json.Unmarshal(i[3], &c.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
case recordUpdate:
|
||||
if len(i) != 4 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
if err = json.Unmarshal(i[3], &c.Ops); err != nil {
|
||||
return err
|
||||
}
|
||||
case recordDelete:
|
||||
if len(i) != 3 {
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("wrong format")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of c.
|
||||
func (c change) MarshalJSON() ([]byte, error) {
|
||||
switch c.Op {
|
||||
case recordInsert:
|
||||
return json.Marshal([]interface{}{recordInsert, c.TID, c.RecordID, c.Data})
|
||||
case recordUpdate:
|
||||
return json.Marshal([]interface{}{recordUpdate, c.TID, c.RecordID, c.Ops})
|
||||
case recordDelete:
|
||||
return json.Marshal([]interface{}{recordDelete, c.TID, c.RecordID})
|
||||
}
|
||||
return nil, fmt.Errorf("could not marshal Change type")
|
||||
}
|
202
vendor/github.com/stacktic/dropbox/datastores_parser_test.go
generated
vendored
202
vendor/github.com/stacktic/dropbox/datastores_parser_test.go
generated
vendored
@ -1,202 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type equaller interface {
|
||||
equals(equaller) bool
|
||||
}
|
||||
|
||||
func (s *atom) equals(o *atom) bool {
|
||||
switch v1 := s.Value.(type) {
|
||||
case float64:
|
||||
if v2, ok := o.Value.(float64); ok {
|
||||
if math.IsNaN(v1) && math.IsNaN(v2) {
|
||||
return true
|
||||
}
|
||||
return v1 == v2
|
||||
}
|
||||
default:
|
||||
return reflect.DeepEqual(s, o)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *value) equals(o *value) bool {
|
||||
return reflect.DeepEqual(s, o)
|
||||
}
|
||||
|
||||
func (s Fields) equals(o Fields) bool {
|
||||
return reflect.DeepEqual(s, o)
|
||||
}
|
||||
|
||||
func (s opDict) equals(o opDict) bool {
|
||||
return reflect.DeepEqual(s, o)
|
||||
}
|
||||
|
||||
func (s *change) equals(o *change) bool {
|
||||
return reflect.DeepEqual(s, o)
|
||||
}
|
||||
|
||||
func (s *fieldOp) equals(o *fieldOp) bool {
|
||||
return reflect.DeepEqual(s, o)
|
||||
}
|
||||
|
||||
func testDSAtom(t *testing.T, c *atom, e string) {
|
||||
var c2 atom
|
||||
var err error
|
||||
var js []byte
|
||||
|
||||
if js, err = json.Marshal(c); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if err = c2.UnmarshalJSON(js); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if !c.equals(&c2) {
|
||||
t.Errorf("expected %#v type %s got %#v of type %s", c.Value, reflect.TypeOf(c.Value).Name(), c2.Value, reflect.TypeOf(c2.Value).Name())
|
||||
}
|
||||
c2 = atom{}
|
||||
if err = c2.UnmarshalJSON([]byte(e)); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if !c.equals(&c2) {
|
||||
t.Errorf("expected %#v type %s got %#v of type %s", c.Value, reflect.TypeOf(c.Value).Name(), c2.Value, reflect.TypeOf(c2.Value).Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSAtomUnmarshalJSON(t *testing.T) {
|
||||
testDSAtom(t, &atom{Value: 32.5}, `32.5`)
|
||||
testDSAtom(t, &atom{Value: true}, `true`)
|
||||
testDSAtom(t, &atom{Value: int64(42)}, `{"I":"42"}`)
|
||||
testDSAtom(t, &atom{Value: math.NaN()}, `{"N":"nan"}`)
|
||||
testDSAtom(t, &atom{Value: math.Inf(1)}, `{"N":"+inf"}`)
|
||||
testDSAtom(t, &atom{Value: math.Inf(-1)}, `{"N":"-inf"}`)
|
||||
testDSAtom(t, &atom{Value: []byte(`random string converted to bytes`)}, `{"B":"cmFuZG9tIHN0cmluZyBjb252ZXJ0ZWQgdG8gYnl0ZXM="}`)
|
||||
|
||||
now := time.Now().Round(time.Millisecond)
|
||||
js := fmt.Sprintf(`{"T": "%d"}`, now.UnixNano()/int64(time.Millisecond))
|
||||
testDSAtom(t, &atom{Value: now}, js)
|
||||
}
|
||||
|
||||
func testDSChange(t *testing.T, c *change, e string) {
|
||||
var c2 change
|
||||
var err error
|
||||
var js []byte
|
||||
|
||||
if js, err = json.Marshal(c); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if err = c2.UnmarshalJSON(js); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if !c.equals(&c2) {
|
||||
t.Errorf("mismatch: got:\n\t%#v\nexpected:\n\t%#v", c2, *c)
|
||||
}
|
||||
c2 = change{}
|
||||
if err = c2.UnmarshalJSON([]byte(e)); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if !c.equals(&c2) {
|
||||
t.Errorf("mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSChangeUnmarshalJSON(t *testing.T) {
|
||||
testDSChange(t,
|
||||
&change{
|
||||
Op: recordInsert,
|
||||
TID: "dropbox",
|
||||
RecordID: "test",
|
||||
Data: Fields{"float": value{values: []interface{}{float64(42)}, isList: false}},
|
||||
}, `["I","dropbox","test",{"float":42}]`)
|
||||
testDSChange(t,
|
||||
&change{
|
||||
Op: recordUpdate,
|
||||
TID: "dropbox",
|
||||
RecordID: "test",
|
||||
Ops: opDict{"field": fieldOp{Op: fieldPut, Data: value{values: []interface{}{float64(42)}, isList: false}}},
|
||||
}, `["U","dropbox","test",{"field":["P", 42]}]`)
|
||||
testDSChange(t,
|
||||
&change{
|
||||
Op: recordUpdate,
|
||||
TID: "dropbox",
|
||||
RecordID: "test",
|
||||
Ops: opDict{"field": fieldOp{Op: listCreate}},
|
||||
}, `["U","dropbox","test",{"field":["LC"]}]`)
|
||||
|
||||
testDSChange(t,
|
||||
&change{
|
||||
Op: recordDelete,
|
||||
TID: "dropbox",
|
||||
RecordID: "test",
|
||||
}, `["D","dropbox","test"]`)
|
||||
}
|
||||
|
||||
func testCheckfieldOp(t *testing.T, fo *fieldOp, e string) {
|
||||
var fo2 fieldOp
|
||||
var js []byte
|
||||
var err error
|
||||
|
||||
if js, err = json.Marshal(fo); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if string(js) != e {
|
||||
t.Errorf("marshalling error got %s expected %s", string(js), e)
|
||||
}
|
||||
if err = json.Unmarshal(js, &fo2); err != nil {
|
||||
t.Errorf("%s %s", err, string(js))
|
||||
}
|
||||
if !fo.equals(&fo2) {
|
||||
t.Errorf("%#v != %#v\n", fo, fo2)
|
||||
}
|
||||
fo2 = fieldOp{}
|
||||
if err = json.Unmarshal([]byte(e), &fo2); err != nil {
|
||||
t.Errorf("%s %s", err, string(js))
|
||||
}
|
||||
if !fo.equals(&fo2) {
|
||||
t.Errorf("%#v != %#v\n", fo, fo2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSfieldOpMarshalling(t *testing.T) {
|
||||
testCheckfieldOp(t, &fieldOp{Op: "P", Data: value{values: []interface{}{"bar"}, isList: false}}, `["P","bar"]`)
|
||||
testCheckfieldOp(t, &fieldOp{Op: "P", Data: value{values: []interface{}{"ga", "bu", "zo", "meuh", int64(42), 4.5, true}, isList: true}}, `["P",["ga","bu","zo","meuh",{"I":"42"},4.5,true]]`)
|
||||
testCheckfieldOp(t, &fieldOp{Op: "D"}, `["D"]`)
|
||||
testCheckfieldOp(t, &fieldOp{Op: "LC"}, `["LC"]`)
|
||||
testCheckfieldOp(t, &fieldOp{Op: "LP", Index: 1, Data: value{values: []interface{}{"baz"}}}, `["LP",1,"baz"]`)
|
||||
testCheckfieldOp(t, &fieldOp{Op: "LI", Index: 1, Data: value{values: []interface{}{"baz"}}}, `["LI",1,"baz"]`)
|
||||
testCheckfieldOp(t, &fieldOp{Op: "LD", Index: 1}, `["LD",1]`)
|
||||
testCheckfieldOp(t, &fieldOp{Op: "LM", Index: 1, Index2: 2}, `["LM",1,2]`)
|
||||
}
|
305
vendor/github.com/stacktic/dropbox/datastores_requests.go
generated
vendored
305
vendor/github.com/stacktic/dropbox/datastores_requests.go
generated
vendored
@ -1,305 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type row struct {
|
||||
TID string `json:"tid"`
|
||||
RowID string `json:"rowid"`
|
||||
Data Fields `json:"data"`
|
||||
}
|
||||
|
||||
type infoDict struct {
|
||||
Title string `json:"title"`
|
||||
MTime struct {
|
||||
Time DBTime `json:"T"`
|
||||
} `json:"mtime"`
|
||||
}
|
||||
|
||||
type datastoreInfo struct {
|
||||
ID string `json:"dsid"`
|
||||
Handle string `json:"handle"`
|
||||
Revision int `json:"rev"`
|
||||
Info infoDict `json:"info"`
|
||||
}
|
||||
|
||||
func (db *Dropbox) openOrCreateDatastore(dsID string) (int, string, bool, error) {
|
||||
var r struct {
|
||||
Revision int `json:"rev"`
|
||||
Handle string `json:"handle"`
|
||||
Created bool `json:"created"`
|
||||
}
|
||||
|
||||
err := db.doRequest("POST", "datastores/get_or_create_datastore", &url.Values{"dsid": {dsID}}, &r)
|
||||
return r.Revision, r.Handle, r.Created, err
|
||||
}
|
||||
|
||||
func (db *Dropbox) listDatastores() ([]DatastoreInfo, string, error) {
|
||||
var rv []DatastoreInfo
|
||||
|
||||
var dl struct {
|
||||
Info []datastoreInfo `json:"datastores"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
if err := db.doRequest("GET", "datastores/list_datastores", nil, &dl); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
rv = make([]DatastoreInfo, len(dl.Info))
|
||||
for i, di := range dl.Info {
|
||||
rv[i] = DatastoreInfo{
|
||||
ID: di.ID,
|
||||
handle: di.Handle,
|
||||
revision: di.Revision,
|
||||
title: di.Info.Title,
|
||||
mtime: time.Time(di.Info.MTime.Time),
|
||||
}
|
||||
}
|
||||
return rv, dl.Token, nil
|
||||
}
|
||||
|
||||
func (db *Dropbox) deleteDatastore(handle string) (*string, error) {
|
||||
var r struct {
|
||||
NotFound string `json:"notfound"`
|
||||
OK string `json:"ok"`
|
||||
}
|
||||
|
||||
if err := db.doRequest("POST", "datastores/delete_datastore", &url.Values{"handle": {handle}}, &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(r.NotFound) != 0 {
|
||||
return nil, fmt.Errorf(r.NotFound)
|
||||
}
|
||||
return &r.OK, nil
|
||||
}
|
||||
|
||||
func generateDatastoreID() (string, error) {
|
||||
var b []byte
|
||||
var blen int
|
||||
|
||||
b = make([]byte, 1)
|
||||
_, err := io.ReadFull(rand.Reader, b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
blen = (int(b[0]) % maxGlobalIDLength) + 1
|
||||
b = make([]byte, blen)
|
||||
_, err = io.ReadFull(rand.Reader, b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return encodeDBase64(b), nil
|
||||
}
|
||||
|
||||
func (db *Dropbox) createDatastore(key string) (int, string, bool, error) {
|
||||
var r struct {
|
||||
Revision int `json:"rev"`
|
||||
Handle string `json:"handle"`
|
||||
Created bool `json:"created"`
|
||||
NotFound string `json:"notfound"`
|
||||
}
|
||||
var b64key string
|
||||
var err error
|
||||
|
||||
if len(key) != 0 {
|
||||
b64key = encodeDBase64([]byte(key))
|
||||
} else {
|
||||
b64key, err = generateDatastoreID()
|
||||
if err != nil {
|
||||
return 0, "", false, err
|
||||
}
|
||||
}
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(b64key))
|
||||
rhash := hash.Sum(nil)
|
||||
dsID := "." + encodeDBase64(rhash[:])
|
||||
|
||||
params := &url.Values{
|
||||
"key": {b64key},
|
||||
"dsid": {dsID},
|
||||
}
|
||||
if err := db.doRequest("POST", "datastores/create_datastore", params, &r); err != nil {
|
||||
return 0, "", false, err
|
||||
}
|
||||
if len(r.NotFound) != 0 {
|
||||
return 0, "", false, fmt.Errorf("%s", r.NotFound)
|
||||
}
|
||||
return r.Revision, r.Handle, r.Created, nil
|
||||
}
|
||||
|
||||
func (db *Dropbox) putDelta(handle string, rev int, changes listOfChanges) (int, error) {
|
||||
var r struct {
|
||||
Revision int `json:"rev"`
|
||||
NotFound string `json:"notfound"`
|
||||
Conflict string `json:"conflict"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
var js []byte
|
||||
var err error
|
||||
|
||||
if len(changes) == 0 {
|
||||
return rev, nil
|
||||
}
|
||||
|
||||
if js, err = json.Marshal(changes); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
params := &url.Values{
|
||||
"handle": {handle},
|
||||
"rev": {strconv.FormatInt(int64(rev), 10)},
|
||||
"changes": {string(js)},
|
||||
}
|
||||
|
||||
if err = db.doRequest("POST", "datastores/put_delta", params, &r); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(r.NotFound) != 0 {
|
||||
return 0, fmt.Errorf("%s", r.NotFound)
|
||||
}
|
||||
if len(r.Conflict) != 0 {
|
||||
return 0, fmt.Errorf("%s", r.Conflict)
|
||||
}
|
||||
if len(r.Error) != 0 {
|
||||
return 0, fmt.Errorf("%s", r.Error)
|
||||
}
|
||||
return r.Revision, nil
|
||||
}
|
||||
|
||||
func (db *Dropbox) getDelta(handle string, rev int) ([]datastoreDelta, error) {
|
||||
var rv struct {
|
||||
Deltas []datastoreDelta `json:"deltas"`
|
||||
NotFound string `json:"notfound"`
|
||||
}
|
||||
err := db.doRequest("GET", "datastores/get_deltas",
|
||||
&url.Values{
|
||||
"handle": {handle},
|
||||
"rev": {strconv.FormatInt(int64(rev), 10)},
|
||||
}, &rv)
|
||||
|
||||
if len(rv.NotFound) != 0 {
|
||||
return nil, fmt.Errorf("%s", rv.NotFound)
|
||||
}
|
||||
return rv.Deltas, err
|
||||
}
|
||||
|
||||
func (db *Dropbox) getSnapshot(handle string) ([]row, int, error) {
|
||||
var r struct {
|
||||
Rows []row `json:"rows"`
|
||||
Revision int `json:"rev"`
|
||||
NotFound string `json:"notfound"`
|
||||
}
|
||||
|
||||
if err := db.doRequest("GET", "datastores/get_snapshot",
|
||||
&url.Values{"handle": {handle}}, &r); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(r.NotFound) != 0 {
|
||||
return nil, 0, fmt.Errorf("%s", r.NotFound)
|
||||
}
|
||||
return r.Rows, r.Revision, nil
|
||||
}
|
||||
|
||||
func (db *Dropbox) await(cursors []*Datastore, token string) (string, []DatastoreInfo, map[string][]datastoreDelta, error) {
|
||||
var params *url.Values
|
||||
var dis []DatastoreInfo
|
||||
var dd map[string][]datastoreDelta
|
||||
|
||||
type awaitResult struct {
|
||||
Deltas struct {
|
||||
Results map[string]struct {
|
||||
Deltas []datastoreDelta `json:"deltas"`
|
||||
NotFound string `json:"notfound"`
|
||||
} `json:"deltas"`
|
||||
} `json:"get_deltas"`
|
||||
Datastores struct {
|
||||
Info []datastoreInfo `json:"datastores"`
|
||||
Token string `json:"token"`
|
||||
} `json:"list_datastores"`
|
||||
}
|
||||
var r awaitResult
|
||||
if len(token) == 0 && len(cursors) == 0 {
|
||||
return "", nil, nil, fmt.Errorf("at least one parameter required")
|
||||
}
|
||||
params = &url.Values{}
|
||||
if len(token) != 0 {
|
||||
js, err := json.Marshal(map[string]string{"token": token})
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
params.Set("list_datastores", string(js))
|
||||
}
|
||||
if len(cursors) != 0 {
|
||||
m := make(map[string]int)
|
||||
for _, ds := range cursors {
|
||||
m[ds.info.handle] = ds.info.revision
|
||||
}
|
||||
js, err := json.Marshal(map[string]map[string]int{"cursors": m})
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
params.Set("get_deltas", string(js))
|
||||
}
|
||||
if err := db.doRequest("GET", "datastores/await", params, &r); err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
if len(r.Deltas.Results) == 0 && len(r.Datastores.Info) == 0 {
|
||||
return token, nil, nil, fmt.Errorf("await timed out")
|
||||
}
|
||||
if len(r.Datastores.Token) != 0 {
|
||||
token = r.Datastores.Token
|
||||
}
|
||||
if len(r.Deltas.Results) != 0 {
|
||||
dd = make(map[string][]datastoreDelta)
|
||||
for k, v := range r.Deltas.Results {
|
||||
dd[k] = v.Deltas
|
||||
}
|
||||
}
|
||||
if len(r.Datastores.Info) != 0 {
|
||||
dis = make([]DatastoreInfo, len(r.Datastores.Info))
|
||||
for i, di := range r.Datastores.Info {
|
||||
dis[i] = DatastoreInfo{
|
||||
ID: di.ID,
|
||||
handle: di.Handle,
|
||||
revision: di.Revision,
|
||||
title: di.Info.Title,
|
||||
mtime: time.Time(di.Info.MTime.Time),
|
||||
}
|
||||
}
|
||||
}
|
||||
return token, dis, dd, nil
|
||||
}
|
263
vendor/github.com/stacktic/dropbox/datastores_test.go
generated
vendored
263
vendor/github.com/stacktic/dropbox/datastores_test.go
generated
vendored
@ -1,263 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func checkList(t *testing.T, l *List, e []interface{}) {
|
||||
var elt1 interface{}
|
||||
var err error
|
||||
|
||||
if l.Size() != len(e) {
|
||||
t.Errorf("wrong size")
|
||||
}
|
||||
for i := range e {
|
||||
if elt1, err = l.Get(i); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if elt1 != e[i] {
|
||||
t.Errorf("position %d mismatch got %#v, expected %#v", i, elt1, e[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newDatastore(t *testing.T) *Datastore {
|
||||
var ds *Datastore
|
||||
|
||||
ds = &Datastore{
|
||||
manager: newDropbox(t).NewDatastoreManager(),
|
||||
info: DatastoreInfo{
|
||||
ID: "dummyID",
|
||||
handle: "dummyHandle",
|
||||
title: "dummyTitle",
|
||||
revision: 0,
|
||||
},
|
||||
tables: make(map[string]*Table),
|
||||
changesQueue: make(chan changeWork),
|
||||
}
|
||||
go ds.doHandleChange()
|
||||
return ds
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
var tbl *Table
|
||||
var r *Record
|
||||
var ds *Datastore
|
||||
var l *List
|
||||
var err error
|
||||
|
||||
ds = newDatastore(t)
|
||||
|
||||
if tbl, err = ds.GetTable("dummyTable"); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if r, err = tbl.GetOrInsert("dummyRecord"); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if l, err = r.GetOrCreateList("dummyList"); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
for i := 0; i < 10; i++ {
|
||||
if err = l.Add(i); err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
}
|
||||
if ftype, err := r.GetFieldType("dummyList"); err != nil || ftype != TypeList {
|
||||
t.Errorf("wrong type")
|
||||
}
|
||||
|
||||
ftype, err := l.GetType(0)
|
||||
if err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if ftype != TypeInteger {
|
||||
t.Errorf("wrong type")
|
||||
}
|
||||
|
||||
checkList(t, l, []interface{}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
|
||||
if err = l.Remove(5); err != nil {
|
||||
t.Errorf("could not remove element 5")
|
||||
}
|
||||
checkList(t, l, []interface{}{0, 1, 2, 3, 4, 6, 7, 8, 9})
|
||||
|
||||
if err = l.Remove(0); err != nil {
|
||||
t.Errorf("could not remove element 0")
|
||||
}
|
||||
checkList(t, l, []interface{}{1, 2, 3, 4, 6, 7, 8, 9})
|
||||
|
||||
if err = l.Remove(7); err != nil {
|
||||
t.Errorf("could not remove element 7")
|
||||
}
|
||||
checkList(t, l, []interface{}{1, 2, 3, 4, 6, 7, 8})
|
||||
|
||||
if err = l.Remove(7); err == nil {
|
||||
t.Errorf("out of bound index must return an error")
|
||||
}
|
||||
checkList(t, l, []interface{}{1, 2, 3, 4, 6, 7, 8})
|
||||
|
||||
if err = l.Move(3, 6); err != nil {
|
||||
t.Errorf("could not move element 3 to position 6")
|
||||
}
|
||||
checkList(t, l, []interface{}{1, 2, 3, 6, 7, 8, 4})
|
||||
|
||||
if err = l.Move(3, 9); err == nil {
|
||||
t.Errorf("out of bound index must return an error")
|
||||
}
|
||||
checkList(t, l, []interface{}{1, 2, 3, 6, 7, 8, 4})
|
||||
|
||||
if err = l.Move(6, 3); err != nil {
|
||||
t.Errorf("could not move element 6 to position 3")
|
||||
}
|
||||
checkList(t, l, []interface{}{1, 2, 3, 4, 6, 7, 8})
|
||||
|
||||
if err = l.AddAtPos(0, 0); err != nil {
|
||||
t.Errorf("could not insert element at position 0")
|
||||
}
|
||||
checkList(t, l, []interface{}{0, 1, 2, 3, 4, 6, 7, 8})
|
||||
|
||||
if err = l.Add(9); err != nil {
|
||||
t.Errorf("could not append element")
|
||||
}
|
||||
checkList(t, l, []interface{}{0, 1, 2, 3, 4, 6, 7, 8, 9})
|
||||
|
||||
if err = l.AddAtPos(5, 5); err != nil {
|
||||
t.Errorf("could not insert element at position 5")
|
||||
}
|
||||
checkList(t, l, []interface{}{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
|
||||
if err = l.Set(0, 3); err != nil {
|
||||
t.Errorf("could not update element at position 0")
|
||||
}
|
||||
checkList(t, l, []interface{}{3, 1, 2, 3, 4, 5, 6, 7, 8, 9})
|
||||
|
||||
if err = l.Set(9, 2); err != nil {
|
||||
t.Errorf("could not update element at position 9")
|
||||
}
|
||||
checkList(t, l, []interface{}{3, 1, 2, 3, 4, 5, 6, 7, 8, 2})
|
||||
|
||||
if err = l.Set(10, 11); err == nil {
|
||||
t.Errorf("out of bound index must return an error")
|
||||
}
|
||||
checkList(t, l, []interface{}{3, 1, 2, 3, 4, 5, 6, 7, 8, 2})
|
||||
}
|
||||
|
||||
func TestGenerateID(t *testing.T) {
|
||||
f, err := generateDatastoreID()
|
||||
if err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if !isValidDatastoreID(f) {
|
||||
t.Errorf("generated ID is not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalAwait(t *testing.T) {
|
||||
type awaitResult struct {
|
||||
Deltas struct {
|
||||
Results map[string]struct {
|
||||
Deltas []datastoreDelta `json:"deltas"`
|
||||
} `json:"deltas"`
|
||||
} `json:"get_deltas"`
|
||||
Datastores struct {
|
||||
Info []datastoreInfo `json:"datastores"`
|
||||
Token string `json:"token"`
|
||||
} `json:"list_datastores"`
|
||||
}
|
||||
var r awaitResult
|
||||
var datastoreID string
|
||||
var res []datastoreDelta
|
||||
|
||||
js := `{"get_deltas":{"deltas":{"12345678901234567890":{"deltas":[{"changes":[["I","dummyTable","dummyRecord",{}]],"nonce":"","rev":0},{"changes":[["U","dummyTable","dummyRecord",{"name":["P","dummy"]}],["U","dummyTable","dummyRecord",{"dummyList":["LC"]}]],"nonce":"","rev":1},{"changes":[["U","dummyTable","dummyRecord",{"dummyList":["LI",0,{"I":"0"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",1,{"I":"1"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",2,{"I":"2"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",3,{"I":"3"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",4,{"I":"4"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",5,{"I":"5"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",6,{"I":"6"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",7,{"I":"7"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",8,{"I":"8"}]}],["U","dummyTable","dummyRecord",{"dummyList":["LI",9,{"I":"9"}]}]],"nonce":"","rev":2},{"changes":[["D","dummyTable","dummyRecord"]],"nonce":"","rev":3}]}}}}`
|
||||
datastoreID = "12345678901234567890"
|
||||
|
||||
expected := []datastoreDelta{
|
||||
datastoreDelta{
|
||||
Revision: 0,
|
||||
Changes: listOfChanges{
|
||||
&change{Op: recordInsert, TID: "dummyTable", RecordID: "dummyRecord", Data: Fields{}},
|
||||
},
|
||||
},
|
||||
datastoreDelta{
|
||||
Revision: 1,
|
||||
Changes: listOfChanges{
|
||||
&change{Op: "U", TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"name": fieldOp{Op: "P", Index: 0, Data: value{values: []interface{}{"dummy"}}}}},
|
||||
&change{Op: "U", TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: "LC"}}},
|
||||
},
|
||||
},
|
||||
datastoreDelta{
|
||||
Revision: 2,
|
||||
Changes: listOfChanges{
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 0, Data: value{values: []interface{}{int64(0)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 1, Data: value{values: []interface{}{int64(1)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 2, Data: value{values: []interface{}{int64(2)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 3, Data: value{values: []interface{}{int64(3)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 4, Data: value{values: []interface{}{int64(4)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 5, Data: value{values: []interface{}{int64(5)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 6, Data: value{values: []interface{}{int64(6)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 7, Data: value{values: []interface{}{int64(7)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 8, Data: value{values: []interface{}{int64(8)}}}}},
|
||||
&change{Op: recordUpdate, TID: "dummyTable", RecordID: "dummyRecord", Ops: opDict{"dummyList": fieldOp{Op: listInsert, Index: 9, Data: value{values: []interface{}{int64(9)}}}}},
|
||||
},
|
||||
},
|
||||
datastoreDelta{
|
||||
Revision: 3,
|
||||
Changes: listOfChanges{
|
||||
&change{Op: "D", TID: "dummyTable", RecordID: "dummyRecord"},
|
||||
},
|
||||
},
|
||||
}
|
||||
err := json.Unmarshal([]byte(js), &r)
|
||||
if err != nil {
|
||||
t.Errorf("%s", err)
|
||||
}
|
||||
if len(r.Deltas.Results) != 1 {
|
||||
t.Errorf("wrong number of datastoreDelta")
|
||||
}
|
||||
|
||||
if tmp, ok := r.Deltas.Results[datastoreID]; !ok {
|
||||
t.Fatalf("wrong datastore ID")
|
||||
} else {
|
||||
res = tmp.Deltas
|
||||
}
|
||||
if len(res) != len(expected) {
|
||||
t.Fatalf("got %d results expected %d", len(res), len(expected))
|
||||
}
|
||||
for i, d := range res {
|
||||
ed := expected[i]
|
||||
if d.Revision != ed.Revision {
|
||||
t.Errorf("wrong revision got %d expected %d", d.Revision, expected[i].Revision)
|
||||
}
|
||||
for j, c := range d.Changes {
|
||||
if !c.equals(ed.Changes[j]) {
|
||||
t.Errorf("wrong change: got: %+v expected: %+v", *c, *ed.Changes[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
943
vendor/github.com/stacktic/dropbox/dropbox.go
generated
vendored
943
vendor/github.com/stacktic/dropbox/dropbox.go
generated
vendored
@ -1,943 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Package dropbox implements the Dropbox core and datastore API.
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// ErrNotAuth is the error returned when the OAuth token is not provided
|
||||
var ErrNotAuth = errors.New("authentication required")
|
||||
|
||||
// Account represents information about the user account.
|
||||
type Account struct {
|
||||
ReferralLink string `json:"referral_link,omitempty"` // URL for referral.
|
||||
DisplayName string `json:"display_name,omitempty"` // User name.
|
||||
UID int `json:"uid,omitempty"` // User account ID.
|
||||
Country string `json:"country,omitempty"` // Country ISO code.
|
||||
QuotaInfo struct {
|
||||
Shared int64 `json:"shared,omitempty"` // Quota for shared files.
|
||||
Quota int64 `json:"quota,omitempty"` // Quota in bytes.
|
||||
Normal int64 `json:"normal,omitempty"` // Quota for non-shared files.
|
||||
} `json:"quota_info"`
|
||||
}
|
||||
|
||||
// CopyRef represents the reply of CopyRef.
|
||||
type CopyRef struct {
|
||||
CopyRef string `json:"copy_ref"` // Reference to use on fileops/copy.
|
||||
Expires string `json:"expires"` // Expiration date.
|
||||
}
|
||||
|
||||
// DeltaPage represents the reply of delta.
|
||||
type DeltaPage struct {
|
||||
Reset bool // if true the local state must be cleared.
|
||||
HasMore bool // if true an other call to delta should be made.
|
||||
Cursor // Tag of the current state.
|
||||
Entries []DeltaEntry // List of changed entries.
|
||||
}
|
||||
|
||||
// DeltaEntry represents the list of changes for a given path.
|
||||
type DeltaEntry struct {
|
||||
Path string // Path of this entry in lowercase.
|
||||
Entry *Entry // nil when this entry does not exists.
|
||||
}
|
||||
|
||||
// DeltaPoll represents the reply of longpoll_delta.
|
||||
type DeltaPoll struct {
|
||||
Changes bool `json:"changes"` // true if the polled path has changed.
|
||||
Backoff int `json:"backoff"` // time in second before calling poll again.
|
||||
}
|
||||
|
||||
// ChunkUploadResponse represents the reply of chunked_upload.
|
||||
type ChunkUploadResponse struct {
|
||||
UploadID string `json:"upload_id"` // Unique ID of this upload.
|
||||
Offset int64 `json:"offset"` // Size in bytes of already sent data.
|
||||
Expires DBTime `json:"expires"` // Expiration time of this upload.
|
||||
}
|
||||
|
||||
// Cursor represents the tag of a server state at a given moment.
|
||||
type Cursor struct {
|
||||
Cursor string `json:"cursor"`
|
||||
}
|
||||
|
||||
// Format of reply when http error code is not 200.
|
||||
// Format may be:
|
||||
// {"error": "reason"}
|
||||
// {"error": {"param": "reason"}}
|
||||
type requestError struct {
|
||||
Error interface{} `json:"error"` // Description of this error.
|
||||
}
|
||||
|
||||
const (
|
||||
// PollMinTimeout is the minimum timeout for longpoll.
|
||||
PollMinTimeout = 30
|
||||
// PollMaxTimeout is the maximum timeout for longpoll.
|
||||
PollMaxTimeout = 480
|
||||
// DefaultChunkSize is the maximum size of a file sendable using files_put.
|
||||
DefaultChunkSize = 4 * 1024 * 1024
|
||||
// MaxPutFileSize is the maximum size of a file sendable using files_put.
|
||||
MaxPutFileSize = 150 * 1024 * 1024
|
||||
// MetadataLimitMax is the maximum number of entries returned by metadata.
|
||||
MetadataLimitMax = 25000
|
||||
// MetadataLimitDefault is the default number of entries returned by metadata.
|
||||
MetadataLimitDefault = 10000
|
||||
// RevisionsLimitMax is the maximum number of revisions returned by revisions.
|
||||
RevisionsLimitMax = 1000
|
||||
// RevisionsLimitDefault is the default number of revisions returned by revisions.
|
||||
RevisionsLimitDefault = 10
|
||||
// SearchLimitMax is the maximum number of entries returned by search.
|
||||
SearchLimitMax = 1000
|
||||
// SearchLimitDefault is the default number of entries returned by search.
|
||||
SearchLimitDefault = 1000
|
||||
// DateFormat is the format to use when decoding a time.
|
||||
DateFormat = time.RFC1123Z
|
||||
)
|
||||
|
||||
// DBTime allow marshalling and unmarshalling of time.
|
||||
type DBTime time.Time
|
||||
|
||||
// UnmarshalJSON unmarshals a time according to the Dropbox format.
|
||||
func (dbt *DBTime) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
var err error
|
||||
var t time.Time
|
||||
|
||||
if err = json.Unmarshal(data, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
if t, err = time.ParseInLocation(DateFormat, s, time.UTC); err != nil {
|
||||
return err
|
||||
}
|
||||
if t.IsZero() {
|
||||
*dbt = DBTime(time.Time{})
|
||||
} else {
|
||||
*dbt = DBTime(t)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON marshals a time according to the Dropbox format.
|
||||
func (dbt DBTime) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(time.Time(dbt).Format(DateFormat))
|
||||
}
|
||||
|
||||
// Modifier represents the user who made a change on a particular file
|
||||
type Modifier struct {
|
||||
UID int64 `json:"uid"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
// Entry represents the metadata of a file or folder.
|
||||
type Entry struct {
|
||||
Bytes int64 `json:"bytes,omitempty"` // Size of the file in bytes.
|
||||
ClientMtime DBTime `json:"client_mtime,omitempty"` // Modification time set by the client when added.
|
||||
Contents []Entry `json:"contents,omitempty"` // List of children for a directory.
|
||||
Hash string `json:"hash,omitempty"` // Hash of this entry.
|
||||
Icon string `json:"icon,omitempty"` // Name of the icon displayed for this entry.
|
||||
IsDeleted bool `json:"is_deleted,omitempty"` // true if this entry was deleted.
|
||||
IsDir bool `json:"is_dir,omitempty"` // true if this entry is a directory.
|
||||
MimeType string `json:"mime_type,omitempty"` // MimeType of this entry.
|
||||
Modified DBTime `json:"modified,omitempty"` // Date of last modification.
|
||||
Path string `json:"path,omitempty"` // Absolute path of this entry.
|
||||
Revision string `json:"rev,omitempty"` // Unique ID for this file revision.
|
||||
Root string `json:"root,omitempty"` // dropbox or sandbox.
|
||||
Size string `json:"size,omitempty"` // Size of the file humanized/localized.
|
||||
ThumbExists bool `json:"thumb_exists,omitempty"` // true if a thumbnail is available for this entry.
|
||||
Modifier *Modifier `json:"modifier"` // last user to edit the file if in a shared folder
|
||||
ParentSharedFolderID string `json:"parent_shared_folder_id,omitempty"`
|
||||
}
|
||||
|
||||
// Link for sharing a file.
|
||||
type Link struct {
|
||||
Expires DBTime `json:"expires"` // Expiration date of this link.
|
||||
URL string `json:"url"` // URL to share.
|
||||
}
|
||||
|
||||
// User represents a Dropbox user.
|
||||
type User struct {
|
||||
UID int64 `json:"uid"`
|
||||
DisplayName string `json:"display_name"`
|
||||
}
|
||||
|
||||
// SharedFolderMember represents access right associated with a Dropbox user.
|
||||
type SharedFolderMember struct {
|
||||
User User `json:"user"`
|
||||
Active bool `json:"active"`
|
||||
AccessType string `json:"access_type"`
|
||||
}
|
||||
|
||||
// SharedFolder reprensents a directory with a specific sharing policy.
|
||||
type SharedFolder struct {
|
||||
SharedFolderID string `json:"shared_folder_id"`
|
||||
SharedFolderName string `json:"shared_folder_name"`
|
||||
Path string `json:"path"`
|
||||
AccessType string `json:"access_type"`
|
||||
SharedLinkPolicy string `json:"shared_link_policy"`
|
||||
Owner User `json:"owner"`
|
||||
Membership []SharedFolderMember `json:"membership"`
|
||||
}
|
||||
|
||||
// Dropbox client.
|
||||
type Dropbox struct {
|
||||
RootDirectory string // dropbox or sandbox.
|
||||
Locale string // Locale sent to the API to translate/format messages.
|
||||
APIURL string // Normal API URL.
|
||||
APIContentURL string // URL for transferring files.
|
||||
APINotifyURL string // URL for realtime notification.
|
||||
config *oauth2.Config
|
||||
token *oauth2.Token
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewDropbox returns a new Dropbox configured.
|
||||
func NewDropbox() *Dropbox {
|
||||
db := &Dropbox{
|
||||
RootDirectory: "auto", // auto (recommended), dropbox or sandbox.
|
||||
Locale: "en",
|
||||
APIURL: "https://api.dropbox.com/1",
|
||||
APIContentURL: "https://api-content.dropbox.com/1",
|
||||
APINotifyURL: "https://api-notify.dropbox.com/1",
|
||||
ctx: oauth2.NoContext,
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
// SetAppInfo sets the clientid (app_key) and clientsecret (app_secret).
|
||||
// You have to register an application on https://www.dropbox.com/developers/apps.
|
||||
func (db *Dropbox) SetAppInfo(clientid, clientsecret string) error {
|
||||
|
||||
db.config = &oauth2.Config{
|
||||
ClientID: clientid,
|
||||
ClientSecret: clientsecret,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: "https://www.dropbox.com/1/oauth2/authorize",
|
||||
TokenURL: "https://api.dropbox.com/1/oauth2/token",
|
||||
},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAccessToken sets access token to avoid calling Auth method.
|
||||
func (db *Dropbox) SetAccessToken(accesstoken string) {
|
||||
db.token = &oauth2.Token{AccessToken: accesstoken}
|
||||
}
|
||||
|
||||
// SetContext allow to set a custom context.
|
||||
func (db *Dropbox) SetContext(ctx context.Context) {
|
||||
db.ctx = ctx
|
||||
}
|
||||
|
||||
// AccessToken returns the OAuth access token.
|
||||
func (db *Dropbox) AccessToken() string {
|
||||
return db.token.AccessToken
|
||||
}
|
||||
|
||||
// SetRedirectURL updates the configuration with the given redirection URL.
|
||||
func (db *Dropbox) SetRedirectURL(url string) {
|
||||
db.config.RedirectURL = url
|
||||
}
|
||||
|
||||
func (db *Dropbox) client() *http.Client {
|
||||
return db.config.Client(db.ctx, db.token)
|
||||
}
|
||||
|
||||
// Auth displays the URL to authorize this application to connect to your account.
|
||||
func (db *Dropbox) Auth() error {
|
||||
var code string
|
||||
|
||||
fmt.Printf("Please visit:\n%s\nEnter the code: ",
|
||||
db.config.AuthCodeURL(""))
|
||||
fmt.Scanln(&code)
|
||||
return db.AuthCode(code)
|
||||
}
|
||||
|
||||
// AuthCode gets the token associated with the given code.
|
||||
func (db *Dropbox) AuthCode(code string) error {
|
||||
t, err := db.config.Exchange(oauth2.NoContext, code)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db.token = t
|
||||
db.token.TokenType = "Bearer"
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error - all errors generated by HTTP transactions are of this type.
|
||||
// Other error may be passed on from library functions though.
|
||||
type Error struct {
|
||||
StatusCode int // HTTP status code
|
||||
Text string
|
||||
}
|
||||
|
||||
// Error satisfy the error interface.
|
||||
func (e *Error) Error() string {
|
||||
return e.Text
|
||||
}
|
||||
|
||||
// newError make a new error from a string.
|
||||
func newError(StatusCode int, Text string) *Error {
|
||||
return &Error{
|
||||
StatusCode: StatusCode,
|
||||
Text: Text,
|
||||
}
|
||||
}
|
||||
|
||||
// newErrorf makes a new error from sprintf parameters.
|
||||
func newErrorf(StatusCode int, Text string, Parameters ...interface{}) *Error {
|
||||
return newError(StatusCode, fmt.Sprintf(Text, Parameters...))
|
||||
}
|
||||
|
||||
func getResponse(r *http.Response) ([]byte, error) {
|
||||
var e requestError
|
||||
var b []byte
|
||||
var err error
|
||||
|
||||
if b, err = ioutil.ReadAll(r.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.StatusCode == http.StatusOK {
|
||||
return b, nil
|
||||
}
|
||||
if err = json.Unmarshal(b, &e); err == nil {
|
||||
switch v := e.Error.(type) {
|
||||
case string:
|
||||
return nil, newErrorf(r.StatusCode, "%s", v)
|
||||
case map[string]interface{}:
|
||||
for param, reason := range v {
|
||||
if reasonstr, ok := reason.(string); ok {
|
||||
return nil, newErrorf(r.StatusCode, "%s: %s", param, reasonstr)
|
||||
}
|
||||
}
|
||||
return nil, newErrorf(r.StatusCode, "wrong parameter")
|
||||
}
|
||||
}
|
||||
return nil, newErrorf(r.StatusCode, "unexpected HTTP status code %d", r.StatusCode)
|
||||
}
|
||||
|
||||
// urlEncode encodes s for url
|
||||
func urlEncode(s string) string {
|
||||
// Would like to call url.escape(value, encodePath) here
|
||||
encoded := url.QueryEscape(s)
|
||||
encoded = strings.Replace(encoded, "+", "%20", -1)
|
||||
return encoded
|
||||
}
|
||||
|
||||
// CommitChunkedUpload ends the chunked upload by giving a name to the UploadID.
|
||||
func (db *Dropbox) CommitChunkedUpload(uploadid, dst string, overwrite bool, parentRev string) (*Entry, error) {
|
||||
var err error
|
||||
var rawurl string
|
||||
var response *http.Response
|
||||
var params *url.Values
|
||||
var body []byte
|
||||
var rv Entry
|
||||
|
||||
if dst[0] == '/' {
|
||||
dst = dst[1:]
|
||||
}
|
||||
|
||||
params = &url.Values{
|
||||
"locale": {db.Locale},
|
||||
"upload_id": {uploadid},
|
||||
"overwrite": {strconv.FormatBool(overwrite)},
|
||||
}
|
||||
if len(parentRev) != 0 {
|
||||
params.Set("parent_rev", parentRev)
|
||||
}
|
||||
rawurl = fmt.Sprintf("%s/commit_chunked_upload/%s/%s?%s", db.APIContentURL, db.RootDirectory, urlEncode(dst), params.Encode())
|
||||
|
||||
if response, err = db.client().Post(rawurl, "", nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if body, err = getResponse(response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(body, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// ChunkedUpload sends a chunk with a maximum size of chunksize, if there is no session a new one is created.
|
||||
func (db *Dropbox) ChunkedUpload(session *ChunkUploadResponse, input io.ReadCloser, chunksize int) (*ChunkUploadResponse, error) {
|
||||
var err error
|
||||
var rawurl string
|
||||
var cur ChunkUploadResponse
|
||||
var response *http.Response
|
||||
var body []byte
|
||||
var r *io.LimitedReader
|
||||
|
||||
if chunksize <= 0 {
|
||||
chunksize = DefaultChunkSize
|
||||
} else if chunksize > MaxPutFileSize {
|
||||
chunksize = MaxPutFileSize
|
||||
}
|
||||
|
||||
if session != nil {
|
||||
rawurl = fmt.Sprintf("%s/chunked_upload?upload_id=%s&offset=%d", db.APIContentURL, session.UploadID, session.Offset)
|
||||
} else {
|
||||
rawurl = fmt.Sprintf("%s/chunked_upload", db.APIContentURL)
|
||||
}
|
||||
r = &io.LimitedReader{R: input, N: int64(chunksize)}
|
||||
|
||||
if response, err = db.client().Post(rawurl, "application/octet-stream", r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if body, err = getResponse(response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(body, &cur)
|
||||
if r.N != 0 {
|
||||
err = io.EOF
|
||||
}
|
||||
return &cur, err
|
||||
}
|
||||
|
||||
// UploadByChunk uploads data from the input reader to the dst path on Dropbox by sending chunks of chunksize.
|
||||
func (db *Dropbox) UploadByChunk(input io.ReadCloser, chunksize int, dst string, overwrite bool, parentRev string) (*Entry, error) {
|
||||
var err error
|
||||
var cur *ChunkUploadResponse
|
||||
|
||||
for err == nil {
|
||||
if cur, err = db.ChunkedUpload(cur, input, chunksize); err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return db.CommitChunkedUpload(cur.UploadID, dst, overwrite, parentRev)
|
||||
}
|
||||
|
||||
// FilesPut uploads size bytes from the input reader to the dst path on Dropbox.
|
||||
func (db *Dropbox) FilesPut(input io.ReadCloser, size int64, dst string, overwrite bool, parentRev string) (*Entry, error) {
|
||||
var err error
|
||||
var rawurl string
|
||||
var rv Entry
|
||||
var request *http.Request
|
||||
var response *http.Response
|
||||
var params *url.Values
|
||||
var body []byte
|
||||
|
||||
if size > MaxPutFileSize {
|
||||
return nil, fmt.Errorf("could not upload files bigger than 150MB using this method, use UploadByChunk instead")
|
||||
}
|
||||
if dst[0] == '/' {
|
||||
dst = dst[1:]
|
||||
}
|
||||
|
||||
params = &url.Values{"overwrite": {strconv.FormatBool(overwrite)}, "locale": {db.Locale}}
|
||||
if len(parentRev) != 0 {
|
||||
params.Set("parent_rev", parentRev)
|
||||
}
|
||||
rawurl = fmt.Sprintf("%s/files_put/%s/%s?%s", db.APIContentURL, db.RootDirectory, urlEncode(dst), params.Encode())
|
||||
|
||||
if request, err = http.NewRequest("PUT", rawurl, input); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Set("Content-Length", strconv.FormatInt(size, 10))
|
||||
if response, err = db.client().Do(request); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if body, err = getResponse(response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(body, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// UploadFile uploads the file located in the src path on the local disk to the dst path on Dropbox.
|
||||
func (db *Dropbox) UploadFile(src, dst string, overwrite bool, parentRev string) (*Entry, error) {
|
||||
var err error
|
||||
var fd *os.File
|
||||
var fsize int64
|
||||
|
||||
if fd, err = os.Open(src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
if fi, err := fd.Stat(); err == nil {
|
||||
fsize = fi.Size()
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
return db.FilesPut(fd, fsize, dst, overwrite, parentRev)
|
||||
}
|
||||
|
||||
// Thumbnails gets a thumbnail for an image.
|
||||
func (db *Dropbox) Thumbnails(src, format, size string) (io.ReadCloser, int64, *Entry, error) {
|
||||
var response *http.Response
|
||||
var rawurl string
|
||||
var err error
|
||||
var entry Entry
|
||||
|
||||
switch format {
|
||||
case "":
|
||||
format = "jpeg"
|
||||
case "jpeg", "png":
|
||||
break
|
||||
default:
|
||||
return nil, 0, nil, fmt.Errorf("unsupported format '%s' must be jpeg or png", format)
|
||||
}
|
||||
switch size {
|
||||
case "":
|
||||
size = "s"
|
||||
case "xs", "s", "m", "l", "xl":
|
||||
break
|
||||
default:
|
||||
return nil, 0, nil, fmt.Errorf("unsupported size '%s' must be xs, s, m, l or xl", size)
|
||||
|
||||
}
|
||||
if src[0] == '/' {
|
||||
src = src[1:]
|
||||
}
|
||||
rawurl = fmt.Sprintf("%s/thumbnails/%s/%s?format=%s&size=%s", db.APIContentURL, db.RootDirectory, urlEncode(src), urlEncode(format), urlEncode(size))
|
||||
if response, err = db.client().Get(rawurl); err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
if response.StatusCode == http.StatusOK {
|
||||
json.Unmarshal([]byte(response.Header.Get("x-dropbox-metadata")), &entry)
|
||||
return response.Body, response.ContentLength, &entry, err
|
||||
}
|
||||
response.Body.Close()
|
||||
switch response.StatusCode {
|
||||
case http.StatusNotFound:
|
||||
return nil, 0, nil, os.ErrNotExist
|
||||
case http.StatusUnsupportedMediaType:
|
||||
return nil, 0, nil, newErrorf(response.StatusCode, "the image located at '%s' cannot be converted to a thumbnail", src)
|
||||
default:
|
||||
return nil, 0, nil, newErrorf(response.StatusCode, "unexpected HTTP status code %d", response.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
// ThumbnailsToFile downloads the file located in the src path on the Dropbox to the dst file on the local disk.
|
||||
func (db *Dropbox) ThumbnailsToFile(src, dst, format, size string) (*Entry, error) {
|
||||
var input io.ReadCloser
|
||||
var fd *os.File
|
||||
var err error
|
||||
var entry *Entry
|
||||
|
||||
if fd, err = os.Create(dst); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
if input, _, entry, err = db.Thumbnails(src, format, size); err != nil {
|
||||
os.Remove(dst)
|
||||
return nil, err
|
||||
}
|
||||
defer input.Close()
|
||||
if _, err = io.Copy(fd, input); err != nil {
|
||||
os.Remove(dst)
|
||||
}
|
||||
return entry, err
|
||||
}
|
||||
|
||||
// Download requests the file located at src, the specific revision may be given.
|
||||
// offset is used in case the download was interrupted.
|
||||
// A io.ReadCloser and the file size is returned.
|
||||
func (db *Dropbox) Download(src, rev string, offset int64) (io.ReadCloser, int64, error) {
|
||||
var request *http.Request
|
||||
var response *http.Response
|
||||
var rawurl string
|
||||
var err error
|
||||
|
||||
if src[0] == '/' {
|
||||
src = src[1:]
|
||||
}
|
||||
|
||||
rawurl = fmt.Sprintf("%s/files/%s/%s", db.APIContentURL, db.RootDirectory, urlEncode(src))
|
||||
if len(rev) != 0 {
|
||||
rawurl += fmt.Sprintf("?rev=%s", rev)
|
||||
}
|
||||
if request, err = http.NewRequest("GET", rawurl, nil); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if offset != 0 {
|
||||
request.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
|
||||
}
|
||||
|
||||
if response, err = db.client().Do(request); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if response.StatusCode == http.StatusOK || response.StatusCode == http.StatusPartialContent {
|
||||
return response.Body, response.ContentLength, err
|
||||
}
|
||||
response.Body.Close()
|
||||
switch response.StatusCode {
|
||||
case http.StatusNotFound:
|
||||
return nil, 0, os.ErrNotExist
|
||||
default:
|
||||
return nil, 0, newErrorf(response.StatusCode, "unexpected HTTP status code %d", response.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
// DownloadToFileResume resumes the download of the file located in the src path on the Dropbox to the dst file on the local disk.
|
||||
func (db *Dropbox) DownloadToFileResume(src, dst, rev string) error {
|
||||
var input io.ReadCloser
|
||||
var fi os.FileInfo
|
||||
var fd *os.File
|
||||
var offset int64
|
||||
var err error
|
||||
|
||||
if fd, err = os.OpenFile(dst, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
defer fd.Close()
|
||||
if fi, err = fd.Stat(); err != nil {
|
||||
return err
|
||||
}
|
||||
offset = fi.Size()
|
||||
|
||||
if input, _, err = db.Download(src, rev, offset); err != nil {
|
||||
return err
|
||||
}
|
||||
defer input.Close()
|
||||
_, err = io.Copy(fd, input)
|
||||
return err
|
||||
}
|
||||
|
||||
// DownloadToFile downloads the file located in the src path on the Dropbox to the dst file on the local disk.
|
||||
// If the destination file exists it will be truncated.
|
||||
func (db *Dropbox) DownloadToFile(src, dst, rev string) error {
|
||||
var input io.ReadCloser
|
||||
var fd *os.File
|
||||
var err error
|
||||
|
||||
if fd, err = os.Create(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
if input, _, err = db.Download(src, rev, 0); err != nil {
|
||||
os.Remove(dst)
|
||||
return err
|
||||
}
|
||||
defer input.Close()
|
||||
if _, err = io.Copy(fd, input); err != nil {
|
||||
os.Remove(dst)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *Dropbox) doRequest(method, path string, params *url.Values, receiver interface{}) error {
|
||||
var body []byte
|
||||
var rawurl string
|
||||
var response *http.Response
|
||||
var request *http.Request
|
||||
var err error
|
||||
|
||||
if params == nil {
|
||||
params = &url.Values{"locale": {db.Locale}}
|
||||
} else {
|
||||
params.Set("locale", db.Locale)
|
||||
}
|
||||
rawurl = fmt.Sprintf("%s/%s?%s", db.APIURL, urlEncode(path), params.Encode())
|
||||
if request, err = http.NewRequest(method, rawurl, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if response, err = db.client().Do(request); err != nil {
|
||||
return err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if body, err = getResponse(response); err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(body, receiver)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAccountInfo gets account information for the user currently authenticated.
|
||||
func (db *Dropbox) GetAccountInfo() (*Account, error) {
|
||||
var rv Account
|
||||
|
||||
err := db.doRequest("GET", "account/info", nil, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// Shares shares a file.
|
||||
func (db *Dropbox) Shares(path string, shortURL bool) (*Link, error) {
|
||||
var rv Link
|
||||
var params *url.Values
|
||||
|
||||
params = &url.Values{"short_url": {strconv.FormatBool(shortURL)}}
|
||||
act := strings.Join([]string{"shares", db.RootDirectory, path}, "/")
|
||||
err := db.doRequest("POST", act, params, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// Media shares a file for streaming (direct access).
|
||||
func (db *Dropbox) Media(path string) (*Link, error) {
|
||||
var rv Link
|
||||
|
||||
act := strings.Join([]string{"media", db.RootDirectory, path}, "/")
|
||||
err := db.doRequest("POST", act, nil, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// Search searches the entries matching all the words contained in query in the given path.
|
||||
// The maximum number of entries and whether to consider deleted file may be given.
|
||||
func (db *Dropbox) Search(path, query string, fileLimit int, includeDeleted bool) ([]Entry, error) {
|
||||
var rv []Entry
|
||||
var params *url.Values
|
||||
|
||||
if fileLimit <= 0 || fileLimit > SearchLimitMax {
|
||||
fileLimit = SearchLimitDefault
|
||||
}
|
||||
params = &url.Values{
|
||||
"query": {query},
|
||||
"file_limit": {strconv.FormatInt(int64(fileLimit), 10)},
|
||||
"include_deleted": {strconv.FormatBool(includeDeleted)},
|
||||
}
|
||||
act := strings.Join([]string{"search", db.RootDirectory, path}, "/")
|
||||
err := db.doRequest("GET", act, params, &rv)
|
||||
return rv, err
|
||||
}
|
||||
|
||||
// Delta gets modifications since the cursor.
|
||||
func (db *Dropbox) Delta(cursor, pathPrefix string) (*DeltaPage, error) {
|
||||
var rv DeltaPage
|
||||
var params *url.Values
|
||||
type deltaPageParser struct {
|
||||
Reset bool `json:"reset"` // if true the local state must be cleared.
|
||||
HasMore bool `json:"has_more"` // if true an other call to delta should be made.
|
||||
Cursor // Tag of the current state.
|
||||
Entries [][]json.RawMessage `json:"entries"` // List of changed entries.
|
||||
}
|
||||
var dpp deltaPageParser
|
||||
|
||||
params = &url.Values{}
|
||||
if len(cursor) != 0 {
|
||||
params.Set("cursor", cursor)
|
||||
}
|
||||
if len(pathPrefix) != 0 {
|
||||
params.Set("path_prefix", pathPrefix)
|
||||
}
|
||||
err := db.doRequest("POST", "delta", params, &dpp)
|
||||
rv = DeltaPage{Reset: dpp.Reset, HasMore: dpp.HasMore, Cursor: dpp.Cursor}
|
||||
rv.Entries = make([]DeltaEntry, 0, len(dpp.Entries))
|
||||
for _, jentry := range dpp.Entries {
|
||||
var path string
|
||||
var entry Entry
|
||||
|
||||
if len(jentry) != 2 {
|
||||
return nil, fmt.Errorf("malformed reply")
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(jentry[0], &path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal(jentry[1], &entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entry.Path == "" {
|
||||
rv.Entries = append(rv.Entries, DeltaEntry{Path: path, Entry: nil})
|
||||
} else {
|
||||
rv.Entries = append(rv.Entries, DeltaEntry{Path: path, Entry: &entry})
|
||||
}
|
||||
}
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// LongPollDelta waits for a notification to happen.
|
||||
func (db *Dropbox) LongPollDelta(cursor string, timeout int) (*DeltaPoll, error) {
|
||||
var rv DeltaPoll
|
||||
var params *url.Values
|
||||
var body []byte
|
||||
var rawurl string
|
||||
var response *http.Response
|
||||
var err error
|
||||
var client http.Client
|
||||
|
||||
params = &url.Values{}
|
||||
if timeout != 0 {
|
||||
if timeout < PollMinTimeout || timeout > PollMaxTimeout {
|
||||
return nil, fmt.Errorf("timeout out of range [%d; %d]", PollMinTimeout, PollMaxTimeout)
|
||||
}
|
||||
params.Set("timeout", strconv.FormatInt(int64(timeout), 10))
|
||||
}
|
||||
params.Set("cursor", cursor)
|
||||
rawurl = fmt.Sprintf("%s/longpoll_delta?%s", db.APINotifyURL, params.Encode())
|
||||
if response, err = client.Get(rawurl); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if body, err = getResponse(response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(body, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// Metadata gets the metadata for a file or a directory.
|
||||
// If list is true and src is a directory, immediate child will be sent in the Contents field.
|
||||
// If include_deleted is true, entries deleted will be sent.
|
||||
// hash is the hash of the contents of a directory, it is used to avoid sending data when directory did not change.
|
||||
// rev is the specific revision to get the metadata from.
|
||||
// limit is the maximum number of entries requested.
|
||||
func (db *Dropbox) Metadata(src string, list bool, includeDeleted bool, hash, rev string, limit int) (*Entry, error) {
|
||||
var rv Entry
|
||||
var params *url.Values
|
||||
|
||||
if limit <= 0 {
|
||||
limit = MetadataLimitDefault
|
||||
} else if limit > MetadataLimitMax {
|
||||
limit = MetadataLimitMax
|
||||
}
|
||||
params = &url.Values{
|
||||
"list": {strconv.FormatBool(list)},
|
||||
"include_deleted": {strconv.FormatBool(includeDeleted)},
|
||||
"file_limit": {strconv.FormatInt(int64(limit), 10)},
|
||||
}
|
||||
if len(rev) != 0 {
|
||||
params.Set("rev", rev)
|
||||
}
|
||||
if len(hash) != 0 {
|
||||
params.Set("hash", hash)
|
||||
}
|
||||
|
||||
src = strings.Trim(src, "/")
|
||||
act := strings.Join([]string{"metadata", db.RootDirectory, src}, "/")
|
||||
err := db.doRequest("GET", act, params, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// CopyRef gets a reference to a file.
|
||||
// This reference can be used to copy this file to another user's Dropbox by passing it to the Copy method.
|
||||
func (db *Dropbox) CopyRef(src string) (*CopyRef, error) {
|
||||
var rv CopyRef
|
||||
act := strings.Join([]string{"copy_ref", db.RootDirectory, src}, "/")
|
||||
err := db.doRequest("GET", act, nil, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// Revisions gets the list of revisions for a file.
|
||||
func (db *Dropbox) Revisions(src string, revLimit int) ([]Entry, error) {
|
||||
var rv []Entry
|
||||
if revLimit <= 0 {
|
||||
revLimit = RevisionsLimitDefault
|
||||
} else if revLimit > RevisionsLimitMax {
|
||||
revLimit = RevisionsLimitMax
|
||||
}
|
||||
act := strings.Join([]string{"revisions", db.RootDirectory, src}, "/")
|
||||
err := db.doRequest("GET", act,
|
||||
&url.Values{"rev_limit": {strconv.FormatInt(int64(revLimit), 10)}}, &rv)
|
||||
return rv, err
|
||||
}
|
||||
|
||||
// Restore restores a deleted file at the corresponding revision.
|
||||
func (db *Dropbox) Restore(src string, rev string) (*Entry, error) {
|
||||
var rv Entry
|
||||
act := strings.Join([]string{"restore", db.RootDirectory, src}, "/")
|
||||
err := db.doRequest("POST", act, &url.Values{"rev": {rev}}, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// Copy copies a file.
|
||||
// If isRef is true src must be a reference from CopyRef instead of a path.
|
||||
func (db *Dropbox) Copy(src, dst string, isRef bool) (*Entry, error) {
|
||||
var rv Entry
|
||||
params := &url.Values{"root": {db.RootDirectory}, "to_path": {dst}}
|
||||
if isRef {
|
||||
params.Set("from_copy_ref", src)
|
||||
} else {
|
||||
params.Set("from_path", src)
|
||||
}
|
||||
err := db.doRequest("POST", "fileops/copy", params, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// CreateFolder creates a new directory.
|
||||
func (db *Dropbox) CreateFolder(path string) (*Entry, error) {
|
||||
var rv Entry
|
||||
err := db.doRequest("POST", "fileops/create_folder",
|
||||
&url.Values{"root": {db.RootDirectory}, "path": {path}}, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// Delete removes a file or directory (it is a recursive delete).
|
||||
func (db *Dropbox) Delete(path string) (*Entry, error) {
|
||||
var rv Entry
|
||||
err := db.doRequest("POST", "fileops/delete",
|
||||
&url.Values{"root": {db.RootDirectory}, "path": {path}}, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// Move moves a file or directory.
|
||||
func (db *Dropbox) Move(src, dst string) (*Entry, error) {
|
||||
var rv Entry
|
||||
err := db.doRequest("POST", "fileops/move",
|
||||
&url.Values{"root": {db.RootDirectory},
|
||||
"from_path": {src},
|
||||
"to_path": {dst}}, &rv)
|
||||
return &rv, err
|
||||
}
|
||||
|
||||
// LatestCursor returns the latest cursor without fetching any data.
|
||||
func (db *Dropbox) LatestCursor(prefix string, mediaInfo bool) (*Cursor, error) {
|
||||
var (
|
||||
params = &url.Values{}
|
||||
cur Cursor
|
||||
)
|
||||
|
||||
if prefix != "" {
|
||||
params.Set("path_prefix", prefix)
|
||||
}
|
||||
|
||||
if mediaInfo {
|
||||
params.Set("include_media_info", "true")
|
||||
}
|
||||
|
||||
err := db.doRequest("POST", "delta/latest_cursor", params, &cur)
|
||||
return &cur, err
|
||||
}
|
||||
|
||||
// SharedFolders returns the list of allowed shared folders.
|
||||
func (db *Dropbox) SharedFolders(sharedFolderID string) ([]SharedFolder, error) {
|
||||
var sharedFolders []SharedFolder
|
||||
var err error
|
||||
|
||||
if sharedFolderID != "" {
|
||||
sharedFolders = make([]SharedFolder, 1)
|
||||
err = db.doRequest("GET", "/shared_folders/"+sharedFolderID, nil, &sharedFolders[0])
|
||||
} else {
|
||||
err = db.doRequest("GET", "/shared_folders/", nil, &sharedFolders)
|
||||
}
|
||||
return sharedFolders, err
|
||||
}
|
786
vendor/github.com/stacktic/dropbox/dropbox_test.go
generated
vendored
786
vendor/github.com/stacktic/dropbox/dropbox_test.go
generated
vendored
@ -1,786 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014 Arnaud Ysmal. All Rights Reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package dropbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var dirEntry = Entry{Size: "0 bytes", Revision: "1f477dd351f", ThumbExists: false, Bytes: 0,
|
||||
Modified: DBTime(time.Date(2011, time.August, 10, 18, 21, 30, 0, time.UTC)),
|
||||
Path: "/testdir", IsDir: true, Icon: "folder", Root: "auto"}
|
||||
|
||||
var fileEntry = Entry{Size: "0 bytes", Revision: "1f33043551f", ThumbExists: false, Bytes: 0,
|
||||
Modified: DBTime(time.Date(2011, time.August, 10, 18, 21, 30, 0, time.UTC)),
|
||||
Path: "/testfile", IsDir: false, Icon: "page_white_text",
|
||||
Root: "auto", MimeType: "text/plain"}
|
||||
|
||||
type FakeHTTP struct {
|
||||
t *testing.T
|
||||
Method string
|
||||
Host string
|
||||
Path string
|
||||
Params map[string]string
|
||||
RequestData []byte
|
||||
ResponseData []byte
|
||||
}
|
||||
|
||||
func (f FakeHTTP) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||
if resp, err = f.checkRequest(req); err != nil {
|
||||
f.t.Errorf("%s", err)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (f FakeHTTP) checkRequest(r *http.Request) (*http.Response, error) {
|
||||
var va []string
|
||||
var ok bool
|
||||
|
||||
if r.Method != f.Method {
|
||||
return nil, fmt.Errorf("wrong method")
|
||||
}
|
||||
if r.URL.Scheme != "https" || r.URL.Host != f.Host || r.URL.Path != f.Path {
|
||||
return nil, fmt.Errorf("wrong URL %s://%s%s", r.URL.Scheme, r.URL.Host, r.URL.Path)
|
||||
}
|
||||
vals := r.URL.Query()
|
||||
if len(vals) != len(f.Params) {
|
||||
return nil, fmt.Errorf("wrong number of parameters got %d expected %d", len(vals), len(f.Params))
|
||||
}
|
||||
for k, v := range f.Params {
|
||||
if va, ok = vals[k]; !ok || len(va) != 1 {
|
||||
return nil, fmt.Errorf("wrong parameters %s", k)
|
||||
} else if va[0] != v {
|
||||
return nil, fmt.Errorf("wrong parameters %s expected %s received %s", k, v, va[0])
|
||||
}
|
||||
}
|
||||
if len(f.RequestData) != 0 {
|
||||
var buf []byte
|
||||
var err error
|
||||
|
||||
if buf, err = ioutil.ReadAll(r.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !bytes.Equal(buf, f.RequestData) {
|
||||
return nil, fmt.Errorf("wrong request body")
|
||||
}
|
||||
}
|
||||
|
||||
return &http.Response{Status: "200 OK", StatusCode: 200,
|
||||
Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1,
|
||||
ContentLength: int64(len(f.ResponseData)), Body: ioutil.NopCloser(bytes.NewReader(f.ResponseData))}, nil
|
||||
}
|
||||
|
||||
// Downloading a file
|
||||
func Example() {
|
||||
db := NewDropbox()
|
||||
db.SetAppInfo("application id", "application secret")
|
||||
db.SetAccessToken("your secret token for this application")
|
||||
db.DownloadToFile("file on Dropbox", "local destination", "revision of the file on Dropbox")
|
||||
}
|
||||
|
||||
func newDropbox(t *testing.T) *Dropbox {
|
||||
db := NewDropbox()
|
||||
db.SetAppInfo("dummyappkey", "dummyappsecret")
|
||||
db.SetAccessToken("dummyoauthtoken")
|
||||
return db
|
||||
}
|
||||
|
||||
func TestAccountInfo(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Account
|
||||
|
||||
db = newDropbox(t)
|
||||
|
||||
expected := Account{ReferralLink: "https://www.dropbox.com/referrals/r1a2n3d4m5s6t7", DisplayName: "John P. User", Country: "US", UID: 12345678}
|
||||
expected.QuotaInfo.Shared = 253738410565
|
||||
expected.QuotaInfo.Quota = 107374182400000
|
||||
expected.QuotaInfo.Normal = 680031877871
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test marshalling issue")
|
||||
}
|
||||
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: FakeHTTP{
|
||||
t: t,
|
||||
Method: "GET",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/account/info",
|
||||
Params: map[string]string{"locale": "en"},
|
||||
ResponseData: js,
|
||||
},
|
||||
}
|
||||
|
||||
if received, err = db.GetAccountInfo(); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Entry
|
||||
var from, to string
|
||||
var fake FakeHTTP
|
||||
|
||||
expected := fileEntry
|
||||
from = expected.Path[1:]
|
||||
to = from + ".1"
|
||||
expected.Path = to
|
||||
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test marshalling issue")
|
||||
}
|
||||
|
||||
fake = FakeHTTP{
|
||||
t: t,
|
||||
Method: "POST",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/fileops/copy",
|
||||
Params: map[string]string{
|
||||
"root": "auto",
|
||||
"from_path": from,
|
||||
"to_path": to,
|
||||
"locale": "en",
|
||||
},
|
||||
ResponseData: js,
|
||||
}
|
||||
db = newDropbox(t)
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: fake,
|
||||
}
|
||||
|
||||
if received, err = db.Copy(from, to, false); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
delete(fake.Params, "from_path")
|
||||
fake.Params["from_copy_ref"] = from
|
||||
if received, err = db.Copy(from, to, true); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyRef(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *CopyRef
|
||||
var filename string
|
||||
|
||||
filename = "dummyfile"
|
||||
db = newDropbox(t)
|
||||
|
||||
expected := CopyRef{CopyRef: "z1X6ATl6aWtzOGq0c3g5Ng", Expires: "Fri, 31 Jan 2042 21:01:05 +0000"}
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test due to marshalling issue")
|
||||
}
|
||||
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: FakeHTTP{
|
||||
Method: "GET",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/copy_ref/auto/" + filename,
|
||||
t: t,
|
||||
Params: map[string]string{"locale": "en"},
|
||||
ResponseData: js,
|
||||
},
|
||||
}
|
||||
if received, err = db.CopyRef(filename); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFolder(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Entry
|
||||
var foldername string
|
||||
|
||||
expected := dirEntry
|
||||
foldername = expected.Path[1:]
|
||||
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test due to marshalling issue")
|
||||
}
|
||||
|
||||
db = newDropbox(t)
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: FakeHTTP{
|
||||
Method: "POST",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/fileops/create_folder",
|
||||
Params: map[string]string{
|
||||
"root": "auto",
|
||||
"path": foldername,
|
||||
"locale": "en",
|
||||
},
|
||||
t: t,
|
||||
ResponseData: js,
|
||||
},
|
||||
}
|
||||
if received, err = db.CreateFolder(foldername); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Entry
|
||||
var path string
|
||||
|
||||
expected := dirEntry
|
||||
expected.IsDeleted = true
|
||||
path = expected.Path[1:]
|
||||
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test marshalling issue")
|
||||
}
|
||||
|
||||
db = newDropbox(t)
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: FakeHTTP{
|
||||
t: t,
|
||||
Method: "POST",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/fileops/delete",
|
||||
Params: map[string]string{
|
||||
"root": "auto",
|
||||
"path": path,
|
||||
"locale": "en",
|
||||
},
|
||||
ResponseData: js,
|
||||
},
|
||||
}
|
||||
if received, err = db.Delete(path); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilesPut(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Entry
|
||||
var filename string
|
||||
var content, js []byte
|
||||
var fake FakeHTTP
|
||||
|
||||
filename = "test.txt"
|
||||
content = []byte("file content")
|
||||
|
||||
expected := Entry{Size: strconv.FormatInt(int64(len(content)), 10), Revision: "35e97029684fe", ThumbExists: false, Bytes: int64(len(content)),
|
||||
Modified: DBTime(time.Date(2011, time.July, 19, 21, 55, 38, 0, time.UTC)), Path: "/" + filename, IsDir: false, Icon: "page_white_text",
|
||||
Root: "auto", MimeType: "text/plain"}
|
||||
|
||||
js, err = json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test marshalling issue")
|
||||
}
|
||||
|
||||
fake = FakeHTTP{
|
||||
t: t,
|
||||
Method: "PUT",
|
||||
Host: "api-content.dropbox.com",
|
||||
Path: "/1/files_put/auto/" + filename,
|
||||
Params: map[string]string{
|
||||
"locale": "en",
|
||||
"overwrite": "false",
|
||||
},
|
||||
ResponseData: js,
|
||||
RequestData: content,
|
||||
}
|
||||
|
||||
db = newDropbox(t)
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: fake,
|
||||
}
|
||||
|
||||
received, err = db.FilesPut(ioutil.NopCloser(bytes.NewBuffer(content)), int64(len(content)), filename, false, "")
|
||||
if err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["parent_rev"] = "12345"
|
||||
received, err = db.FilesPut(ioutil.NopCloser(bytes.NewBuffer(content)), int64(len(content)), filename, false, "12345")
|
||||
if err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["overwrite"] = "true"
|
||||
received, err = db.FilesPut(ioutil.NopCloser(bytes.NewBuffer(content)), int64(len(content)), filename, true, "12345")
|
||||
if err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
_, err = db.FilesPut(ioutil.NopCloser(bytes.NewBuffer(content)), int64(MaxPutFileSize+1), filename, true, "12345")
|
||||
if err == nil {
|
||||
t.Errorf("size > %d bytes must returns an error", MaxPutFileSize)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMedia(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Link
|
||||
var filename string
|
||||
|
||||
filename = "dummyfile"
|
||||
db = newDropbox(t)
|
||||
|
||||
expected := Link{Expires: DBTime(time.Date(2011, time.August, 10, 18, 21, 30, 0, time.UTC)), URL: "https://dl.dropboxusercontent.com/1/view/abcdefghijk/example"}
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test due to marshalling issue: %s", err)
|
||||
}
|
||||
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: FakeHTTP{
|
||||
Method: "POST",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/media/auto/" + filename,
|
||||
Params: map[string]string{"locale": "en"},
|
||||
t: t,
|
||||
ResponseData: js,
|
||||
},
|
||||
}
|
||||
if received, err = db.Media(filename); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetadata(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Entry
|
||||
var path string
|
||||
var fake FakeHTTP
|
||||
|
||||
expected := fileEntry
|
||||
path = expected.Path[1:]
|
||||
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test marshalling issue")
|
||||
}
|
||||
|
||||
fake = FakeHTTP{
|
||||
t: t,
|
||||
Method: "GET",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/metadata/auto/" + path,
|
||||
Params: map[string]string{
|
||||
"list": "false",
|
||||
"include_deleted": "false",
|
||||
"file_limit": "10",
|
||||
"locale": "en",
|
||||
},
|
||||
ResponseData: js,
|
||||
}
|
||||
db = newDropbox(t)
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: fake,
|
||||
}
|
||||
|
||||
if received, err = db.Metadata(path, false, false, "", "", 10); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["list"] = "true"
|
||||
if received, err = db.Metadata(path, true, false, "", "", 10); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["include_deleted"] = "true"
|
||||
if received, err = db.Metadata(path, true, true, "", "", 10); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["file_limit"] = "20"
|
||||
if received, err = db.Metadata(path, true, true, "", "", 20); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["rev"] = "12345"
|
||||
if received, err = db.Metadata(path, true, true, "", "12345", 20); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["hash"] = "6789"
|
||||
if received, err = db.Metadata(path, true, true, "6789", "12345", 20); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["file_limit"] = "10000"
|
||||
if received, err = db.Metadata(path, true, true, "6789", "12345", 0); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["file_limit"] = strconv.FormatInt(int64(MetadataLimitMax), 10)
|
||||
if received, err = db.Metadata(path, true, true, "6789", "12345", MetadataLimitMax+1); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMove(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Entry
|
||||
var from, to string
|
||||
|
||||
expected := fileEntry
|
||||
from = expected.Path[1:]
|
||||
to = from + ".1"
|
||||
expected.Path = to
|
||||
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test marshalling issue")
|
||||
}
|
||||
|
||||
db = newDropbox(t)
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: FakeHTTP{
|
||||
t: t,
|
||||
Method: "POST",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/fileops/move",
|
||||
Params: map[string]string{
|
||||
"root": "auto",
|
||||
"from_path": from,
|
||||
"to_path": to,
|
||||
"locale": "en",
|
||||
},
|
||||
ResponseData: js,
|
||||
},
|
||||
}
|
||||
if received, err = db.Move(from, to); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRestore(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Entry
|
||||
var path string
|
||||
|
||||
expected := fileEntry
|
||||
path = expected.Path[1:]
|
||||
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test marshalling issue")
|
||||
}
|
||||
|
||||
db = newDropbox(t)
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: FakeHTTP{
|
||||
t: t,
|
||||
Method: "POST",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/restore/auto/" + path,
|
||||
Params: map[string]string{
|
||||
"rev": expected.Revision,
|
||||
"locale": "en",
|
||||
},
|
||||
ResponseData: js,
|
||||
},
|
||||
}
|
||||
if received, err = db.Restore(path, expected.Revision); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevisions(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received []Entry
|
||||
var path string
|
||||
var fake FakeHTTP
|
||||
|
||||
expected := []Entry{fileEntry}
|
||||
path = expected[0].Path[1:]
|
||||
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test marshalling issue")
|
||||
}
|
||||
|
||||
fake = FakeHTTP{
|
||||
t: t,
|
||||
Method: "GET",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/revisions/auto/" + path,
|
||||
Params: map[string]string{
|
||||
"rev_limit": "10",
|
||||
"locale": "en",
|
||||
},
|
||||
ResponseData: js,
|
||||
}
|
||||
db = newDropbox(t)
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: fake,
|
||||
}
|
||||
|
||||
if received, err = db.Revisions(path, 10); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, received) {
|
||||
t.Errorf("got %#v expected %#v", received, expected)
|
||||
}
|
||||
|
||||
fake.Params["rev_limit"] = strconv.FormatInt(int64(RevisionsLimitDefault), 10)
|
||||
if received, err = db.Revisions(path, 0); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, received) {
|
||||
t.Errorf("got %#v expected %#v", received, expected)
|
||||
}
|
||||
|
||||
fake.Params["rev_limit"] = strconv.FormatInt(int64(RevisionsLimitMax), 10)
|
||||
if received, err = db.Revisions(path, RevisionsLimitMax+1); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, received) {
|
||||
t.Errorf("got %#v expected %#v", received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearch(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received []Entry
|
||||
var dirname string
|
||||
|
||||
dirname = "dummy"
|
||||
db = newDropbox(t)
|
||||
|
||||
expected := []Entry{Entry{Size: "0 bytes", Revision: "35c1f029684fe", ThumbExists: false, Bytes: 0,
|
||||
Modified: DBTime(time.Date(2011, time.August, 10, 18, 21, 30, 0, time.UTC)), Path: "/" + dirname + "/dummyfile", IsDir: false, Icon: "page_white_text",
|
||||
Root: "auto", MimeType: "text/plain"}}
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test due to marshalling issue")
|
||||
}
|
||||
|
||||
fake := FakeHTTP{
|
||||
Method: "GET",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/search/auto/" + dirname,
|
||||
t: t,
|
||||
Params: map[string]string{
|
||||
"locale": "en",
|
||||
"query": "foo bar",
|
||||
"file_limit": "10",
|
||||
"include_deleted": "false",
|
||||
},
|
||||
ResponseData: js,
|
||||
}
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: fake,
|
||||
}
|
||||
|
||||
if received, err = db.Search(dirname, "foo bar", 10, false); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, received) {
|
||||
t.Errorf("got %#v expected %#v", received, expected)
|
||||
}
|
||||
|
||||
fake.Params["include_deleted"] = "true"
|
||||
if received, err = db.Search(dirname, "foo bar", 10, true); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, received) {
|
||||
t.Errorf("got %#v expected %#v", received, expected)
|
||||
}
|
||||
|
||||
fake.Params["file_limit"] = strconv.FormatInt(int64(SearchLimitDefault), 10)
|
||||
if received, err = db.Search(dirname, "foo bar", 0, true); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, received) {
|
||||
t.Errorf("got %#v expected %#v", received, expected)
|
||||
}
|
||||
|
||||
if received, err = db.Search(dirname, "foo bar", SearchLimitMax+1, true); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, received) {
|
||||
t.Errorf("got %#v expected %#v", received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShares(t *testing.T) {
|
||||
var err error
|
||||
var db *Dropbox
|
||||
var received *Link
|
||||
var filename string
|
||||
|
||||
filename = "dummyfile"
|
||||
db = newDropbox(t)
|
||||
|
||||
expected := Link{Expires: DBTime(time.Date(2011, time.August, 10, 18, 21, 30, 0, time.UTC)), URL: "https://db.tt/c0mFuu1Y"}
|
||||
js, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("could not run test due to marshalling issue")
|
||||
}
|
||||
fake := FakeHTTP{
|
||||
Method: "POST",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/shares/auto/" + filename,
|
||||
Params: map[string]string{
|
||||
"locale": "en",
|
||||
"short_url": "false",
|
||||
},
|
||||
t: t,
|
||||
ResponseData: js,
|
||||
}
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: fake,
|
||||
}
|
||||
|
||||
if received, err = db.Shares(filename, false); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
|
||||
fake.Params["short_url"] = "true"
|
||||
if received, err = db.Shares(filename, true); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLatestCursor(t *testing.T) {
|
||||
tab := []struct {
|
||||
prefix string
|
||||
mediaInfo bool
|
||||
}{
|
||||
{
|
||||
prefix: "",
|
||||
mediaInfo: false,
|
||||
},
|
||||
{
|
||||
prefix: "/some",
|
||||
mediaInfo: false,
|
||||
},
|
||||
{
|
||||
prefix: "",
|
||||
mediaInfo: true,
|
||||
},
|
||||
{
|
||||
prefix: "/some",
|
||||
mediaInfo: true,
|
||||
},
|
||||
}
|
||||
|
||||
expected := Cursor{Cursor: "some"}
|
||||
cur, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to JSON encode Cursor")
|
||||
}
|
||||
|
||||
for _, testCase := range tab {
|
||||
db := newDropbox(t)
|
||||
fake := FakeHTTP{
|
||||
Method: "POST",
|
||||
Host: "api.dropbox.com",
|
||||
Path: "/1/delta/latest_cursor",
|
||||
t: t,
|
||||
Params: map[string]string{
|
||||
"locale": "en",
|
||||
},
|
||||
ResponseData: cur,
|
||||
}
|
||||
|
||||
if testCase.prefix != "" {
|
||||
fake.Params["path_prefix"] = testCase.prefix
|
||||
}
|
||||
|
||||
if testCase.mediaInfo {
|
||||
fake.Params["include_media_info"] = "true"
|
||||
}
|
||||
|
||||
http.DefaultClient = &http.Client{
|
||||
Transport: fake,
|
||||
}
|
||||
|
||||
if received, err := db.LatestCursor(testCase.prefix, testCase.mediaInfo); err != nil {
|
||||
t.Errorf("API error: %s", err)
|
||||
} else if !reflect.DeepEqual(expected, *received) {
|
||||
t.Errorf("got %#v expected %#v", *received, expected)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user