team.go 15.3 KB
Newer Older
1
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
=Corey Hulen's avatar
=Corey Hulen committed
2 3 4 5 6
// See License.txt for license information.

package api

import (
7
	"bytes"
8
	"io"
9 10 11
	"net/http"
	"strconv"
	"strings"
12 13 14 15

	l4g "github.com/alecthomas/log4go"
	"github.com/gorilla/mux"

Christopher Speller's avatar
Christopher Speller committed
16 17 18
	"github.com/mattermost/mattermost-server/app"
	"github.com/mattermost/mattermost-server/model"
	"github.com/mattermost/mattermost-server/utils"
=Corey Hulen's avatar
=Corey Hulen committed
19 20
)

21
func (api *API) InitTeam() {
22
	l4g.Debug(utils.T("api.team.init.debug"))
=Corey Hulen's avatar
=Corey Hulen committed
23

24 25 26 27 28 29 30 31
	api.BaseRoutes.Teams.Handle("/create", api.ApiUserRequired(createTeam)).Methods("POST")
	api.BaseRoutes.Teams.Handle("/all", api.ApiUserRequired(getAll)).Methods("GET")
	api.BaseRoutes.Teams.Handle("/all_team_listings", api.ApiUserRequired(GetAllTeamListings)).Methods("GET")
	api.BaseRoutes.Teams.Handle("/get_invite_info", api.ApiAppHandler(getInviteInfo)).Methods("POST")
	api.BaseRoutes.Teams.Handle("/find_team_by_name", api.ApiUserRequired(findTeamByName)).Methods("POST")
	api.BaseRoutes.Teams.Handle("/name/{team_name:[A-Za-z0-9\\-]+}", api.ApiUserRequired(getTeamByName)).Methods("GET")
	api.BaseRoutes.Teams.Handle("/members", api.ApiUserRequired(getMyTeamMembers)).Methods("GET")
	api.BaseRoutes.Teams.Handle("/unread", api.ApiUserRequired(getMyTeamsUnread)).Methods("GET")
32

33 34 35 36 37 38 39
	api.BaseRoutes.NeedTeam.Handle("/me", api.ApiUserRequired(getMyTeam)).Methods("GET")
	api.BaseRoutes.NeedTeam.Handle("/stats", api.ApiUserRequired(getTeamStats)).Methods("GET")
	api.BaseRoutes.NeedTeam.Handle("/members/{offset:[0-9]+}/{limit:[0-9]+}", api.ApiUserRequired(getTeamMembers)).Methods("GET")
	api.BaseRoutes.NeedTeam.Handle("/members/ids", api.ApiUserRequired(getTeamMembersByIds)).Methods("POST")
	api.BaseRoutes.NeedTeam.Handle("/members/{user_id:[A-Za-z0-9]+}", api.ApiUserRequired(getTeamMember)).Methods("GET")
	api.BaseRoutes.NeedTeam.Handle("/update", api.ApiUserRequired(updateTeam)).Methods("POST")
	api.BaseRoutes.NeedTeam.Handle("/update_member_roles", api.ApiUserRequired(updateMemberRoles)).Methods("POST")
40

41
	api.BaseRoutes.NeedTeam.Handle("/invite_members", api.ApiUserRequired(inviteMembers)).Methods("POST")
42

43 44
	api.BaseRoutes.NeedTeam.Handle("/add_user_to_team", api.ApiUserRequired(addUserToTeam)).Methods("POST")
	api.BaseRoutes.NeedTeam.Handle("/remove_user_from_team", api.ApiUserRequired(removeUserFromTeam)).Methods("POST")
45

46
	// These should be moved to the global admin console
47 48
	api.BaseRoutes.NeedTeam.Handle("/import_team", api.ApiUserRequired(importTeam)).Methods("POST")
	api.BaseRoutes.Teams.Handle("/add_user_to_team_from_invite", api.ApiUserRequiredMfa(addUserToTeamFromInvite)).Methods("POST")
=Corey Hulen's avatar
=Corey Hulen committed
49 50
}

51 52
func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	team := model.TeamFromJson(r.Body)
53

54 55
	if team == nil {
		c.SetInvalidParam("createTeam", "team")
56 57 58
		return
	}

59
	if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_CREATE_TEAM) {
60
		c.Err = model.NewAppError("createTeam", "api.team.is_team_creation_allowed.disabled.app_error", nil, "", http.StatusForbidden)
61 62 63
		return
	}

Chris's avatar
Chris committed
64
	rteam, err := c.App.CreateTeamWithUser(team, c.Session.UserId)
65 66
	if err != nil {
		c.Err = err
67 68 69
		return
	}

70 71
	// Don't sanitize the team here since the user will be a team admin and their session won't reflect that yet

=Corey Hulen's avatar
=Corey Hulen committed
72 73 74
	w.Write([]byte(rteam.ToJson()))
}

75
func GetAllTeamListings(c *Context, w http.ResponseWriter, r *http.Request) {
76 77 78
	var teams []*model.Team
	var err *model.AppError

Chris's avatar
Chris committed
79
	if teams, err = c.App.GetAllOpenTeams(); err != nil {
80
		c.Err = err
81
		return
82
	}
83

84 85 86
	m := make(map[string]*model.Team)
	for _, v := range teams {
		m[v.Id] = v
87
	}
88

89 90
	sanitizeTeamMap(c.Session, m)

91
	w.Write([]byte(model.TeamMapToJson(m)))
92 93
}

94 95
// Gets all teams which the current user can has access to. If the user is a System Admin, this will be all teams
// on the server. Otherwise, it will only be the teams of which the user is a member.
96
func getAll(c *Context, w http.ResponseWriter, r *http.Request) {
97 98 99
	var teams []*model.Team
	var err *model.AppError

Chris's avatar
Chris committed
100 101
	if c.App.HasPermissionTo(c.Session.UserId, model.PERMISSION_MANAGE_SYSTEM) {
		teams, err = c.App.GetAllTeams()
102
	} else {
Chris's avatar
Chris committed
103
		teams, err = c.App.GetTeamsForUser(c.Session.UserId)
104 105
	}

106 107
	if err != nil {
		c.Err = err
108 109 110
		return
	}

111 112 113
	m := make(map[string]*model.Team)
	for _, v := range teams {
		m[v.Id] = v
114
	}
115

116 117
	sanitizeTeamMap(c.Session, m)

118
	w.Write([]byte(model.TeamMapToJson(m)))
119 120
}

121 122
func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
	invites := model.InvitesFromJson(r.Body)
=Corey Hulen's avatar
=Corey Hulen committed
123

124
	if utils.IsLicensed() && !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_INVITE_USER) {
125
		errorId := ""
Chris's avatar
Chris committed
126
		if *c.App.Config().TeamSettings.RestrictTeamInvite == model.PERMISSIONS_SYSTEM_ADMIN {
127
			errorId = "api.team.invite_members.restricted_system_admin.app_error"
Chris's avatar
Chris committed
128
		} else if *c.App.Config().TeamSettings.RestrictTeamInvite == model.PERMISSIONS_TEAM_ADMIN {
129
			errorId = "api.team.invite_members.restricted_team_admin.app_error"
130 131
		}

132
		c.Err = model.NewAppError("inviteMembers", errorId, nil, "", http.StatusForbidden)
133
		return
=Corey Hulen's avatar
=Corey Hulen committed
134 135
	}

Chris's avatar
Chris committed
136
	if err := c.App.InviteNewUsersToTeam(invites.ToEmailList(), c.TeamId, c.Session.UserId); err != nil {
137 138 139
		c.Err = err
		return
	}
140

141
	w.Write([]byte(invites.ToJson()))
=Corey Hulen's avatar
=Corey Hulen committed
142 143
}

144 145 146 147 148 149
func addUserToTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	params := model.MapFromJson(r.Body)
	userId := params["user_id"]

	if len(userId) != 26 {
		c.SetInvalidParam("addUserToTeam", "user_id")
=Corey Hulen's avatar
=Corey Hulen committed
150 151 152
		return
	}

153
	if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_ADD_USER_TO_TEAM) {
154
		c.SetPermissionError(model.PERMISSION_ADD_USER_TO_TEAM)
155 156 157
		return
	}

Chris's avatar
Chris committed
158
	if _, err := c.App.AddUserToTeam(c.TeamId, userId, ""); err != nil {
159 160 161 162 163 164 165
		c.Err = err
		return
	}

	w.Write([]byte(model.MapToJson(params)))
}

166 167 168 169 170 171 172 173 174
func removeUserFromTeam(c *Context, w http.ResponseWriter, r *http.Request) {
	params := model.MapFromJson(r.Body)
	userId := params["user_id"]

	if len(userId) != 26 {
		c.SetInvalidParam("removeUserFromTeam", "user_id")
		return
	}

175
	if c.Session.UserId != userId {
176
		if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_REMOVE_USER_FROM_TEAM) {
177
			c.SetPermissionError(model.PERMISSION_REMOVE_USER_FROM_TEAM)
178 179 180 181
			return
		}
	}

Chris's avatar
Chris committed
182
	if err := c.App.RemoveUserFromTeam(c.TeamId, userId); err != nil {
183 184 185 186 187 188 189
		c.Err = err
		return
	}

	w.Write([]byte(model.MapToJson(params)))
}

190 191 192 193 194 195 196
func addUserToTeamFromInvite(c *Context, w http.ResponseWriter, r *http.Request) {
	params := model.MapFromJson(r.Body)
	hash := params["hash"]
	data := params["data"]
	inviteId := params["invite_id"]

	var team *model.Team
197
	var err *model.AppError
198 199

	if len(hash) > 0 {
Chris's avatar
Chris committed
200
		team, err = c.App.AddUserToTeamByHash(c.Session.UserId, hash, data)
201
	} else if len(inviteId) > 0 {
Chris's avatar
Chris committed
202
		team, err = c.App.AddUserToTeamByInviteId(inviteId, c.Session.UserId)
203
	} else {
204
		c.Err = model.NewAppError("addUserToTeamFromInvite", "api.user.create_user.signup_link_invalid.app_error", nil, "", http.StatusBadRequest)
205 206 207
		return
	}

208 209
	if err != nil {
		c.Err = err
210
		return
211 212
	}

213
	app.SanitizeTeam(c.Session, team)
214 215 216 217 218

	w.Write([]byte(team.ToJson()))
}

func findTeamByName(c *Context, w http.ResponseWriter, r *http.Request) {
=Corey Hulen's avatar
=Corey Hulen committed
219

220 221 222
	m := model.MapFromJson(r.Body)
	name := strings.ToLower(strings.TrimSpace(m["name"]))

Chris's avatar
Chris committed
223
	found := c.App.FindTeamByName(name)
224 225 226 227 228 229

	if found {
		w.Write([]byte("true"))
	} else {
		w.Write([]byte("false"))
	}
=Corey Hulen's avatar
=Corey Hulen committed
230 231
}

232 233 234 235
func getTeamByName(c *Context, w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)
	teamname := params["team_name"]

Chris's avatar
Chris committed
236
	if team, err := c.App.GetTeamByName(teamname); err != nil {
237
		c.Err = err
238 239
		return
	} else {
JoramWilander's avatar
JoramWilander committed
240
		if (!team.AllowOpenInvite || team.Type != model.TEAM_OPEN) && c.Session.GetTeamByTeamId(team.Id) == nil {
241
			if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
242
				c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
243 244 245 246
				return
			}
		}

247 248
		app.SanitizeTeam(c.Session, team)

249 250 251 252 253
		w.Write([]byte(team.ToJson()))
		return
	}
}

enahum's avatar
enahum committed
254 255 256 257
func getMyTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
	if len(c.Session.TeamMembers) > 0 {
		w.Write([]byte(model.TeamMembersToJson(c.Session.TeamMembers)))
	} else {
Chris's avatar
Chris committed
258
		if members, err := c.App.GetTeamMembersForUser(c.Session.UserId); err != nil {
259
			c.Err = err
enahum's avatar
enahum committed
260 261
			return
		} else {
262
			w.Write([]byte(model.TeamMembersToJson(members)))
enahum's avatar
enahum committed
263 264 265 266 267 268 269
		}
	}
}

func getMyTeamsUnread(c *Context, w http.ResponseWriter, r *http.Request) {
	teamId := r.URL.Query().Get("id")

Chris's avatar
Chris committed
270
	if unreads, err := c.App.GetTeamsUnreadForUser(teamId, c.Session.UserId); err != nil {
271
		c.Err = err
enahum's avatar
enahum committed
272 273
		return
	} else {
274
		w.Write([]byte(model.TeamsUnreadToJson(unreads)))
=Corey Hulen's avatar
=Corey Hulen committed
275 276 277
	}
}

=Corey Hulen's avatar
PLT-340  
=Corey Hulen committed
278
func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) {
=Corey Hulen's avatar
=Corey Hulen committed
279

=Corey Hulen's avatar
PLT-340  
=Corey Hulen committed
280 281 282
	team := model.TeamFromJson(r.Body)
	if team == nil {
		c.SetInvalidParam("updateTeam", "team")
=Corey Hulen's avatar
=Corey Hulen committed
283 284 285
		return
	}

286
	team.Id = c.TeamId
=Corey Hulen's avatar
=Corey Hulen committed
287

288
	if !c.App.SessionHasPermissionToTeam(c.Session, team.Id, model.PERMISSION_MANAGE_TEAM) {
289
		c.SetPermissionError(model.PERMISSION_MANAGE_TEAM)
=Corey Hulen's avatar
=Corey Hulen committed
290 291 292
		return
	}

293 294
	var err *model.AppError
	var updatedTeam *model.Team
=Corey Hulen's avatar
PLT-340  
=Corey Hulen committed
295

Chris's avatar
Chris committed
296
	updatedTeam, err = c.App.UpdateTeam(team)
297 298
	if err != nil {
		c.Err = err
=Corey Hulen's avatar
=Corey Hulen committed
299 300 301
		return
	}

302 303
	app.SanitizeTeam(c.Session, updatedTeam)

304
	w.Write([]byte(updatedTeam.ToJson()))
=Corey Hulen's avatar
=Corey Hulen committed
305
}
306

307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
func updateMemberRoles(c *Context, w http.ResponseWriter, r *http.Request) {
	props := model.MapFromJson(r.Body)

	userId := props["user_id"]
	if len(userId) != 26 {
		c.SetInvalidParam("updateMemberRoles", "user_id")
		return
	}

	teamId := c.TeamId

	newRoles := props["new_roles"]
	if !(model.IsValidUserRoles(newRoles)) {
		c.SetInvalidParam("updateMemberRoles", "new_roles")
		return
	}

324
	if !c.App.SessionHasPermissionToTeam(c.Session, teamId, model.PERMISSION_MANAGE_TEAM_ROLES) {
325
		c.SetPermissionError(model.PERMISSION_MANAGE_TEAM_ROLES)
326 327 328
		return
	}

Chris's avatar
Chris committed
329
	if _, err := c.App.UpdateTeamMemberRoles(teamId, userId, newRoles); err != nil {
330
		c.Err = err
331 332 333 334 335 336 337 338
		return
	}

	rdata := map[string]string{}
	rdata["status"] = "ok"
	w.Write([]byte(model.MapToJson(rdata)))
}

339 340
func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) {

341
	if len(c.TeamId) == 0 {
342 343 344
		return
	}

Chris's avatar
Chris committed
345
	if team, err := c.App.GetTeam(c.TeamId); err != nil {
346
		c.Err = err
347
		return
348
	} else if c.HandleEtag(team.Etag(), "Get My Team", w, r) {
349 350
		return
	} else {
351
		w.Header().Set(model.HEADER_ETAG_SERVER, team.Etag())
352 353 354

		app.SanitizeTeam(c.Session, team)

355
		w.Write([]byte(team.ToJson()))
356 357 358
		return
	}
}
359

360 361
func getTeamStats(c *Context, w http.ResponseWriter, r *http.Request) {
	if c.Session.GetTeamByTeamId(c.TeamId) == nil {
362
		if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
363
			c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
364 365 366 367
			return
		}
	}

Chris's avatar
Chris committed
368
	stats, err := c.App.GetTeamStats(c.TeamId)
369 370
	if err != nil {
		c.Err = err
371 372
		return
	}
373 374

	w.Write([]byte(stats.ToJson()))
375 376
}

377
func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
378
	if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_IMPORT_TEAM) {
379
		c.SetPermissionError(model.PERMISSION_IMPORT_TEAM)
380 381 382 383
		return
	}

	if err := r.ParseMultipartForm(10000000); err != nil {
384
		c.Err = model.NewAppError("importTeam", "api.team.import_team.parse.app_error", nil, err.Error(), http.StatusBadRequest)
385 386 387 388
		return
	}

	importFromArray, ok := r.MultipartForm.Value["importFrom"]
389 390 391 392
	if !ok || len(importFromArray) < 1 {
		c.Err = model.NewAppError("importTeam", "api.team.import_team.no_import_from.app_error", nil, "", http.StatusBadRequest)
		return
	}
393 394 395
	importFrom := importFromArray[0]

	fileSizeStr, ok := r.MultipartForm.Value["filesize"]
396
	if !ok || len(fileSizeStr) < 1 {
397
		c.Err = model.NewAppError("importTeam", "api.team.import_team.unavailable.app_error", nil, "", http.StatusBadRequest)
398 399 400 401 402
		return
	}

	fileSize, err := strconv.ParseInt(fileSizeStr[0], 10, 64)
	if err != nil {
403
		c.Err = model.NewAppError("importTeam", "api.team.import_team.integer.app_error", nil, "", http.StatusBadRequest)
404 405 406 407 408
		return
	}

	fileInfoArray, ok := r.MultipartForm.File["file"]
	if !ok {
409
		c.Err = model.NewAppError("importTeam", "api.team.import_team.no_file.app_error", nil, "", http.StatusBadRequest)
410 411 412 413
		return
	}

	if len(fileInfoArray) <= 0 {
414
		c.Err = model.NewAppError("importTeam", "api.team.import_team.array.app_error", nil, "", http.StatusBadRequest)
415 416 417 418 419 420 421
		return
	}

	fileInfo := fileInfoArray[0]

	fileData, err := fileInfo.Open()
	if err != nil {
422
		c.Err = model.NewAppError("importTeam", "api.team.import_team.open.app_error", nil, err.Error(), http.StatusBadRequest)
423 424
		return
	}
425
	defer fileData.Close()
426 427 428 429 430

	var log *bytes.Buffer
	switch importFrom {
	case "slack":
		var err *model.AppError
Chris's avatar
Chris committed
431
		if err, log = c.App.SlackImport(fileData, fileSize, c.TeamId); err != nil {
432 433 434 435 436 437 438
			c.Err = err
			c.Err.StatusCode = http.StatusBadRequest
		}
	}

	w.Header().Set("Content-Disposition", "attachment; filename=MattermostImportLog.txt")
	w.Header().Set("Content-Type", "application/octet-stream")
439 440 441 442 443
	if c.Err != nil {
		w.WriteHeader(c.Err.StatusCode)
	}
	io.Copy(w, bytes.NewReader(log.Bytes()))
	//http.ServeContent(w, r, "MattermostImportLog.txt", time.Now(), bytes.NewReader(log.Bytes()))
444
}
445

446 447 448 449
func getInviteInfo(c *Context, w http.ResponseWriter, r *http.Request) {
	m := model.MapFromJson(r.Body)
	inviteId := m["invite_id"]

Chris's avatar
Chris committed
450
	if team, err := c.App.GetTeamByInviteId(inviteId); err != nil {
451
		c.Err = err
452 453 454
		return
	} else {
		if !(team.Type == model.TEAM_OPEN) {
455
			c.Err = model.NewAppError("getInviteInfo", "api.team.get_invite_info.not_open_team", nil, "id="+inviteId, http.StatusBadRequest)
456 457 458 459 460
			return
		}

		result := map[string]string{}
		result["display_name"] = team.DisplayName
461
		result["description"] = team.Description
462 463 464 465 466
		result["name"] = team.Name
		result["id"] = team.Id
		w.Write([]byte(model.MapToJson(result)))
	}
}
467

468
func getTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
469 470
	params := mux.Vars(r)

471 472 473 474 475 476 477 478 479 480 481 482 483
	offset, err := strconv.Atoi(params["offset"])
	if err != nil {
		c.SetInvalidParam("getTeamMembers", "offset")
		return
	}

	limit, err := strconv.Atoi(params["limit"])
	if err != nil {
		c.SetInvalidParam("getTeamMembers", "limit")
		return
	}

	if c.Session.GetTeamByTeamId(c.TeamId) == nil {
484
		if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_SYSTEM) {
485
			c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
486 487 488 489
			return
		}
	}

Chris's avatar
Chris committed
490
	if members, err := c.App.GetTeamMembers(c.TeamId, offset, limit); err != nil {
491
		c.Err = err
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
		return
	} else {
		w.Write([]byte(model.TeamMembersToJson(members)))
		return
	}
}

func getTeamMember(c *Context, w http.ResponseWriter, r *http.Request) {
	params := mux.Vars(r)

	userId := params["user_id"]
	if len(userId) < 26 {
		c.SetInvalidParam("getTeamMember", "user_id")
		return
	}

	if c.Session.GetTeamByTeamId(c.TeamId) == nil {
509
		if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_SYSTEM) {
510
			c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
511 512 513 514
			return
		}
	}

Chris's avatar
Chris committed
515
	if member, err := c.App.GetTeamMember(c.TeamId, userId); err != nil {
516
		c.Err = err
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
		return
	} else {
		w.Write([]byte(member.ToJson()))
		return
	}
}

func getTeamMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
	userIds := model.ArrayFromJson(r.Body)
	if len(userIds) == 0 {
		c.SetInvalidParam("getTeamMembersByIds", "user_ids")
		return
	}

	if c.Session.GetTeamByTeamId(c.TeamId) == nil {
532
		if !c.App.SessionHasPermissionToTeam(c.Session, c.TeamId, model.PERMISSION_MANAGE_SYSTEM) {
533
			c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
534 535 536 537
			return
		}
	}

Chris's avatar
Chris committed
538
	if members, err := c.App.GetTeamMembersByIds(c.TeamId, userIds); err != nil {
539
		c.Err = err
540 541 542 543 544 545
		return
	} else {
		w.Write([]byte(model.TeamMembersToJson(members)))
		return
	}
}
546 547 548 549 550 551

func sanitizeTeamMap(session model.Session, teams map[string]*model.Team) {
	for _, team := range teams {
		app.SanitizeTeam(session, team)
	}
}