From 27f0846b45a9f01c0e4af4c10fb4933fb678668f Mon Sep 17 00:00:00 2001 From: Adphi Date: Thu, 3 Jan 2019 14:09:23 +0100 Subject: [PATCH] implemented User's CreateBatchWithoutPassoword --- client.go | 7 +++++++ gonextcloud_test.go | 36 ++++++++++++++++++++++++++++++++++++ types/errors.go | 4 +--- types/interfaces.go | 9 +++++---- types/responses.go | 6 +++--- types/user.go | 32 ++++++++++++++++++++++---------- users.go | 39 +++++++++++++++++++++++++++++++++++---- 7 files changed, 109 insertions(+), 24 deletions(-) diff --git a/client.go b/client.go index 7f77457..79bcfe9 100644 --- a/client.go +++ b/client.go @@ -52,30 +52,37 @@ func NewClient(hostname string) (*Client, error) { return c, nil } +//Apps return the Apps client Interface func (c *Client) Apps() types.Apps { return c.apps } +//AppsConfig return the AppsConfig client Interface func (c *Client) AppsConfig() types.AppsConfig { return c.appsConfig } +//GroupFolders return the GroupFolders client Interface func (c *Client) GroupFolders() types.GroupFolders { return c.groupFolders } +//Notifications return the Notifications client Interface func (c *Client) Notifications() types.Notifications { return c.notifications } +//Shares return the Shares client Interface func (c *Client) Shares() types.Shares { return c.shares } +//Users return the Users client Interface func (c *Client) Users() types.Users { return c.users } +//Groups return the Groups client Interface func (c *Client) Groups() types.Groups { return c.groups } diff --git a/gonextcloud_test.go b/gonextcloud_test.go index 37d04f8..6b6ae5c 100644 --- a/gonextcloud_test.go +++ b/gonextcloud_test.go @@ -12,6 +12,7 @@ import ( "os" "strconv" "strings" + "sync" "testing" "time" ) @@ -488,6 +489,41 @@ func TestUserCreateWithoutPassword(t *testing.T) { assert.NoError(t, err) } +func TestUserCreateBatchWithoutPassword(t *testing.T) { + c = nil + if err := initClient(); err != nil { + t.Fatal(err) + } + if c.version.Major < 14 { + t.SkipNow() + } + var us []types.User + for i := 0; i < 5; i++ { + u := fmt.Sprintf(config.NotExistingUser+"_%d", i) + us = append(us, types.User{ + Username: u, + DisplayName: strings.Title(u), + Groups: []string{"admin"}, + Email: config.Email, + Language: "fr", + Quota: "100024", + }) + } + err := c.Users().CreateBatchWithoutPassword(us) + assert.NoError(t, err) + + // Cleaning + var wg sync.WaitGroup + for _, u := range us { + wg.Add(1) + go func(n string) { + defer wg.Done() + c.Users().Delete(n) + }(u.Username) + } + wg.Wait() +} + func TestUserListDetails(t *testing.T) { c = nil if err := initClient(); err != nil { diff --git a/types/errors.go b/types/errors.go index 6677176..044e0f6 100644 --- a/types/errors.go +++ b/types/errors.go @@ -45,16 +45,14 @@ func (e *UserUpdateError) Error() string { //NewUpdateError returns an UpdateError based on an UpdateError channel func NewUpdateError(errors chan UpdateError) *UserUpdateError { - empty := true var ue UserUpdateError for e := range errors { if ue.Errors == nil { - empty = false ue.Errors = map[string]error{e.Field: e.Error} } ue.Errors[e.Field] = e.Error } - if !empty { + if len(ue.Errors) > 0 { return &ue } return nil diff --git a/types/interfaces.go b/types/interfaces.go index 3d717d9..749bd5c 100644 --- a/types/interfaces.go +++ b/types/interfaces.go @@ -95,16 +95,17 @@ type Shares interface { //Users available methods type Users interface { List() ([]string, error) - ListDetails() (map[string]User, error) - Get(name string) (*User, error) + ListDetails() (map[string]UserDetails, error) + Get(name string) (*UserDetails, error) Search(search string) ([]string, error) - Create(username string, password string, user *User) error + Create(username string, password string, user *UserDetails) error CreateWithoutPassword(username, email, displayName, quota, language string, groups ...string) error + CreateBatchWithoutPassword(users []User) error Delete(name string) error Enable(name string) error Disable(name string) error SendWelcomeEmail(name string) error - Update(user *User) error + Update(user *UserDetails) error UpdateEmail(name string, email string) error UpdateDisplayName(name string, displayName string) error UpdatePhone(name string, phone string) error diff --git a/types/responses.go b/types/responses.go index 98dea48..e7487e5 100644 --- a/types/responses.go +++ b/types/responses.go @@ -31,7 +31,7 @@ type UserListDetailsResponse struct { Ocs struct { Meta Meta `json:"meta"` Data struct { - Users map[string]User `json:"users"` + Users map[string]UserDetails `json:"users"` } `json:"data"` } `json:"ocs"` } @@ -39,8 +39,8 @@ type UserListDetailsResponse struct { //UserResponse type UserResponse struct { Ocs struct { - Meta Meta `json:"meta"` - Data User `json:"data"` + Meta Meta `json:"meta"` + Data UserDetails `json:"data"` } `json:"ocs"` } diff --git a/types/user.go b/types/user.go index b443f95..b619ede 100644 --- a/types/user.go +++ b/types/user.go @@ -1,16 +1,20 @@ package types -//Users +//User encapsulate the data needed to create a new Nextcloud's User type User struct { - Enabled bool `json:"enabled"` - ID string `json:"id"` - Quota struct { - Free int64 `json:"free"` - Used int `json:"used"` - Total int64 `json:"total"` - Relative float64 `json:"relative"` - Quota int `json:"quota"` - } `json:"quota"` + Username string + Email string + DisplayName string + Quota string + Language string + Groups []string +} + +//UserDetails is the raw Nextcloud User response +type UserDetails struct { + Enabled bool `json:"enabled"` + ID string `json:"id"` + Quota Quota `json:"quota"` Email string `json:"email"` Displayname string `json:"displayname"` Phone string `json:"phone"` @@ -26,3 +30,11 @@ type User struct { Subadmin []interface{} `json:"subadmin,omitempty"` Locale string `json:"locale,omitempty"` } + +type Quota struct { + Free int64 `json:"free"` + Used int `json:"used"` + Total int64 `json:"total"` + Relative float64 `json:"relative"` + Quota int `json:"quota"` +} diff --git a/users.go b/users.go index 5b1533d..804f563 100644 --- a/users.go +++ b/users.go @@ -5,6 +5,7 @@ import ( "github.com/fatih/structs" req "github.com/levigross/grequests" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "gitlab.bertha.cloud/partitio/Nextcloud-Partitio/gonextcloud/types" "net/http" "net/url" @@ -32,7 +33,7 @@ func (u *Users) List() ([]string, error) { } //ListDetails return a map of user with details -func (u *Users) ListDetails() (map[string]types.User, error) { +func (u *Users) ListDetails() (map[string]types.UserDetails, error) { res, err := u.c.baseRequest(http.MethodGet, routes.users, nil, "details") //res, err := c.session.Get(u.String(), nil) if err != nil { @@ -44,7 +45,7 @@ func (u *Users) ListDetails() (map[string]types.User, error) { } // Get return the details about the specified user -func (u *Users) Get(name string) (*types.User, error) { +func (u *Users) Get(name string) (*types.UserDetails, error) { if name == "" { return nil, &types.APIError{Message: "name cannot be empty"} } @@ -77,7 +78,7 @@ func (u *Users) Search(search string) ([]string, error) { } // Create create a new user -func (u *Users) Create(username string, password string, user *types.User) error { +func (u *Users) Create(username string, password string, user *types.UserDetails) error { // Create base Users ro := &req.RequestOptions{ Data: map[string]string{ @@ -132,6 +133,36 @@ func (u *Users) CreateWithoutPassword(username, email, displayName, quota, langu return nil } +//CreateBatchWithoutPassword create multiple users and send them the init password email +func (u *Users) CreateBatchWithoutPassword(users []types.User) error { + var wg sync.WaitGroup + errs := make(chan error) + for _, us := range users { + wg.Add(1) + go func(user types.User) { + logrus.Debugf("creating user %s", user.Username) + defer wg.Done() + if err := u.CreateWithoutPassword( + user.Username, user.Email, user.DisplayName, "", "", user.Groups..., + ); err != nil { + errs <- err + } + }(us) + } + go func() { + wg.Wait() + close(errs) + }() + var es []error + for err := range errs { + es = append(es, err) + } + if len(es) > 0 { + return errors.Errorf("errors occurred while creating users: %v", es) + } + return nil +} + //Delete delete the user func (u *Users) Delete(name string) error { return u.baseRequest(http.MethodDelete, nil, name) @@ -159,7 +190,7 @@ func (u *Users) SendWelcomeEmail(name string) error { } //Update takes a *types.Users struct to update the user's information -func (u *Users) Update(user *types.User) error { +func (u *Users) Update(user *types.UserDetails) error { m := structs.Map(user) errs := make(chan types.UpdateError) var wg sync.WaitGroup