#1 OCS Shares API

This commit is contained in:
Philippe-Adrien Nousse 2018-08-08 16:04:06 +02:00
parent e03fd9fd88
commit 3c45f09874
9 changed files with 248 additions and 20 deletions

View File

@ -2,9 +2,6 @@ url: https://my.nextcloud.com
login: admin login: admin
password: mypassword password: mypassword
app-name: testapp app-name: testapp
groups-to-create: share-folder: /Documents
- grp1
- grp2
- grp3
not-existing-user: this-user-should-not-exist not-existing-user: this-user-should-not-exist
not-existing-group: this-group-should-not-exist not-existing-group: this-group-should-not-exist

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4"> <module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

View File

@ -24,7 +24,7 @@ type Config struct {
Login string `yaml:"login"` Login string `yaml:"login"`
Password string `yaml:"password"` Password string `yaml:"password"`
AppName string `yaml:"app-name"` AppName string `yaml:"app-name"`
GroupsToCreate []string `yaml:"groups-to-create"` ShareFolder string `yaml:"share-folder"`
NotExistingUser string `yaml:"not-existing-user"` NotExistingUser string `yaml:"not-existing-user"`
NotExistingGroup string `yaml:"not-existing-group"` NotExistingGroup string `yaml:"not-existing-group"`
} }
@ -307,9 +307,19 @@ func TestUserDelete(t *testing.T) {
func TestInvalidBaseRequest(t *testing.T) { func TestInvalidBaseRequest(t *testing.T) {
c.baseURL = &url.URL{} c.baseURL = &url.URL{}
_, err := c.baseRequest(routes.capabilities, "admin", "invalid", nil, http.MethodGet) _, err := c.baseRequest(routes.capabilities, "admin", "invalid", nil, http.MethodGet)
c = nil
assert.Error(t, err) assert.Error(t, err)
} }
func TestShareList(t *testing.T) {
if err := initClient(); err != nil {
return
}
s, err := c.SharesList()
assert.Nil(t, err)
assert.NotNil(t, s)
}
func TestLogout(t *testing.T) { func TestLogout(t *testing.T) {
err := c.Logout() err := c.Logout()
assert.Nil(t, err) assert.Nil(t, err)

View File

@ -9,17 +9,19 @@ type Routes struct {
groups *url.URL groups *url.URL
apps *url.URL apps *url.URL
monitor *url.URL monitor *url.URL
shares *url.URL
} }
const badRequest = 998 const badRequest = 998
var ( var (
apiPath = &url.URL{Path: "/ocs/v1.php"} apiPath = &url.URL{Path: "/ocs/v2.php"}
routes = Routes{ routes = Routes{
capabilities: &url.URL{Path: apiPath.Path + "/cloud/capabilities"}, capabilities: &url.URL{Path: apiPath.Path + "/cloud/capabilities"},
users: &url.URL{Path: apiPath.Path + "/cloud/users"}, users: &url.URL{Path: apiPath.Path + "/cloud/users"},
groups: &url.URL{Path: apiPath.Path + "/cloud/groups"}, groups: &url.URL{Path: apiPath.Path + "/cloud/groups"},
apps: &url.URL{Path: apiPath.Path + "/cloud/apps"}, apps: &url.URL{Path: apiPath.Path + "/cloud/apps"},
monitor: &url.URL{Path: apiPath.Path + "/apps/serverinfo/api/v1/info"}, monitor: &url.URL{Path: apiPath.Path + "/apps/serverinfo/api/v1/info"},
shares: &url.URL{Path: apiPath.Path + "/apps/files_sharing/api/v1/shares"},
} }
) )

156
shares.go Normal file
View File

@ -0,0 +1,156 @@
package gonextcloud
import (
"fmt"
req "github.com/levigross/grequests"
"github.com/partitio/gonextcloud/types"
"net/http"
"strconv"
"sync"
)
func (c *Client) SharesList() ([]types.Share, error) {
res, err := c.baseRequest(routes.shares, "", "", nil, http.MethodGet)
if err != nil {
return nil, err
}
var r types.SharesListResponse
res.JSON(&r)
return r.Ocs.Data, nil
}
func (c *Client) Shares(path string, reshares bool, subfiles bool) ([]types.Share, error) {
ro := &req.RequestOptions{
Params: map[string]string{
"path": path,
"reshares": strconv.FormatBool(reshares),
"subfiles": strconv.FormatBool(subfiles),
},
}
res, err := c.baseRequest(routes.shares, "", "", ro, http.MethodGet)
if err != nil {
return nil, err
}
var r types.SharesListResponse
res.JSON(&r)
return r.Ocs.Data, nil
}
func (c *Client) Share(shareID string) (types.Share, error) {
res, err := c.baseRequest(routes.shares, shareID, "", nil, http.MethodGet)
if err != nil {
return types.Share{}, err
}
var r types.SharesListResponse
res.JSON(&r)
return r.Ocs.Data[0], nil
}
func (c *Client) ShareCreate(
path string,
shareType types.ShareType,
permission types.SharePermission,
shareWith string,
publicUpload bool,
password string,
) (types.Share, error) {
if (shareType == types.UserShare || shareType == types.GroupShare) && shareWith == "" {
return types.Share{}, fmt.Errorf("shareWith cannot be empty for ShareType UserShare or GroupShare")
}
ro := &req.RequestOptions{
Data: map[string]string{
"path": path,
"shareType": strconv.Itoa(int(shareType)),
"shareWith": shareWith,
"publicUpload": strconv.FormatBool(publicUpload),
"password": password,
"permissions": strconv.Itoa(int(permission)),
},
}
res, err := c.baseRequest(routes.shares, "", "", ro, http.MethodPost)
if err != nil {
return types.Share{}, err
}
var r types.SharesResponse
res.JSON(&r)
return r.Ocs.Data, nil
}
func (c *Client) ShareDelete(shareID int) error {
_, err := c.baseRequest(routes.shares, strconv.Itoa(shareID), "", nil, http.MethodDelete)
return err
}
// expireDate expireDate expects a well formatted date string, e.g. YYYY-MM-DD
func (c *Client) ShareUpdate(shareUpdate types.ShareUpdate) error {
errs := make(chan types.UpdateError)
var wg sync.WaitGroup
wg.Add(4)
go func() {
defer wg.Done()
if err := c.ShareUpdatePassword(shareUpdate.ShareID, shareUpdate.Password); err != nil {
errs <- types.UpdateError{
Field: "password",
Error: err,
}
}
}()
go func() {
defer wg.Done()
if err := c.ShareUpdateExpireDate(shareUpdate.ShareID, shareUpdate.ExpireDate); err != nil {
errs <- types.UpdateError{
Field: "expireDate",
Error: err,
}
}
}()
go func() {
defer wg.Done()
if err := c.ShareUpdatePermissions(shareUpdate.ShareID, shareUpdate.Permissions); err != nil {
errs <- types.UpdateError{
Field: "permissions",
Error: err,
}
}
}()
go func() {
defer wg.Done()
if err := c.ShareUpdatePublicUpload(shareUpdate.ShareID, shareUpdate.PublicUpload); err != nil {
errs <- types.UpdateError{
Field: "publicUpload",
Error: err,
}
}
}()
go func() {
wg.Wait()
close(errs)
}()
return types.NewUpdateError(errs)
}
// expireDate expects a well formatted date string, e.g. YYYY-MM-DD
func (c *Client) ShareUpdateExpireDate(shareID int, expireDate string) error {
return c.baseShareUpdate(strconv.Itoa(shareID), "expireDate", expireDate)
}
func (c *Client) ShareUpdatePublicUpload(shareID int, public bool) error {
return c.baseShareUpdate(strconv.Itoa(shareID), "publicUpload", strconv.FormatBool(public))
}
func (c *Client) ShareUpdatePassword(shareID int, password string) error {
return c.baseShareUpdate(strconv.Itoa(shareID), "password", password)
}
func (c *Client) ShareUpdatePermissions(shareID int, permissions types.SharePermission) error {
return c.baseShareUpdate(strconv.Itoa(shareID), "permissions", strconv.Itoa(int(permissions)))
}
func (c *Client) baseShareUpdate(shareID string, key string, value string) error {
ro := &req.RequestOptions{
Data: map[string]string{key: value},
}
_, err := c.baseRequest(routes.shares, shareID, "", ro, http.MethodPut)
return err
}

View File

@ -38,7 +38,7 @@ type UserUpdateError struct {
func (e *UserUpdateError) Error() string { func (e *UserUpdateError) Error() string {
var errors []string var errors []string
for k, e := range e.Errors { for k, e := range e.Errors {
errors = append(errors, fmt.Sprintf("%s: %s", k, e.Error())) errors = append(errors, fmt.Sprintf("%s: %v", k, e))
} }
return strings.Join(errors, ",") return strings.Join(errors, ",")
} }

View File

@ -90,11 +90,21 @@ type CapabilitiesResponse struct {
type MonitoringResponse struct { type MonitoringResponse struct {
Ocs struct { Ocs struct {
Meta struct { Meta Meta `json:"meta"`
Status string `json:"status"`
Statuscode int `json:"statuscode"`
Message string `json:"message"`
} `json:"meta"`
Data Monitoring `json:"data"` Data Monitoring `json:"data"`
} `json:"ocs"` } `json:"ocs"`
} }
type SharesListResponse struct {
Ocs struct {
Meta Meta `json:"meta"`
Data []Share `json:"data"`
} `json:"ocs"`
}
type SharesResponse struct {
Ocs struct {
Meta Meta `json:"meta"`
Data Share `json:"data"`
} `json:"ocs"`
}

53
types/shares.go Normal file
View File

@ -0,0 +1,53 @@
package types
type ShareType int
type SharePermission int
const (
UserShare ShareType = 0
GroupShare ShareType = 1
PublicLinkShare ShareType = 3
FederatedCloudShare ShareType = 6
ReadPermission SharePermission = 1
UpdatePermission SharePermission = 2
CreatePermission SharePermission = 4
DeletePermission SharePermission = 8
ReSharePermission SharePermission = 16
AllPermissions SharePermission = 31
)
type ShareUpdate struct {
ShareID int
Permissions SharePermission
Password string
PublicUpload bool
ExpireDate string
}
type Share struct {
ID string `json:"id"`
ShareType int `json:"share_type"`
UIDOwner string `json:"uid_owner"`
DisplaynameOwner string `json:"displayname_owner"`
Permissions int `json:"permissions"`
Stime int `json:"stime"`
Parent interface{} `json:"parent"`
Expiration string `json:"expiration"`
Token string `json:"token"`
UIDFileOwner string `json:"uid_file_owner"`
DisplaynameFileOwner string `json:"displayname_file_owner"`
Path string `json:"path"`
ItemType string `json:"item_type"`
Mimetype string `json:"mimetype"`
StorageID string `json:"storage_id"`
Storage int `json:"storage"`
ItemSource int `json:"item_source"`
FileSource int `json:"file_source"`
FileParent int `json:"file_parent"`
FileTarget string `json:"file_target"`
ShareWith string `json:"share_with"`
ShareWithDisplayname string `json:"share_with_displayname"`
MailSend int `json:"mail_send"`
Tags []string `json:"tags"`
}

View File

@ -41,7 +41,7 @@ func (c *Client) baseRequest(route *url.URL, name string, subroute string, ro *r
js := res.String() js := res.String()
var r types.BaseResponse var r types.BaseResponse
json.Unmarshal([]byte(js), &r) json.Unmarshal([]byte(js), &r)
if r.Ocs.Meta.Statuscode != 100 { if r.Ocs.Meta.Statuscode != 200 {
err := types.ErrorFromMeta(r.Ocs.Meta) err := types.ErrorFromMeta(r.Ocs.Meta)
return nil, err return nil, err
} }