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
10	"github.com/mattermost/mattermost-server/v6/audit"
11	"github.com/mattermost/mattermost-server/v6/model"
12	"github.com/mattermost/mattermost-server/v6/shared/mlog"
13)
14
15func getCategoriesForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
16	c.RequireUserId().RequireTeamId()
17	if c.Err != nil {
18		return
19	}
20
21	if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
22		c.SetPermissionError(model.PermissionEditOtherUsers)
23		return
24	}
25
26	categories, err := c.App.GetSidebarCategories(c.Params.UserId, c.Params.TeamId)
27	if err != nil {
28		c.Err = err
29		return
30	}
31
32	categoriesJSON, jsonErr := json.Marshal(categories)
33	if jsonErr != nil {
34		c.Err = model.NewAppError("getCategoriesForTeamForUser", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
35		return
36	}
37
38	w.Write(categoriesJSON)
39}
40
41func createCategoryForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
42	c.RequireUserId().RequireTeamId()
43	if c.Err != nil {
44		return
45	}
46
47	if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
48		c.SetPermissionError(model.PermissionEditOtherUsers)
49		return
50	}
51
52	auditRec := c.MakeAuditRecord("createCategoryForTeamForUser", audit.Fail)
53	defer c.LogAuditRec(auditRec)
54
55	var categoryCreateRequest *model.SidebarCategoryWithChannels
56	err := json.NewDecoder(r.Body).Decode(&categoryCreateRequest)
57	if err != nil || c.Params.UserId != categoryCreateRequest.UserId || c.Params.TeamId != categoryCreateRequest.TeamId {
58		c.SetInvalidParam("category")
59		return
60	}
61
62	if appErr := validateSidebarCategory(c, c.Params.TeamId, c.Params.UserId, categoryCreateRequest); appErr != nil {
63		c.Err = appErr
64		return
65	}
66
67	category, appErr := c.App.CreateSidebarCategory(c.Params.UserId, c.Params.TeamId, categoryCreateRequest)
68	if appErr != nil {
69		c.Err = appErr
70		return
71	}
72
73	categoryJSON, jsonErr := json.Marshal(category)
74	if jsonErr != nil {
75		c.Err = model.NewAppError("createCategoryForTeamForUser", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
76		return
77	}
78
79	auditRec.Success()
80
81	w.Write(categoryJSON)
82}
83
84func getCategoryOrderForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
85	c.RequireUserId().RequireTeamId()
86	if c.Err != nil {
87		return
88	}
89
90	if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
91		c.SetPermissionError(model.PermissionEditOtherUsers)
92		return
93	}
94
95	order, err := c.App.GetSidebarCategoryOrder(c.Params.UserId, c.Params.TeamId)
96	if err != nil {
97		c.Err = err
98		return
99	}
100
101	w.Write([]byte(model.ArrayToJSON(order)))
102}
103
104func updateCategoryOrderForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
105	c.RequireUserId().RequireTeamId()
106	if c.Err != nil {
107		return
108	}
109
110	if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
111		c.SetPermissionError(model.PermissionEditOtherUsers)
112		return
113	}
114
115	auditRec := c.MakeAuditRecord("updateCategoryOrderForTeamForUser", audit.Fail)
116	defer c.LogAuditRec(auditRec)
117
118	categoryOrder := model.ArrayFromJSON(r.Body)
119
120	for _, categoryId := range categoryOrder {
121		if !c.App.SessionHasPermissionToCategory(*c.AppContext.Session(), c.Params.UserId, c.Params.TeamId, categoryId) {
122			c.SetInvalidParam("category")
123			return
124		}
125	}
126
127	err := c.App.UpdateSidebarCategoryOrder(c.Params.UserId, c.Params.TeamId, categoryOrder)
128	if err != nil {
129		c.Err = err
130		return
131	}
132
133	auditRec.Success()
134	w.Write([]byte(model.ArrayToJSON(categoryOrder)))
135}
136
137func getCategoryForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
138	c.RequireUserId().RequireTeamId().RequireCategoryId()
139	if c.Err != nil {
140		return
141	}
142
143	if !c.App.SessionHasPermissionToCategory(*c.AppContext.Session(), c.Params.UserId, c.Params.TeamId, c.Params.CategoryId) {
144		c.SetPermissionError(model.PermissionEditOtherUsers)
145		return
146	}
147
148	categories, err := c.App.GetSidebarCategory(c.Params.CategoryId)
149	if err != nil {
150		c.Err = err
151		return
152	}
153
154	categoriesJSON, jsonErr := json.Marshal(categories)
155	if jsonErr != nil {
156		c.Err = model.NewAppError("getCategoryForTeamForUser", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
157		return
158	}
159
160	w.Write(categoriesJSON)
161}
162
163func updateCategoriesForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
164	c.RequireUserId().RequireTeamId()
165	if c.Err != nil {
166		return
167	}
168
169	if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
170		c.SetPermissionError(model.PermissionEditOtherUsers)
171		return
172	}
173
174	auditRec := c.MakeAuditRecord("updateCategoriesForTeamForUser", audit.Fail)
175	defer c.LogAuditRec(auditRec)
176
177	var categoriesUpdateRequest []*model.SidebarCategoryWithChannels
178	err := json.NewDecoder(r.Body).Decode(&categoriesUpdateRequest)
179	if err != nil {
180		c.SetInvalidParam("category")
181		return
182	}
183
184	for _, category := range categoriesUpdateRequest {
185		if !c.App.SessionHasPermissionToCategory(*c.AppContext.Session(), c.Params.UserId, c.Params.TeamId, category.Id) {
186			c.SetInvalidParam("category")
187			return
188		}
189	}
190
191	if appErr := validateSidebarCategories(c, c.Params.TeamId, c.Params.UserId, categoriesUpdateRequest); appErr != nil {
192		c.Err = appErr
193		return
194	}
195
196	categories, appErr := c.App.UpdateSidebarCategories(c.Params.UserId, c.Params.TeamId, categoriesUpdateRequest)
197	if appErr != nil {
198		c.Err = appErr
199		return
200	}
201
202	categoriesJSON, jsonErr := json.Marshal(categories)
203	if jsonErr != nil {
204		c.Err = model.NewAppError("updateCategoriesForTeamForUser", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
205		return
206	}
207
208	auditRec.Success()
209	w.Write(categoriesJSON)
210}
211
212func validateSidebarCategory(c *Context, teamId, userId string, category *model.SidebarCategoryWithChannels) *model.AppError {
213	channels, err := c.App.GetChannelsForUser(teamId, userId, true, 0)
214	if err != nil {
215		return model.NewAppError("validateSidebarCategory", "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
216	}
217
218	category.Channels = validateSidebarCategoryChannels(userId, category.Channels, channels)
219
220	return nil
221}
222
223func validateSidebarCategories(c *Context, teamId, userId string, categories []*model.SidebarCategoryWithChannels) *model.AppError {
224	channels, err := c.App.GetChannelsForUser(teamId, userId, true, 0)
225	if err != nil {
226		return model.NewAppError("validateSidebarCategory", "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
227	}
228
229	for _, category := range categories {
230		category.Channels = validateSidebarCategoryChannels(userId, category.Channels, channels)
231	}
232
233	return nil
234}
235
236func validateSidebarCategoryChannels(userId string, channelIds []string, channels model.ChannelList) []string {
237	var filtered []string
238
239	for _, channelId := range channelIds {
240		found := false
241		for _, channel := range channels {
242			if channel.Id == channelId {
243				found = true
244				break
245			}
246		}
247
248		if found {
249			filtered = append(filtered, channelId)
250		} else {
251			mlog.Info("Stopping user from adding channel to their sidebar when they are not a member", mlog.String("user_id", userId), mlog.String("channel_id", channelId))
252		}
253	}
254
255	return filtered
256}
257
258func updateCategoryForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
259	c.RequireUserId().RequireTeamId().RequireCategoryId()
260	if c.Err != nil {
261		return
262	}
263
264	if !c.App.SessionHasPermissionToCategory(*c.AppContext.Session(), c.Params.UserId, c.Params.TeamId, c.Params.CategoryId) {
265		c.SetPermissionError(model.PermissionEditOtherUsers)
266		return
267	}
268
269	auditRec := c.MakeAuditRecord("updateCategoryForTeamForUser", audit.Fail)
270	defer c.LogAuditRec(auditRec)
271
272	var categoryUpdateRequest *model.SidebarCategoryWithChannels
273	err := json.NewDecoder(r.Body).Decode(&categoryUpdateRequest)
274	if err != nil || categoryUpdateRequest.TeamId != c.Params.TeamId || categoryUpdateRequest.UserId != c.Params.UserId {
275		c.SetInvalidParam("category")
276		return
277	}
278
279	if appErr := validateSidebarCategory(c, c.Params.TeamId, c.Params.UserId, categoryUpdateRequest); appErr != nil {
280		c.Err = appErr
281		return
282	}
283
284	categoryUpdateRequest.Id = c.Params.CategoryId
285
286	categories, appErr := c.App.UpdateSidebarCategories(c.Params.UserId, c.Params.TeamId, []*model.SidebarCategoryWithChannels{categoryUpdateRequest})
287	if appErr != nil {
288		c.Err = appErr
289		return
290	}
291
292	categoryJSON, jsonErr := json.Marshal(categories[0])
293	if jsonErr != nil {
294		c.Err = model.NewAppError("updateCategoryForTeamForUser", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
295		return
296	}
297
298	auditRec.Success()
299	w.Write(categoryJSON)
300}
301
302func deleteCategoryForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
303	c.RequireUserId().RequireTeamId().RequireCategoryId()
304	if c.Err != nil {
305		return
306	}
307
308	if !c.App.SessionHasPermissionToCategory(*c.AppContext.Session(), c.Params.UserId, c.Params.TeamId, c.Params.CategoryId) {
309		c.SetPermissionError(model.PermissionEditOtherUsers)
310		return
311	}
312
313	auditRec := c.MakeAuditRecord("deleteCategoryForTeamForUser", audit.Fail)
314	defer c.LogAuditRec(auditRec)
315
316	appErr := c.App.DeleteSidebarCategory(c.Params.UserId, c.Params.TeamId, c.Params.CategoryId)
317	if appErr != nil {
318		c.Err = appErr
319		return
320	}
321
322	auditRec.Success()
323	ReturnStatusOK(w)
324}
325