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