gonextcloud/users.go

333 lines
9.0 KiB
Go

package gonextcloud
import (
"encoding/json"
"github.com/fatih/structs"
req "github.com/levigross/grequests"
"github.com/pkg/errors"
"gitlab.adphi.fr/partitio/Nextcloud-Partitio/gonextcloud/types"
"net/http"
"path"
"strconv"
"strings"
"sync"
)
//UsersI available methods
type UsersI interface {
List() ([]string, error)
ListDetails() (map[string]types.User, error)
Get(name string) (*types.User, error)
Search(search string) ([]string, error)
Create(username string, password string, user *types.User) error
CreateWithoutPassword(username, email, displayName string) error
Delete(name string) error
Enable(name string) error
Disable(name string) error
SendWelcomeEmail(name string) error
Update(user *types.User) error
UpdateEmail(name string, email string) error
UpdateDisplayName(name string, displayName string) error
UpdatePhone(name string, phone string) error
UpdateAddress(name string, address string) error
UpdateWebSite(name string, website string) error
UpdateTwitter(name string, twitter string) error
UpdatePassword(name string, password string) error
UpdateQuota(name string, quota int) error
GroupList(name string) ([]string, error)
GroupAdd(name string, group string) error
GroupRemove(name string, group string) error
GroupPromote(name string, group string) error
GroupDemote(name string, group string) error
GroupSubAdminList(name string) ([]string, error)
}
//Users contains all Users available actions
type Users struct {
c *Client
}
// List return the Nextcloud'user list
func (u *Users) List() ([]string, error) {
res, err := u.c.baseRequest(http.MethodGet, routes.users, nil)
//res, err := c.session.Get(u.String(), nil)
if err != nil {
return nil, err
}
var r types.UserListResponse
res.JSON(&r)
return r.Ocs.Data.Users, nil
}
//ListDetails return a map of user with details
func (u *Users) ListDetails() (map[string]types.User, error) {
res, err := u.c.baseRequest(http.MethodGet, routes.users, nil, "details")
//res, err := c.session.Get(u.String(), nil)
if err != nil {
return nil, err
}
var r types.UserListDetailsResponse
res.JSON(&r)
return r.Ocs.Data.Users, nil
}
// Get return the details about the specified user
func (u *Users) Get(name string) (*types.User, error) {
if name == "" {
return nil, &types.APIError{Message: "name cannot be empty"}
}
res, err := u.c.baseRequest(http.MethodGet, routes.users, nil, name)
if err != nil {
return nil, err
}
var r types.UserResponse
js := res.String()
// Nextcloud does not encode JSON properly
js = reformatJSON(js)
if err := json.Unmarshal([]byte(js), &r); err != nil {
return nil, err
}
return &r.Ocs.Data, nil
}
// Search returns the users whose name match the search string
func (u *Users) Search(search string) ([]string, error) {
ro := &req.RequestOptions{
Params: map[string]string{"search": search},
}
res, err := u.c.baseRequest(http.MethodGet, routes.users, ro)
if err != nil {
return nil, err
}
var r types.UserListResponse
res.JSON(&r)
return r.Ocs.Data.Users, nil
}
// Create create a new user
func (u *Users) Create(username string, password string, user *types.User) error {
// Create base Users
ro := &req.RequestOptions{
Data: map[string]string{
"userid": username,
"password": password,
},
}
if err := u.baseRequest(http.MethodPost, ro); err != nil {
return err
}
// Check if we need to add user details information
if user == nil {
return nil
}
// Add user details information
return u.Update(user)
}
// CreateWithoutPassword create a user without provisioning a password, the email address must be provided to send
// an init password email
func (u *Users) CreateWithoutPassword(username, email, displayName string) error {
if u.c.version.Major < 14 {
return errors.New("unsupported method: requires Nextcloud 14+")
}
if username == "" || email == "" {
return errors.New("username and email cannot be empty")
}
ro := &req.RequestOptions{
Data: map[string]string{
"userid": username,
"email": email,
"displayName": displayName,
},
}
if err := u.baseRequest(http.MethodPost, ro); err != nil {
return err
}
return nil
}
//Delete delete the user
func (u *Users) Delete(name string) error {
return u.baseRequest(http.MethodDelete, nil, name)
}
//Enable enables the user
func (u *Users) Enable(name string) error {
ro := &req.RequestOptions{
Data: map[string]string{},
}
return u.baseRequest(http.MethodPut, ro, name, "enable")
}
//Disable disables the user
func (u *Users) Disable(name string) error {
ro := &req.RequestOptions{
Data: map[string]string{},
}
return u.baseRequest(http.MethodPut, ro, name, "disable")
}
//SendWelcomeEmail (re)send the welcome mail to the user (return an error if the user has not configured his email)
func (u *Users) SendWelcomeEmail(name string) error {
return u.baseRequest(http.MethodPost, nil, name, "welcome")
}
//Update takes a *types.Users struct to update the user's information
func (u *Users) Update(user *types.User) error {
m := structs.Map(user)
errs := make(chan types.UpdateError)
var wg sync.WaitGroup
for k := range m {
if !ignoredUserField(k) && m[k].(string) != "" {
wg.Add(1)
go func(key string, value string) {
defer wg.Done()
if err := u.updateAttribute(user.ID, strings.ToLower(key), value); err != nil {
errs <- types.UpdateError{
Field: key,
Error: err,
}
}
}(k, m[k].(string))
}
}
go func() {
wg.Wait()
close(errs)
}()
return types.NewUpdateError(errs)
}
//UpdateEmail update the user's email
func (u *Users) UpdateEmail(name string, email string) error {
return u.updateAttribute(name, "email", email)
}
//UpdateDisplayName update the user's display name
func (u *Users) UpdateDisplayName(name string, displayName string) error {
return u.updateAttribute(name, "displayname", displayName)
}
//UpdatePhone update the user's phone
func (u *Users) UpdatePhone(name string, phone string) error {
return u.updateAttribute(name, "phone", phone)
}
//UpdateAddress update the user's address
func (u *Users) UpdateAddress(name string, address string) error {
return u.updateAttribute(name, "address", address)
}
//UpdateWebSite update the user's website
func (u *Users) UpdateWebSite(name string, website string) error {
return u.updateAttribute(name, "website", website)
}
//UpdateTwitter update the user's twitter
func (u *Users) UpdateTwitter(name string, twitter string) error {
return u.updateAttribute(name, "twitter", twitter)
}
//UpdatePassword update the user's password
func (u *Users) UpdatePassword(name string, password string) error {
return u.updateAttribute(name, "password", password)
}
//UpdateQuota update the user's quota (bytes)
func (u *Users) UpdateQuota(name string, quota int) error {
return u.updateAttribute(name, "quota", strconv.Itoa(quota))
}
//GroupList lists the user's groups
func (u *Users) GroupList(name string) ([]string, error) {
res, err := u.c.baseRequest(http.MethodGet, routes.users, nil, name, "groups")
if err != nil {
return nil, err
}
var r types.GroupListResponse
res.JSON(&r)
return r.Ocs.Data.Groups, nil
}
//GroupAdd adds a the user to the group
func (u *Users) GroupAdd(name string, group string) error {
ro := &req.RequestOptions{
Data: map[string]string{
"groupid": group,
},
}
return u.baseRequest(http.MethodPost, ro, name, "groups")
}
//GroupRemove removes the user from the group
func (u *Users) GroupRemove(name string, group string) error {
ro := &req.RequestOptions{
Data: map[string]string{
"groupid": group,
},
}
return u.baseRequest(http.MethodDelete, ro, name, "groups")
}
//GroupPromote promotes the user as group admin
func (u *Users) GroupPromote(name string, group string) error {
ro := &req.RequestOptions{
Data: map[string]string{
"groupid": group,
},
}
return u.baseRequest(http.MethodPost, ro, name, "subadmins")
}
//GroupDemote demotes the user
func (u *Users) GroupDemote(name string, group string) error {
ro := &req.RequestOptions{
Data: map[string]string{
"groupid": group,
},
}
return u.baseRequest(http.MethodDelete, ro, name, "subadmins")
}
//GroupSubAdminList lists the groups where he is subadmin
func (u *Users) GroupSubAdminList(name string) ([]string, error) {
if !u.c.loggedIn() {
return nil, errUnauthorized
}
ur := u.c.baseURL.ResolveReference(routes.users)
ur.Path = path.Join(ur.Path, name, "subadmins")
res, err := u.c.session.Get(ur.String(), nil)
if err != nil {
return nil, err
}
var r types.BaseResponse
res.JSON(&r)
return r.Ocs.Data, nil
}
func (u *Users) updateAttribute(name string, key string, value string) error {
ro := &req.RequestOptions{
Data: map[string]string{
"key": key,
"value": value,
},
}
return u.baseRequest(http.MethodPut, ro, name)
}
func (u *Users) baseRequest(method string, ro *req.RequestOptions, subRoutes ...string) error {
_, err := u.c.baseRequest(method, routes.users, ro, subRoutes...)
return err
}
func ignoredUserField(key string) bool {
keys := []string{"ID", "Quota", "Enabled", "Groups", "Language"}
for _, k := range keys {
if key == k {
return true
}
}
return false
}