1// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2// See LICENSE.txt for license information.
3
4package api4
5
6import (
7	"encoding/json"
8	"net/http"
9	"strconv"
10
11	"github.com/mattermost/mattermost-server/v6/audit"
12	"github.com/mattermost/mattermost-server/v6/model"
13	"github.com/mattermost/mattermost-server/v6/shared/mlog"
14	"github.com/mattermost/mattermost-server/v6/store"
15)
16
17func (api *API) InitUserLocal() {
18	api.BaseRoutes.Users.Handle("", api.APILocal(localGetUsers)).Methods("GET")
19	api.BaseRoutes.Users.Handle("", api.APILocal(localPermanentDeleteAllUsers)).Methods("DELETE")
20	api.BaseRoutes.Users.Handle("", api.APILocal(createUser)).Methods("POST")
21	api.BaseRoutes.Users.Handle("/password/reset/send", api.APILocal(sendPasswordReset)).Methods("POST")
22	api.BaseRoutes.Users.Handle("/ids", api.APILocal(localGetUsersByIds)).Methods("POST")
23
24	api.BaseRoutes.User.Handle("", api.APILocal(localGetUser)).Methods("GET")
25	api.BaseRoutes.User.Handle("", api.APILocal(updateUser)).Methods("PUT")
26	api.BaseRoutes.User.Handle("", api.APILocal(localDeleteUser)).Methods("DELETE")
27	api.BaseRoutes.User.Handle("/roles", api.APILocal(updateUserRoles)).Methods("PUT")
28	api.BaseRoutes.User.Handle("/mfa", api.APILocal(updateUserMfa)).Methods("PUT")
29	api.BaseRoutes.User.Handle("/active", api.APILocal(updateUserActive)).Methods("PUT")
30	api.BaseRoutes.User.Handle("/password", api.APILocal(updatePassword)).Methods("PUT")
31	api.BaseRoutes.User.Handle("/convert_to_bot", api.APILocal(convertUserToBot)).Methods("POST")
32	api.BaseRoutes.User.Handle("/email/verify/member", api.APILocal(verifyUserEmailWithoutToken)).Methods("POST")
33	api.BaseRoutes.User.Handle("/promote", api.APILocal(promoteGuestToUser)).Methods("POST")
34	api.BaseRoutes.User.Handle("/demote", api.APILocal(demoteUserToGuest)).Methods("POST")
35
36	api.BaseRoutes.UserByUsername.Handle("", api.APILocal(localGetUserByUsername)).Methods("GET")
37	api.BaseRoutes.UserByEmail.Handle("", api.APILocal(localGetUserByEmail)).Methods("GET")
38
39	api.BaseRoutes.Users.Handle("/tokens/revoke", api.APILocal(revokeUserAccessToken)).Methods("POST")
40	api.BaseRoutes.User.Handle("/tokens", api.APILocal(getUserAccessTokensForUser)).Methods("GET")
41	api.BaseRoutes.User.Handle("/tokens", api.APILocal(createUserAccessToken)).Methods("POST")
42
43	api.BaseRoutes.Users.Handle("/migrate_auth/ldap", api.APILocal(migrateAuthToLDAP)).Methods("POST")
44	api.BaseRoutes.Users.Handle("/migrate_auth/saml", api.APILocal(migrateAuthToSaml)).Methods("POST")
45
46	api.BaseRoutes.User.Handle("/uploads", api.APILocal(localGetUploadsForUser)).Methods("GET")
47}
48
49func localGetUsers(c *Context, w http.ResponseWriter, r *http.Request) {
50	inTeamId := r.URL.Query().Get("in_team")
51	notInTeamId := r.URL.Query().Get("not_in_team")
52	inChannelId := r.URL.Query().Get("in_channel")
53	notInChannelId := r.URL.Query().Get("not_in_channel")
54	groupConstrained := r.URL.Query().Get("group_constrained")
55	withoutTeam := r.URL.Query().Get("without_team")
56	active := r.URL.Query().Get("active")
57	inactive := r.URL.Query().Get("inactive")
58	role := r.URL.Query().Get("role")
59	sort := r.URL.Query().Get("sort")
60
61	if notInChannelId != "" && inTeamId == "" {
62		c.SetInvalidURLParam("team_id")
63		return
64	}
65
66	if sort != "" && sort != "last_activity_at" && sort != "create_at" && sort != "status" {
67		c.SetInvalidURLParam("sort")
68		return
69	}
70
71	// Currently only supports sorting on a team
72	// or sort="status" on inChannelId
73	if (sort == "last_activity_at" || sort == "create_at") && (inTeamId == "" || notInTeamId != "" || inChannelId != "" || notInChannelId != "" || withoutTeam != "") {
74		c.SetInvalidURLParam("sort")
75		return
76	}
77	if sort == "status" && inChannelId == "" {
78		c.SetInvalidURLParam("sort")
79		return
80	}
81
82	withoutTeamBool, _ := strconv.ParseBool(withoutTeam)
83	groupConstrainedBool, _ := strconv.ParseBool(groupConstrained)
84	activeBool, _ := strconv.ParseBool(active)
85	inactiveBool, _ := strconv.ParseBool(inactive)
86
87	userGetOptions := &model.UserGetOptions{
88		InTeamId:         inTeamId,
89		InChannelId:      inChannelId,
90		NotInTeamId:      notInTeamId,
91		NotInChannelId:   notInChannelId,
92		GroupConstrained: groupConstrainedBool,
93		WithoutTeam:      withoutTeamBool,
94		Active:           activeBool,
95		Inactive:         inactiveBool,
96		Role:             role,
97		Sort:             sort,
98		Page:             c.Params.Page,
99		PerPage:          c.Params.PerPage,
100		ViewRestrictions: nil,
101	}
102
103	var err *model.AppError
104	var profiles []*model.User
105	etag := ""
106
107	if withoutTeamBool, _ := strconv.ParseBool(withoutTeam); withoutTeamBool {
108		profiles, err = c.App.GetUsersWithoutTeamPage(userGetOptions, c.IsSystemAdmin())
109	} else if notInChannelId != "" {
110		profiles, err = c.App.GetUsersNotInChannelPage(inTeamId, notInChannelId, groupConstrainedBool, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
111	} else if notInTeamId != "" {
112		etag = c.App.GetUsersNotInTeamEtag(inTeamId, "")
113		if c.HandleEtag(etag, "Get Users Not in Team", w, r) {
114			return
115		}
116
117		profiles, err = c.App.GetUsersNotInTeamPage(notInTeamId, groupConstrainedBool, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
118	} else if inTeamId != "" {
119		if sort == "last_activity_at" {
120			profiles, err = c.App.GetRecentlyActiveUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
121		} else if sort == "create_at" {
122			profiles, err = c.App.GetNewUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
123		} else {
124			etag = c.App.GetUsersInTeamEtag(inTeamId, "")
125			if c.HandleEtag(etag, "Get Users in Team", w, r) {
126				return
127			}
128			profiles, err = c.App.GetUsersInTeamPage(userGetOptions, c.IsSystemAdmin())
129		}
130	} else if inChannelId != "" {
131		if sort == "status" {
132			profiles, err = c.App.GetUsersInChannelPageByStatus(userGetOptions, c.IsSystemAdmin())
133		} else {
134			profiles, err = c.App.GetUsersInChannelPage(userGetOptions, c.IsSystemAdmin())
135		}
136	} else {
137		profiles, err = c.App.GetUsersPage(userGetOptions, c.IsSystemAdmin())
138	}
139
140	if err != nil {
141		c.Err = err
142		return
143	}
144
145	if etag != "" {
146		w.Header().Set(model.HeaderEtagServer, etag)
147	}
148
149	js, jsonErr := json.Marshal(profiles)
150	if jsonErr != nil {
151		c.Err = model.NewAppError("localGetUsers", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
152		return
153	}
154
155	w.Write(js)
156}
157
158func localGetUsersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
159	userIds := model.ArrayFromJSON(r.Body)
160
161	if len(userIds) == 0 {
162		c.SetInvalidParam("user_ids")
163		return
164	}
165
166	sinceString := r.URL.Query().Get("since")
167
168	options := &store.UserGetByIdsOpts{
169		IsAdmin: c.IsSystemAdmin(),
170	}
171
172	if sinceString != "" {
173		since, parseError := strconv.ParseInt(sinceString, 10, 64)
174		if parseError != nil {
175			c.SetInvalidParam("since")
176			return
177		}
178		options.Since = since
179	}
180
181	users, err := c.App.GetUsersByIds(userIds, options)
182	if err != nil {
183		c.Err = err
184		return
185	}
186
187	js, jsonErr := json.Marshal(users)
188	if jsonErr != nil {
189		c.Err = model.NewAppError("localGetUsersByIds", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
190		return
191	}
192
193	w.Write(js)
194}
195
196func localGetUser(c *Context, w http.ResponseWriter, r *http.Request) {
197	c.RequireUserId()
198	if c.Err != nil {
199		return
200	}
201
202	user, err := c.App.GetUser(c.Params.UserId)
203	if err != nil {
204		c.Err = err
205		return
206	}
207
208	userTermsOfService, err := c.App.GetUserTermsOfService(user.Id)
209	if err != nil && err.StatusCode != http.StatusNotFound {
210		c.Err = err
211		return
212	}
213
214	if userTermsOfService != nil {
215		user.TermsOfServiceId = userTermsOfService.TermsOfServiceId
216		user.TermsOfServiceCreateAt = userTermsOfService.CreateAt
217	}
218
219	etag := user.Etag(*c.App.Config().PrivacySettings.ShowFullName, *c.App.Config().PrivacySettings.ShowEmailAddress)
220
221	if c.HandleEtag(etag, "Get User", w, r) {
222		return
223	}
224
225	c.App.SanitizeProfile(user, c.IsSystemAdmin())
226	w.Header().Set(model.HeaderEtagServer, etag)
227	if err := json.NewEncoder(w).Encode(user); err != nil {
228		mlog.Warn("Error while writing response", mlog.Err(err))
229	}
230}
231
232func localDeleteUser(c *Context, w http.ResponseWriter, r *http.Request) {
233	c.RequireUserId()
234	if c.Err != nil {
235		return
236	}
237
238	userId := c.Params.UserId
239
240	auditRec := c.MakeAuditRecord("localDeleteUser", audit.Fail)
241	defer c.LogAuditRec(auditRec)
242
243	user, err := c.App.GetUser(userId)
244	if err != nil {
245		c.Err = err
246		return
247	}
248	auditRec.AddMeta("user", user)
249
250	if c.Params.Permanent {
251		err = c.App.PermanentDeleteUser(c.AppContext, user)
252	} else {
253		_, err = c.App.UpdateActive(c.AppContext, user, false)
254	}
255	if err != nil {
256		c.Err = err
257		return
258	}
259
260	auditRec.Success()
261	ReturnStatusOK(w)
262}
263
264func localPermanentDeleteAllUsers(c *Context, w http.ResponseWriter, r *http.Request) {
265	auditRec := c.MakeAuditRecord("localPermanentDeleteAllUsers", audit.Fail)
266	defer c.LogAuditRec(auditRec)
267
268	if err := c.App.PermanentDeleteAllUsers(c.AppContext); err != nil {
269		c.Err = err
270		return
271	}
272
273	auditRec.Success()
274	ReturnStatusOK(w)
275}
276
277func localGetUserByUsername(c *Context, w http.ResponseWriter, r *http.Request) {
278	c.RequireUsername()
279	if c.Err != nil {
280		return
281	}
282
283	user, err := c.App.GetUserByUsername(c.Params.Username)
284	if err != nil {
285		c.Err = err
286		return
287	}
288
289	userTermsOfService, err := c.App.GetUserTermsOfService(user.Id)
290	if err != nil && err.StatusCode != http.StatusNotFound {
291		c.Err = err
292		return
293	}
294
295	if userTermsOfService != nil {
296		user.TermsOfServiceId = userTermsOfService.TermsOfServiceId
297		user.TermsOfServiceCreateAt = userTermsOfService.CreateAt
298	}
299
300	etag := user.Etag(*c.App.Config().PrivacySettings.ShowFullName, *c.App.Config().PrivacySettings.ShowEmailAddress)
301
302	if c.HandleEtag(etag, "Get User", w, r) {
303		return
304	}
305
306	c.App.SanitizeProfile(user, c.IsSystemAdmin())
307	w.Header().Set(model.HeaderEtagServer, etag)
308	if err := json.NewEncoder(w).Encode(user); err != nil {
309		mlog.Warn("Error while writing response", mlog.Err(err))
310	}
311}
312
313func localGetUserByEmail(c *Context, w http.ResponseWriter, r *http.Request) {
314	c.SanitizeEmail()
315	if c.Err != nil {
316		return
317	}
318
319	sanitizeOptions := c.App.GetSanitizeOptions(c.IsSystemAdmin())
320	if !sanitizeOptions["email"] {
321		c.Err = model.NewAppError("getUserByEmail", "api.user.get_user_by_email.permissions.app_error", nil, "userId="+c.AppContext.Session().UserId, http.StatusForbidden)
322		return
323	}
324
325	user, err := c.App.GetUserByEmail(c.Params.Email)
326	if err != nil {
327		c.Err = err
328		return
329	}
330
331	etag := user.Etag(*c.App.Config().PrivacySettings.ShowFullName, *c.App.Config().PrivacySettings.ShowEmailAddress)
332
333	if c.HandleEtag(etag, "Get User", w, r) {
334		return
335	}
336
337	c.App.SanitizeProfile(user, c.IsSystemAdmin())
338	w.Header().Set(model.HeaderEtagServer, etag)
339	if err := json.NewEncoder(w).Encode(user); err != nil {
340		mlog.Warn("Error while writing response", mlog.Err(err))
341	}
342}
343
344func localGetUploadsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
345	uss, err := c.App.GetUploadSessionsForUser(c.Params.UserId)
346	if err != nil {
347		c.Err = err
348		return
349	}
350
351	js, jsonErr := json.Marshal(uss)
352	if jsonErr != nil {
353		c.Err = model.NewAppError("localGetUploadsForUser", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
354		return
355	}
356	w.Write(js)
357}
358