users.go

  1//
  2// Copyright 2017, Sander van Harmelen
  3//
  4// Licensed under the Apache License, Version 2.0 (the "License");
  5// you may not use this file except in compliance with the License.
  6// You may obtain a copy of the License at
  7//
  8//     http://www.apache.org/licenses/LICENSE-2.0
  9//
 10// Unless required by applicable law or agreed to in writing, software
 11// distributed under the License is distributed on an "AS IS" BASIS,
 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13// See the License for the specific language governing permissions and
 14// limitations under the License.
 15//
 16
 17package gitlab
 18
 19import (
 20	"errors"
 21	"fmt"
 22	"time"
 23)
 24
 25// List a couple of standard errors.
 26var (
 27	ErrUserBlockPrevented   = errors.New("Cannot block a user that is already blocked by LDAP synchronization")
 28	ErrUserNotFound         = errors.New("User does not exist")
 29	ErrUserUnblockPrevented = errors.New("Cannot unblock a user that is blocked by LDAP synchronization")
 30)
 31
 32// UsersService handles communication with the user related methods of
 33// the GitLab API.
 34//
 35// GitLab API docs: https://docs.gitlab.com/ce/api/users.html
 36type UsersService struct {
 37	client *Client
 38}
 39
 40// BasicUser included in other service responses (such as merge requests, pipelines, etc).
 41type BasicUser struct {
 42	ID        int        `json:"id"`
 43	Username  string     `json:"username"`
 44	Name      string     `json:"name"`
 45	State     string     `json:"state"`
 46	CreatedAt *time.Time `json:"created_at"`
 47	AvatarURL string     `json:"avatar_url"`
 48	WebURL    string     `json:"web_url"`
 49}
 50
 51// User represents a GitLab user.
 52//
 53// GitLab API docs: https://docs.gitlab.com/ee/api/users.html
 54type User struct {
 55	ID                        int                `json:"id"`
 56	Username                  string             `json:"username"`
 57	Email                     string             `json:"email"`
 58	Name                      string             `json:"name"`
 59	State                     string             `json:"state"`
 60	CreatedAt                 *time.Time         `json:"created_at"`
 61	Bio                       string             `json:"bio"`
 62	Location                  string             `json:"location"`
 63	PublicEmail               string             `json:"public_email"`
 64	Skype                     string             `json:"skype"`
 65	Linkedin                  string             `json:"linkedin"`
 66	Twitter                   string             `json:"twitter"`
 67	WebsiteURL                string             `json:"website_url"`
 68	Organization              string             `json:"organization"`
 69	ExternUID                 string             `json:"extern_uid"`
 70	Provider                  string             `json:"provider"`
 71	ThemeID                   int                `json:"theme_id"`
 72	LastActivityOn            *ISOTime           `json:"last_activity_on"`
 73	ColorSchemeID             int                `json:"color_scheme_id"`
 74	IsAdmin                   bool               `json:"is_admin"`
 75	AvatarURL                 string             `json:"avatar_url"`
 76	CanCreateGroup            bool               `json:"can_create_group"`
 77	CanCreateProject          bool               `json:"can_create_project"`
 78	ProjectsLimit             int                `json:"projects_limit"`
 79	CurrentSignInAt           *time.Time         `json:"current_sign_in_at"`
 80	LastSignInAt              *time.Time         `json:"last_sign_in_at"`
 81	ConfirmedAt               *time.Time         `json:"confirmed_at"`
 82	TwoFactorEnabled          bool               `json:"two_factor_enabled"`
 83	Identities                []*UserIdentity    `json:"identities"`
 84	External                  bool               `json:"external"`
 85	PrivateProfile            bool               `json:"private_profile"`
 86	SharedRunnersMinutesLimit int                `json:"shared_runners_minutes_limit"`
 87	CustomAttributes          []*CustomAttribute `json:"custom_attributes"`
 88}
 89
 90// UserIdentity represents a user identity.
 91type UserIdentity struct {
 92	Provider  string `json:"provider"`
 93	ExternUID string `json:"extern_uid"`
 94}
 95
 96// ListUsersOptions represents the available ListUsers() options.
 97//
 98// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users
 99type ListUsersOptions struct {
100	ListOptions
101	Active  *bool `url:"active,omitempty" json:"active,omitempty"`
102	Blocked *bool `url:"blocked,omitempty" json:"blocked,omitempty"`
103
104	// The options below are only available for admins.
105	Search               *string    `url:"search,omitempty" json:"search,omitempty"`
106	Username             *string    `url:"username,omitempty" json:"username,omitempty"`
107	ExternalUID          *string    `url:"extern_uid,omitempty" json:"extern_uid,omitempty"`
108	Provider             *string    `url:"provider,omitempty" json:"provider,omitempty"`
109	CreatedBefore        *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
110	CreatedAfter         *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
111	OrderBy              *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
112	Sort                 *string    `url:"sort,omitempty" json:"sort,omitempty"`
113	WithCustomAttributes *bool      `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
114}
115
116// ListUsers gets a list of users.
117//
118// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users
119func (s *UsersService) ListUsers(opt *ListUsersOptions, options ...OptionFunc) ([]*User, *Response, error) {
120	req, err := s.client.NewRequest("GET", "users", opt, options)
121	if err != nil {
122		return nil, nil, err
123	}
124
125	var usr []*User
126	resp, err := s.client.Do(req, &usr)
127	if err != nil {
128		return nil, resp, err
129	}
130
131	return usr, resp, err
132}
133
134// GetUser gets a single user.
135//
136// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-user
137func (s *UsersService) GetUser(user int, options ...OptionFunc) (*User, *Response, error) {
138	u := fmt.Sprintf("users/%d", user)
139
140	req, err := s.client.NewRequest("GET", u, nil, options)
141	if err != nil {
142		return nil, nil, err
143	}
144
145	usr := new(User)
146	resp, err := s.client.Do(req, usr)
147	if err != nil {
148		return nil, resp, err
149	}
150
151	return usr, resp, err
152}
153
154// CreateUserOptions represents the available CreateUser() options.
155//
156// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation
157type CreateUserOptions struct {
158	Email            *string `url:"email,omitempty" json:"email,omitempty"`
159	Password         *string `url:"password,omitempty" json:"password,omitempty"`
160	ResetPassword    *bool   `url:"reset_password,omitempty" json:"reset_password,omitempty"`
161	Username         *string `url:"username,omitempty" json:"username,omitempty"`
162	Name             *string `url:"name,omitempty" json:"name,omitempty"`
163	Skype            *string `url:"skype,omitempty" json:"skype,omitempty"`
164	Linkedin         *string `url:"linkedin,omitempty" json:"linkedin,omitempty"`
165	Twitter          *string `url:"twitter,omitempty" json:"twitter,omitempty"`
166	WebsiteURL       *string `url:"website_url,omitempty" json:"website_url,omitempty"`
167	Organization     *string `url:"organization,omitempty" json:"organization,omitempty"`
168	ProjectsLimit    *int    `url:"projects_limit,omitempty" json:"projects_limit,omitempty"`
169	ExternUID        *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"`
170	Provider         *string `url:"provider,omitempty" json:"provider,omitempty"`
171	Bio              *string `url:"bio,omitempty" json:"bio,omitempty"`
172	Location         *string `url:"location,omitempty" json:"location,omitempty"`
173	Admin            *bool   `url:"admin,omitempty" json:"admin,omitempty"`
174	CanCreateGroup   *bool   `url:"can_create_group,omitempty" json:"can_create_group,omitempty"`
175	SkipConfirmation *bool   `url:"skip_confirmation,omitempty" json:"skip_confirmation,omitempty"`
176	External         *bool   `url:"external,omitempty" json:"external,omitempty"`
177	PrivateProfile   *bool   `url:"private_profile,omitempty" json:"private_profile,omitempty"`
178}
179
180// CreateUser creates a new user. Note only administrators can create new users.
181//
182// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation
183func (s *UsersService) CreateUser(opt *CreateUserOptions, options ...OptionFunc) (*User, *Response, error) {
184	req, err := s.client.NewRequest("POST", "users", opt, options)
185	if err != nil {
186		return nil, nil, err
187	}
188
189	usr := new(User)
190	resp, err := s.client.Do(req, usr)
191	if err != nil {
192		return nil, resp, err
193	}
194
195	return usr, resp, err
196}
197
198// ModifyUserOptions represents the available ModifyUser() options.
199//
200// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification
201type ModifyUserOptions struct {
202	Email              *string `url:"email,omitempty" json:"email,omitempty"`
203	Password           *string `url:"password,omitempty" json:"password,omitempty"`
204	Username           *string `url:"username,omitempty" json:"username,omitempty"`
205	Name               *string `url:"name,omitempty" json:"name,omitempty"`
206	Skype              *string `url:"skype,omitempty" json:"skype,omitempty"`
207	Linkedin           *string `url:"linkedin,omitempty" json:"linkedin,omitempty"`
208	Twitter            *string `url:"twitter,omitempty" json:"twitter,omitempty"`
209	WebsiteURL         *string `url:"website_url,omitempty" json:"website_url,omitempty"`
210	Organization       *string `url:"organization,omitempty" json:"organization,omitempty"`
211	ProjectsLimit      *int    `url:"projects_limit,omitempty" json:"projects_limit,omitempty"`
212	ExternUID          *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"`
213	Provider           *string `url:"provider,omitempty" json:"provider,omitempty"`
214	Bio                *string `url:"bio,omitempty" json:"bio,omitempty"`
215	Location           *string `url:"location,omitempty" json:"location,omitempty"`
216	Admin              *bool   `url:"admin,omitempty" json:"admin,omitempty"`
217	CanCreateGroup     *bool   `url:"can_create_group,omitempty" json:"can_create_group,omitempty"`
218	SkipReconfirmation *bool   `url:"skip_reconfirmation,omitempty" json:"skip_reconfirmation,omitempty"`
219	External           *bool   `url:"external,omitempty" json:"external,omitempty"`
220	PrivateProfile     *bool   `url:"private_profile,omitempty" json:"private_profile,omitempty"`
221}
222
223// ModifyUser modifies an existing user. Only administrators can change attributes
224// of a user.
225//
226// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification
227func (s *UsersService) ModifyUser(user int, opt *ModifyUserOptions, options ...OptionFunc) (*User, *Response, error) {
228	u := fmt.Sprintf("users/%d", user)
229
230	req, err := s.client.NewRequest("PUT", u, opt, options)
231	if err != nil {
232		return nil, nil, err
233	}
234
235	usr := new(User)
236	resp, err := s.client.Do(req, usr)
237	if err != nil {
238		return nil, resp, err
239	}
240
241	return usr, resp, err
242}
243
244// DeleteUser deletes a user. Available only for administrators. This is an
245// idempotent function, calling this function for a non-existent user id still
246// returns a status code 200 OK. The JSON response differs if the user was
247// actually deleted or not. In the former the user is returned and in the
248// latter not.
249//
250// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-deletion
251func (s *UsersService) DeleteUser(user int, options ...OptionFunc) (*Response, error) {
252	u := fmt.Sprintf("users/%d", user)
253
254	req, err := s.client.NewRequest("DELETE", u, nil, options)
255	if err != nil {
256		return nil, err
257	}
258
259	return s.client.Do(req, nil)
260}
261
262// CurrentUser gets currently authenticated user.
263//
264// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#current-user
265func (s *UsersService) CurrentUser(options ...OptionFunc) (*User, *Response, error) {
266	req, err := s.client.NewRequest("GET", "user", nil, options)
267	if err != nil {
268		return nil, nil, err
269	}
270
271	usr := new(User)
272	resp, err := s.client.Do(req, usr)
273	if err != nil {
274		return nil, resp, err
275	}
276
277	return usr, resp, err
278}
279
280// SSHKey represents a SSH key.
281//
282// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys
283type SSHKey struct {
284	ID        int        `json:"id"`
285	Title     string     `json:"title"`
286	Key       string     `json:"key"`
287	CreatedAt *time.Time `json:"created_at"`
288}
289
290// ListSSHKeys gets a list of currently authenticated user's SSH keys.
291//
292// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys
293func (s *UsersService) ListSSHKeys(options ...OptionFunc) ([]*SSHKey, *Response, error) {
294	req, err := s.client.NewRequest("GET", "user/keys", nil, options)
295	if err != nil {
296		return nil, nil, err
297	}
298
299	var k []*SSHKey
300	resp, err := s.client.Do(req, &k)
301	if err != nil {
302		return nil, resp, err
303	}
304
305	return k, resp, err
306}
307
308// ListSSHKeysForUserOptions represents the available ListSSHKeysForUser() options.
309//
310// GitLab API docs:
311// https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user
312type ListSSHKeysForUserOptions ListOptions
313
314// ListSSHKeysForUser gets a list of a specified user's SSH keys. Available
315// only for admin
316//
317// GitLab API docs:
318// https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user
319func (s *UsersService) ListSSHKeysForUser(user int, opt *ListSSHKeysForUserOptions, options ...OptionFunc) ([]*SSHKey, *Response, error) {
320	u := fmt.Sprintf("users/%d/keys", user)
321
322	req, err := s.client.NewRequest("GET", u, opt, options)
323	if err != nil {
324		return nil, nil, err
325	}
326
327	var k []*SSHKey
328	resp, err := s.client.Do(req, &k)
329	if err != nil {
330		return nil, resp, err
331	}
332
333	return k, resp, err
334}
335
336// GetSSHKey gets a single key.
337//
338// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-ssh-key
339func (s *UsersService) GetSSHKey(key int, options ...OptionFunc) (*SSHKey, *Response, error) {
340	u := fmt.Sprintf("user/keys/%d", key)
341
342	req, err := s.client.NewRequest("GET", u, nil, options)
343	if err != nil {
344		return nil, nil, err
345	}
346
347	k := new(SSHKey)
348	resp, err := s.client.Do(req, k)
349	if err != nil {
350		return nil, resp, err
351	}
352
353	return k, resp, err
354}
355
356// AddSSHKeyOptions represents the available AddSSHKey() options.
357//
358// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-ssh-key
359type AddSSHKeyOptions struct {
360	Title *string `url:"title,omitempty" json:"title,omitempty"`
361	Key   *string `url:"key,omitempty" json:"key,omitempty"`
362}
363
364// AddSSHKey creates a new key owned by the currently authenticated user.
365//
366// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key
367func (s *UsersService) AddSSHKey(opt *AddSSHKeyOptions, options ...OptionFunc) (*SSHKey, *Response, error) {
368	req, err := s.client.NewRequest("POST", "user/keys", opt, options)
369	if err != nil {
370		return nil, nil, err
371	}
372
373	k := new(SSHKey)
374	resp, err := s.client.Do(req, k)
375	if err != nil {
376		return nil, resp, err
377	}
378
379	return k, resp, err
380}
381
382// AddSSHKeyForUser creates new key owned by specified user. Available only for
383// admin.
384//
385// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key-for-user
386func (s *UsersService) AddSSHKeyForUser(user int, opt *AddSSHKeyOptions, options ...OptionFunc) (*SSHKey, *Response, error) {
387	u := fmt.Sprintf("users/%d/keys", user)
388
389	req, err := s.client.NewRequest("POST", u, opt, options)
390	if err != nil {
391		return nil, nil, err
392	}
393
394	k := new(SSHKey)
395	resp, err := s.client.Do(req, k)
396	if err != nil {
397		return nil, resp, err
398	}
399
400	return k, resp, err
401}
402
403// DeleteSSHKey deletes key owned by currently authenticated user. This is an
404// idempotent function and calling it on a key that is already deleted or not
405// available results in 200 OK.
406//
407// GitLab API docs:
408// https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-current-owner
409func (s *UsersService) DeleteSSHKey(key int, options ...OptionFunc) (*Response, error) {
410	u := fmt.Sprintf("user/keys/%d", key)
411
412	req, err := s.client.NewRequest("DELETE", u, nil, options)
413	if err != nil {
414		return nil, err
415	}
416
417	return s.client.Do(req, nil)
418}
419
420// DeleteSSHKeyForUser deletes key owned by a specified user. Available only
421// for admin.
422//
423// GitLab API docs:
424// https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-given-user
425func (s *UsersService) DeleteSSHKeyForUser(user, key int, options ...OptionFunc) (*Response, error) {
426	u := fmt.Sprintf("users/%d/keys/%d", user, key)
427
428	req, err := s.client.NewRequest("DELETE", u, nil, options)
429	if err != nil {
430		return nil, err
431	}
432
433	return s.client.Do(req, nil)
434}
435
436// BlockUser blocks the specified user. Available only for admin.
437//
438// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#block-user
439func (s *UsersService) BlockUser(user int, options ...OptionFunc) error {
440	u := fmt.Sprintf("users/%d/block", user)
441
442	req, err := s.client.NewRequest("POST", u, nil, options)
443	if err != nil {
444		return err
445	}
446
447	resp, err := s.client.Do(req, nil)
448	if err != nil && resp == nil {
449		return err
450	}
451
452	switch resp.StatusCode {
453	case 201:
454		return nil
455	case 403:
456		return ErrUserBlockPrevented
457	case 404:
458		return ErrUserNotFound
459	default:
460		return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode)
461	}
462}
463
464// UnblockUser unblocks the specified user. Available only for admin.
465//
466// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#unblock-user
467func (s *UsersService) UnblockUser(user int, options ...OptionFunc) error {
468	u := fmt.Sprintf("users/%d/unblock", user)
469
470	req, err := s.client.NewRequest("POST", u, nil, options)
471	if err != nil {
472		return err
473	}
474
475	resp, err := s.client.Do(req, nil)
476	if err != nil && resp == nil {
477		return err
478	}
479
480	switch resp.StatusCode {
481	case 201:
482		return nil
483	case 403:
484		return ErrUserUnblockPrevented
485	case 404:
486		return ErrUserNotFound
487	default:
488		return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode)
489	}
490}
491
492// Email represents an Email.
493//
494// GitLab API docs: https://doc.gitlab.com/ce/api/users.html#list-emails
495type Email struct {
496	ID    int    `json:"id"`
497	Email string `json:"email"`
498}
499
500// ListEmails gets a list of currently authenticated user's Emails.
501//
502// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-emails
503func (s *UsersService) ListEmails(options ...OptionFunc) ([]*Email, *Response, error) {
504	req, err := s.client.NewRequest("GET", "user/emails", nil, options)
505	if err != nil {
506		return nil, nil, err
507	}
508
509	var e []*Email
510	resp, err := s.client.Do(req, &e)
511	if err != nil {
512		return nil, resp, err
513	}
514
515	return e, resp, err
516}
517
518// ListEmailsForUserOptions represents the available ListEmailsForUser() options.
519//
520// GitLab API docs:
521// https://docs.gitlab.com/ce/api/users.html#list-emails-for-user
522type ListEmailsForUserOptions ListOptions
523
524// ListEmailsForUser gets a list of a specified user's Emails. Available
525// only for admin
526//
527// GitLab API docs:
528// https://docs.gitlab.com/ce/api/users.html#list-emails-for-user
529func (s *UsersService) ListEmailsForUser(user int, opt *ListEmailsForUserOptions, options ...OptionFunc) ([]*Email, *Response, error) {
530	u := fmt.Sprintf("users/%d/emails", user)
531
532	req, err := s.client.NewRequest("GET", u, opt, options)
533	if err != nil {
534		return nil, nil, err
535	}
536
537	var e []*Email
538	resp, err := s.client.Do(req, &e)
539	if err != nil {
540		return nil, resp, err
541	}
542
543	return e, resp, err
544}
545
546// GetEmail gets a single email.
547//
548// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-email
549func (s *UsersService) GetEmail(email int, options ...OptionFunc) (*Email, *Response, error) {
550	u := fmt.Sprintf("user/emails/%d", email)
551
552	req, err := s.client.NewRequest("GET", u, nil, options)
553	if err != nil {
554		return nil, nil, err
555	}
556
557	e := new(Email)
558	resp, err := s.client.Do(req, e)
559	if err != nil {
560		return nil, resp, err
561	}
562
563	return e, resp, err
564}
565
566// AddEmailOptions represents the available AddEmail() options.
567//
568// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-email
569type AddEmailOptions struct {
570	Email *string `url:"email,omitempty" json:"email,omitempty"`
571}
572
573// AddEmail creates a new email owned by the currently authenticated user.
574//
575// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email
576func (s *UsersService) AddEmail(opt *AddEmailOptions, options ...OptionFunc) (*Email, *Response, error) {
577	req, err := s.client.NewRequest("POST", "user/emails", opt, options)
578	if err != nil {
579		return nil, nil, err
580	}
581
582	e := new(Email)
583	resp, err := s.client.Do(req, e)
584	if err != nil {
585		return nil, resp, err
586	}
587
588	return e, resp, err
589}
590
591// AddEmailForUser creates new email owned by specified user. Available only for
592// admin.
593//
594// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email-for-user
595func (s *UsersService) AddEmailForUser(user int, opt *AddEmailOptions, options ...OptionFunc) (*Email, *Response, error) {
596	u := fmt.Sprintf("users/%d/emails", user)
597
598	req, err := s.client.NewRequest("POST", u, opt, options)
599	if err != nil {
600		return nil, nil, err
601	}
602
603	e := new(Email)
604	resp, err := s.client.Do(req, e)
605	if err != nil {
606		return nil, resp, err
607	}
608
609	return e, resp, err
610}
611
612// DeleteEmail deletes email owned by currently authenticated user. This is an
613// idempotent function and calling it on a key that is already deleted or not
614// available results in 200 OK.
615//
616// GitLab API docs:
617// https://docs.gitlab.com/ce/api/users.html#delete-email-for-current-owner
618func (s *UsersService) DeleteEmail(email int, options ...OptionFunc) (*Response, error) {
619	u := fmt.Sprintf("user/emails/%d", email)
620
621	req, err := s.client.NewRequest("DELETE", u, nil, options)
622	if err != nil {
623		return nil, err
624	}
625
626	return s.client.Do(req, nil)
627}
628
629// DeleteEmailForUser deletes email owned by a specified user. Available only
630// for admin.
631//
632// GitLab API docs:
633// https://docs.gitlab.com/ce/api/users.html#delete-email-for-given-user
634func (s *UsersService) DeleteEmailForUser(user, email int, options ...OptionFunc) (*Response, error) {
635	u := fmt.Sprintf("users/%d/emails/%d", user, email)
636
637	req, err := s.client.NewRequest("DELETE", u, nil, options)
638	if err != nil {
639		return nil, err
640	}
641
642	return s.client.Do(req, nil)
643}
644
645// ImpersonationToken represents an impersonation token.
646//
647// GitLab API docs:
648// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user
649type ImpersonationToken struct {
650	ID        int        `json:"id"`
651	Name      string     `json:"name"`
652	Active    bool       `json:"active"`
653	Token     string     `json:"token"`
654	Scopes    []string   `json:"scopes"`
655	Revoked   bool       `json:"revoked"`
656	CreatedAt *time.Time `json:"created_at"`
657	ExpiresAt *ISOTime   `json:"expires_at"`
658}
659
660// GetAllImpersonationTokensOptions represents the available
661// GetAllImpersonationTokens() options.
662//
663// GitLab API docs:
664// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user
665type GetAllImpersonationTokensOptions struct {
666	ListOptions
667	State *string `url:"state,omitempty" json:"state,omitempty"`
668}
669
670// GetAllImpersonationTokens retrieves all impersonation tokens of a user.
671//
672// GitLab API docs:
673// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user
674func (s *UsersService) GetAllImpersonationTokens(user int, opt *GetAllImpersonationTokensOptions, options ...OptionFunc) ([]*ImpersonationToken, *Response, error) {
675	u := fmt.Sprintf("users/%d/impersonation_tokens", user)
676
677	req, err := s.client.NewRequest("GET", u, opt, options)
678	if err != nil {
679		return nil, nil, err
680	}
681
682	var ts []*ImpersonationToken
683	resp, err := s.client.Do(req, &ts)
684	if err != nil {
685		return nil, resp, err
686	}
687
688	return ts, resp, err
689}
690
691// GetImpersonationToken retrieves an impersonation token of a user.
692//
693// GitLab API docs:
694// https://docs.gitlab.com/ce/api/users.html#get-an-impersonation-token-of-a-user
695func (s *UsersService) GetImpersonationToken(user, token int, options ...OptionFunc) (*ImpersonationToken, *Response, error) {
696	u := fmt.Sprintf("users/%d/impersonation_tokens/%d", user, token)
697
698	req, err := s.client.NewRequest("GET", u, nil, options)
699	if err != nil {
700		return nil, nil, err
701	}
702
703	t := new(ImpersonationToken)
704	resp, err := s.client.Do(req, &t)
705	if err != nil {
706		return nil, resp, err
707	}
708
709	return t, resp, err
710}
711
712// CreateImpersonationTokenOptions represents the available
713// CreateImpersonationToken() options.
714//
715// GitLab API docs:
716// https://docs.gitlab.com/ce/api/users.html#create-an-impersonation-token
717type CreateImpersonationTokenOptions struct {
718	Name      *string    `url:"name,omitempty" json:"name,omitempty"`
719	Scopes    *[]string  `url:"scopes,omitempty" json:"scopes,omitempty"`
720	ExpiresAt *time.Time `url:"expires_at,omitempty" json:"expires_at,omitempty"`
721}
722
723// CreateImpersonationToken creates an impersonation token.
724//
725// GitLab API docs:
726// https://docs.gitlab.com/ce/api/users.html#create-an-impersonation-token
727func (s *UsersService) CreateImpersonationToken(user int, opt *CreateImpersonationTokenOptions, options ...OptionFunc) (*ImpersonationToken, *Response, error) {
728	u := fmt.Sprintf("users/%d/impersonation_tokens", user)
729
730	req, err := s.client.NewRequest("POST", u, opt, options)
731	if err != nil {
732		return nil, nil, err
733	}
734
735	t := new(ImpersonationToken)
736	resp, err := s.client.Do(req, &t)
737	if err != nil {
738		return nil, resp, err
739	}
740
741	return t, resp, err
742}
743
744// RevokeImpersonationToken revokes an impersonation token.
745//
746// GitLab API docs:
747// https://docs.gitlab.com/ce/api/users.html#revoke-an-impersonation-token
748func (s *UsersService) RevokeImpersonationToken(user, token int, options ...OptionFunc) (*Response, error) {
749	u := fmt.Sprintf("users/%d/impersonation_tokens/%d", user, token)
750
751	req, err := s.client.NewRequest("DELETE", u, nil, options)
752	if err != nil {
753		return nil, err
754	}
755
756	return s.client.Do(req, nil)
757}
758
759// UserActivity represents an entry in the user/activities response
760//
761// GitLab API docs:
762// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only
763type UserActivity struct {
764	Username       string   `json:"username"`
765	LastActivityOn *ISOTime `json:"last_activity_on"`
766}
767
768// GetUserActivitiesOptions represents the options for GetUserActivities
769//
770// GitLap API docs:
771// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only
772type GetUserActivitiesOptions struct {
773	From *ISOTime `url:"from,omitempty" json:"from,omitempty"`
774}
775
776// GetUserActivities retrieves user activities (admin only)
777//
778// GitLab API docs:
779// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only
780func (s *UsersService) GetUserActivities(opt *GetUserActivitiesOptions, options ...OptionFunc) ([]*UserActivity, *Response, error) {
781	req, err := s.client.NewRequest("GET", "user/activities", opt, options)
782	if err != nil {
783		return nil, nil, err
784	}
785
786	var t []*UserActivity
787	resp, err := s.client.Do(req, &t)
788	if err != nil {
789		return nil, resp, err
790	}
791
792	return t, resp, err
793}
794
795// UserStatus represents the current status of a user
796//
797// GitLab API docs:
798// https://docs.gitlab.com/ce/api/users.html#user-status
799type UserStatus struct {
800	Emoji       string `json:"emoji"`
801	Message     string `json:"message"`
802	MessageHTML string `json:"message_html"`
803}
804
805// CurrentUserStatus retrieves the user status
806//
807// GitLab API docs:
808// https://docs.gitlab.com/ce/api/users.html#user-status
809func (s *UsersService) CurrentUserStatus(options ...OptionFunc) (*UserStatus, *Response, error) {
810	req, err := s.client.NewRequest("GET", "user/status", nil, options)
811	if err != nil {
812		return nil, nil, err
813	}
814
815	status := new(UserStatus)
816	resp, err := s.client.Do(req, status)
817	if err != nil {
818		return nil, resp, err
819	}
820
821	return status, resp, err
822}
823
824// GetUserStatus retrieves a user's status
825//
826// GitLab API docs:
827// https://docs.gitlab.com/ce/api/users.html#get-the-status-of-a-user
828func (s *UsersService) GetUserStatus(user int, options ...OptionFunc) (*UserStatus, *Response, error) {
829	u := fmt.Sprintf("users/%d/status", user)
830
831	req, err := s.client.NewRequest("GET", u, nil, options)
832	if err != nil {
833		return nil, nil, err
834	}
835
836	status := new(UserStatus)
837	resp, err := s.client.Do(req, status)
838	if err != nil {
839		return nil, resp, err
840	}
841
842	return status, resp, err
843}
844
845// UserStatusOptions represents the options required to set the status
846//
847// GitLab API docs:
848// https://docs.gitlab.com/ce/api/users.html#set-user-status
849type UserStatusOptions struct {
850	Emoji   *string `url:"emoji,omitempty" json:"emoji,omitempty"`
851	Message *string `url:"message,omitempty" json:"message,omitempty"`
852}
853
854// SetUserStatus sets the user's status
855//
856// GitLab API docs:
857// https://docs.gitlab.com/ce/api/users.html#set-user-status
858func (s *UsersService) SetUserStatus(opt *UserStatusOptions, options ...OptionFunc) (*UserStatus, *Response, error) {
859	req, err := s.client.NewRequest("PUT", "user/status", opt, options)
860	if err != nil {
861		return nil, nil, err
862	}
863
864	status := new(UserStatus)
865	resp, err := s.client.Do(req, status)
866	if err != nil {
867		return nil, resp, err
868	}
869
870	return status, resp, err
871}