implemented User's CreateBatchWithoutPassoword

This commit is contained in:
Adphi 2019-01-03 14:09:23 +01:00
parent fc966d8703
commit 27f0846b45
7 changed files with 109 additions and 24 deletions

View File

@ -52,30 +52,37 @@ func NewClient(hostname string) (*Client, error) {
return c, nil return c, nil
} }
//Apps return the Apps client Interface
func (c *Client) Apps() types.Apps { func (c *Client) Apps() types.Apps {
return c.apps return c.apps
} }
//AppsConfig return the AppsConfig client Interface
func (c *Client) AppsConfig() types.AppsConfig { func (c *Client) AppsConfig() types.AppsConfig {
return c.appsConfig return c.appsConfig
} }
//GroupFolders return the GroupFolders client Interface
func (c *Client) GroupFolders() types.GroupFolders { func (c *Client) GroupFolders() types.GroupFolders {
return c.groupFolders return c.groupFolders
} }
//Notifications return the Notifications client Interface
func (c *Client) Notifications() types.Notifications { func (c *Client) Notifications() types.Notifications {
return c.notifications return c.notifications
} }
//Shares return the Shares client Interface
func (c *Client) Shares() types.Shares { func (c *Client) Shares() types.Shares {
return c.shares return c.shares
} }
//Users return the Users client Interface
func (c *Client) Users() types.Users { func (c *Client) Users() types.Users {
return c.users return c.users
} }
//Groups return the Groups client Interface
func (c *Client) Groups() types.Groups { func (c *Client) Groups() types.Groups {
return c.groups return c.groups
} }

View File

@ -12,6 +12,7 @@ import (
"os" "os"
"strconv" "strconv"
"strings" "strings"
"sync"
"testing" "testing"
"time" "time"
) )
@ -488,6 +489,41 @@ func TestUserCreateWithoutPassword(t *testing.T) {
assert.NoError(t, err) 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) { func TestUserListDetails(t *testing.T) {
c = nil c = nil
if err := initClient(); err != nil { if err := initClient(); err != nil {

View File

@ -45,16 +45,14 @@ func (e *UserUpdateError) Error() string {
//NewUpdateError returns an UpdateError based on an UpdateError channel //NewUpdateError returns an UpdateError based on an UpdateError channel
func NewUpdateError(errors chan UpdateError) *UserUpdateError { func NewUpdateError(errors chan UpdateError) *UserUpdateError {
empty := true
var ue UserUpdateError var ue UserUpdateError
for e := range errors { for e := range errors {
if ue.Errors == nil { if ue.Errors == nil {
empty = false
ue.Errors = map[string]error{e.Field: e.Error} ue.Errors = map[string]error{e.Field: e.Error}
} }
ue.Errors[e.Field] = e.Error ue.Errors[e.Field] = e.Error
} }
if !empty { if len(ue.Errors) > 0 {
return &ue return &ue
} }
return nil return nil

View File

@ -95,16 +95,17 @@ type Shares interface {
//Users available methods //Users available methods
type Users interface { type Users interface {
List() ([]string, error) List() ([]string, error)
ListDetails() (map[string]User, error) ListDetails() (map[string]UserDetails, error)
Get(name string) (*User, error) Get(name string) (*UserDetails, error)
Search(search string) ([]string, 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 CreateWithoutPassword(username, email, displayName, quota, language string, groups ...string) error
CreateBatchWithoutPassword(users []User) error
Delete(name string) error Delete(name string) error
Enable(name string) error Enable(name string) error
Disable(name string) error Disable(name string) error
SendWelcomeEmail(name string) error SendWelcomeEmail(name string) error
Update(user *User) error Update(user *UserDetails) error
UpdateEmail(name string, email string) error UpdateEmail(name string, email string) error
UpdateDisplayName(name string, displayName string) error UpdateDisplayName(name string, displayName string) error
UpdatePhone(name string, phone string) error UpdatePhone(name string, phone string) error

View File

@ -31,7 +31,7 @@ type UserListDetailsResponse struct {
Ocs struct { Ocs struct {
Meta Meta `json:"meta"` Meta Meta `json:"meta"`
Data struct { Data struct {
Users map[string]User `json:"users"` Users map[string]UserDetails `json:"users"`
} `json:"data"` } `json:"data"`
} `json:"ocs"` } `json:"ocs"`
} }
@ -39,8 +39,8 @@ type UserListDetailsResponse struct {
//UserResponse //UserResponse
type UserResponse struct { type UserResponse struct {
Ocs struct { Ocs struct {
Meta Meta `json:"meta"` Meta Meta `json:"meta"`
Data User `json:"data"` Data UserDetails `json:"data"`
} `json:"ocs"` } `json:"ocs"`
} }

View File

@ -1,16 +1,20 @@
package types package types
//Users //User encapsulate the data needed to create a new Nextcloud's User
type User struct { type User struct {
Enabled bool `json:"enabled"` Username string
ID string `json:"id"` Email string
Quota struct { DisplayName string
Free int64 `json:"free"` Quota string
Used int `json:"used"` Language string
Total int64 `json:"total"` Groups []string
Relative float64 `json:"relative"` }
Quota int `json:"quota"`
} `json:"quota"` //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"` Email string `json:"email"`
Displayname string `json:"displayname"` Displayname string `json:"displayname"`
Phone string `json:"phone"` Phone string `json:"phone"`
@ -26,3 +30,11 @@ type User struct {
Subadmin []interface{} `json:"subadmin,omitempty"` Subadmin []interface{} `json:"subadmin,omitempty"`
Locale string `json:"locale,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"`
}

View File

@ -5,6 +5,7 @@ import (
"github.com/fatih/structs" "github.com/fatih/structs"
req "github.com/levigross/grequests" req "github.com/levigross/grequests"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"gitlab.bertha.cloud/partitio/Nextcloud-Partitio/gonextcloud/types" "gitlab.bertha.cloud/partitio/Nextcloud-Partitio/gonextcloud/types"
"net/http" "net/http"
"net/url" "net/url"
@ -32,7 +33,7 @@ func (u *Users) List() ([]string, error) {
} }
//ListDetails return a map of user with details //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 := u.c.baseRequest(http.MethodGet, routes.users, nil, "details")
//res, err := c.session.Get(u.String(), nil) //res, err := c.session.Get(u.String(), nil)
if err != 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 // 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 == "" { if name == "" {
return nil, &types.APIError{Message: "name cannot be empty"} 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 // 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 // Create base Users
ro := &req.RequestOptions{ ro := &req.RequestOptions{
Data: map[string]string{ Data: map[string]string{
@ -132,6 +133,36 @@ func (u *Users) CreateWithoutPassword(username, email, displayName, quota, langu
return nil 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 //Delete delete the user
func (u *Users) Delete(name string) error { func (u *Users) Delete(name string) error {
return u.baseRequest(http.MethodDelete, nil, name) 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 //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) m := structs.Map(user)
errs := make(chan types.UpdateError) errs := make(chan types.UpdateError)
var wg sync.WaitGroup var wg sync.WaitGroup