170 lines
6.5 KiB
Go
170 lines
6.5 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package app
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
|
"github.com/mattermost/mattermost/server/public/shared/request"
|
|
"github.com/mattermost/mattermost/server/v8/channels/store"
|
|
)
|
|
|
|
func (a *App) CreateView(rctx request.CTX, view *model.View, connectionID string) (*model.View, *model.AppError) {
|
|
if view == nil {
|
|
return nil, model.NewAppError("CreateView", "app.view.create.nil_view.app_error", nil, "view is nil", http.StatusBadRequest)
|
|
}
|
|
|
|
count, err := a.Srv().Store().View().CountForChannel(view.ChannelId, model.ViewQueryOpts{})
|
|
if err != nil {
|
|
return nil, model.NewAppError("CreateView", "app.view.create.count.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
|
}
|
|
if count >= model.MaxViewsPerChannel {
|
|
return nil, model.NewAppError("CreateView", "app.view.create.limit.app_error", nil, "channel has reached the maximum number of views", http.StatusBadRequest)
|
|
}
|
|
|
|
saved, err := a.Srv().Store().View().Save(view)
|
|
if err != nil {
|
|
var appErr *model.AppError
|
|
if errors.As(err, &appErr) {
|
|
return nil, appErr
|
|
}
|
|
return nil, model.NewAppError("CreateView", "app.view.create.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
|
}
|
|
|
|
a.publishViewEvent(rctx, model.WebsocketEventViewCreated, saved, connectionID)
|
|
|
|
return saved, nil
|
|
}
|
|
|
|
func (a *App) GetView(rctx request.CTX, viewID string) (*model.View, *model.AppError) {
|
|
view, err := a.Srv().Store().View().Get(viewID)
|
|
if err != nil {
|
|
var nfErr *store.ErrNotFound
|
|
switch {
|
|
case errors.As(err, &nfErr):
|
|
return nil, model.NewAppError("GetView", "app.view.get.not_found.app_error", nil, "", http.StatusNotFound).Wrap(err)
|
|
default:
|
|
return nil, model.NewAppError("GetView", "app.view.get.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
|
}
|
|
}
|
|
|
|
return view, nil
|
|
}
|
|
|
|
func (a *App) GetViewsForChannel(rctx request.CTX, channelID string, opts model.ViewQueryOpts) ([]*model.View, *model.AppError) {
|
|
result, err := a.Srv().Store().View().GetForChannel(channelID, opts)
|
|
if err != nil {
|
|
var invErr *store.ErrInvalidInput
|
|
if errors.As(err, &invErr) {
|
|
return nil, model.NewAppError("GetViewsForChannel", "app.view.get_for_channel.invalid_input.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
|
}
|
|
return nil, model.NewAppError("GetViewsForChannel", "app.view.get_for_channel.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
|
}
|
|
|
|
if result == nil {
|
|
result = []*model.View{}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (a *App) GetViewsCountForChannel(rctx request.CTX, channelID string, opts model.ViewQueryOpts) (int64, *model.AppError) {
|
|
count, err := a.Srv().Store().View().CountForChannel(channelID, opts)
|
|
if err != nil {
|
|
return 0, model.NewAppError("GetViewsCountForChannel", "app.view.count_for_channel.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
func (a *App) UpdateView(rctx request.CTX, view *model.View, patch *model.ViewPatch, connectionID string) (*model.View, *model.AppError) {
|
|
if view == nil {
|
|
return nil, model.NewAppError("UpdateView", "app.view.update.nil_view.app_error", nil, "view is nil", http.StatusBadRequest)
|
|
}
|
|
view = view.Clone()
|
|
view.Patch(patch)
|
|
updated, err := a.Srv().Store().View().Update(view)
|
|
if err != nil {
|
|
var appErr *model.AppError
|
|
var nfErr *store.ErrNotFound
|
|
switch {
|
|
case errors.As(err, &appErr):
|
|
return nil, appErr
|
|
case errors.As(err, &nfErr):
|
|
return nil, model.NewAppError("UpdateView", "app.view.update.not_found.app_error", nil, "", http.StatusNotFound).Wrap(err)
|
|
default:
|
|
return nil, model.NewAppError("UpdateView", "app.view.update.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
|
}
|
|
}
|
|
|
|
a.publishViewEvent(rctx, model.WebsocketEventViewUpdated, updated, connectionID)
|
|
|
|
return updated, nil
|
|
}
|
|
|
|
func (a *App) DeleteView(rctx request.CTX, view *model.View, connectionID string) *model.AppError {
|
|
if view == nil {
|
|
return model.NewAppError("DeleteView", "app.view.delete.nil_view.app_error", nil, "view is nil", http.StatusBadRequest)
|
|
}
|
|
if err := a.Srv().Store().View().Delete(view.Id, model.GetMillis()); err != nil {
|
|
var nfErr *store.ErrNotFound
|
|
if errors.As(err, &nfErr) {
|
|
return model.NewAppError("DeleteView", "app.view.delete.not_found.app_error", nil, "", http.StatusNotFound).Wrap(err)
|
|
}
|
|
return model.NewAppError("DeleteView", "app.view.delete.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
|
}
|
|
|
|
// Delete events send only the view ID (not the full view JSON) since consumers
|
|
// only need the ID to remove the view from state. Create/Update use publishViewEvent
|
|
// to send the full view.
|
|
message := model.NewWebSocketEvent(model.WebsocketEventViewDeleted, "", view.ChannelId, "", nil, connectionID)
|
|
message.Add("view_id", view.Id)
|
|
a.Publish(message)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *App) UpdateViewSortOrder(rctx request.CTX, viewID, channelID string, newIndex int64, connectionID string) ([]*model.View, *model.AppError) {
|
|
views, err := a.Srv().Store().View().UpdateSortOrder(viewID, channelID, newIndex)
|
|
if err != nil {
|
|
var iiErr *store.ErrInvalidInput
|
|
var nfErr *store.ErrNotFound
|
|
switch {
|
|
case errors.As(err, &iiErr):
|
|
return nil, model.NewAppError("UpdateViewSortOrder", "app.view.update_sort_order.invalid_input.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
|
case errors.As(err, &nfErr):
|
|
return nil, model.NewAppError("UpdateViewSortOrder", "app.view.update_sort_order.not_found.app_error", nil, "", http.StatusNotFound).Wrap(err)
|
|
default:
|
|
return nil, model.NewAppError("UpdateViewSortOrder", "app.view.update_sort_order.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
|
}
|
|
}
|
|
|
|
viewsJSON, jsonErr := json.Marshal(views)
|
|
if jsonErr != nil {
|
|
rctx.Logger().Warn("Failed to encode views to JSON for websocket", mlog.Err(jsonErr))
|
|
} else {
|
|
message := model.NewWebSocketEvent(model.WebsocketEventViewSorted, "", channelID, "", nil, connectionID)
|
|
message.Add("views", string(viewsJSON))
|
|
a.Publish(message)
|
|
}
|
|
|
|
return views, nil
|
|
}
|
|
|
|
func (a *App) publishViewEvent(rctx request.CTX, eventType model.WebsocketEventType, view *model.View, connectionID string) {
|
|
if view == nil {
|
|
return
|
|
}
|
|
viewJSON, err := json.Marshal(view)
|
|
if err != nil {
|
|
rctx.Logger().Warn("Failed to encode view to JSON", mlog.Err(err))
|
|
return
|
|
}
|
|
message := model.NewWebSocketEvent(eventType, "", view.ChannelId, "", nil, connectionID)
|
|
message.Add("view", string(viewJSON))
|
|
a.Publish(message)
|
|
}
|