github.com/nhannv/mattermost-server@v5.11.1+incompatible/app/reaction.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "net/http" 8 9 "github.com/mattermost/mattermost-server/model" 10 ) 11 12 func (a *App) SaveReactionForPost(reaction *model.Reaction) (*model.Reaction, *model.AppError) { 13 post, err := a.GetSinglePost(reaction.PostId) 14 if err != nil { 15 return nil, err 16 } 17 18 channel, err := a.GetChannel(post.ChannelId) 19 if err != nil { 20 return nil, err 21 } 22 23 if channel.DeleteAt > 0 { 24 return nil, model.NewAppError("deleteReactionForPost", "api.reaction.save.archived_channel.app_error", nil, "", http.StatusForbidden) 25 } 26 27 if a.License() != nil && *a.Config().TeamSettings.ExperimentalTownSquareIsReadOnly && channel.Name == model.DEFAULT_CHANNEL { 28 user, err := a.GetUser(reaction.UserId) 29 if err != nil { 30 return nil, err 31 } 32 33 if !a.RolesGrantPermission(user.GetRoles(), model.PERMISSION_MANAGE_SYSTEM.Id) { 34 return nil, model.NewAppError("saveReactionForPost", "api.reaction.town_square_read_only", nil, "", http.StatusForbidden) 35 } 36 } 37 38 result := <-a.Srv.Store.Reaction().Save(reaction) 39 if result.Err != nil { 40 return nil, result.Err 41 } 42 43 reaction = result.Data.(*model.Reaction) 44 45 // The post is always modified since the UpdateAt always changes 46 a.InvalidateCacheForChannelPosts(post.ChannelId) 47 48 a.Srv.Go(func() { 49 a.sendReactionEvent(model.WEBSOCKET_EVENT_REACTION_ADDED, reaction, post, true) 50 }) 51 52 return reaction, nil 53 } 54 55 func (a *App) GetReactionsForPost(postId string) ([]*model.Reaction, *model.AppError) { 56 result := <-a.Srv.Store.Reaction().GetForPost(postId, true) 57 if result.Err != nil { 58 return nil, result.Err 59 } 60 return result.Data.([]*model.Reaction), nil 61 } 62 63 func (a *App) GetBulkReactionsForPosts(postIds []string) (map[string][]*model.Reaction, *model.AppError) { 64 reactions := make(map[string][]*model.Reaction) 65 66 result := <-a.Srv.Store.Reaction().BulkGetForPosts(postIds) 67 if result.Err != nil { 68 return nil, result.Err 69 } 70 71 allReactions := result.Data.([]*model.Reaction) 72 for _, reaction := range allReactions { 73 reactionsForPost := reactions[reaction.PostId] 74 reactionsForPost = append(reactionsForPost, reaction) 75 76 reactions[reaction.PostId] = reactionsForPost 77 } 78 79 reactions = populateEmptyReactions(postIds, reactions) 80 return reactions, nil 81 } 82 83 func populateEmptyReactions(postIds []string, reactions map[string][]*model.Reaction) map[string][]*model.Reaction { 84 for _, postId := range postIds { 85 if _, present := reactions[postId]; !present { 86 reactions[postId] = []*model.Reaction{} 87 } 88 } 89 return reactions 90 } 91 92 func (a *App) DeleteReactionForPost(reaction *model.Reaction) *model.AppError { 93 post, err := a.GetSinglePost(reaction.PostId) 94 if err != nil { 95 return err 96 } 97 98 channel, err := a.GetChannel(post.ChannelId) 99 if err != nil { 100 return err 101 } 102 103 if channel.DeleteAt > 0 { 104 return model.NewAppError("deleteReactionForPost", "api.reaction.delete.archived_channel.app_error", nil, "", http.StatusForbidden) 105 } 106 107 if a.License() != nil && *a.Config().TeamSettings.ExperimentalTownSquareIsReadOnly && channel.Name == model.DEFAULT_CHANNEL { 108 user, err := a.GetUser(reaction.UserId) 109 if err != nil { 110 return err 111 } 112 113 if !a.RolesGrantPermission(user.GetRoles(), model.PERMISSION_MANAGE_SYSTEM.Id) { 114 return model.NewAppError("deleteReactionForPost", "api.reaction.town_square_read_only", nil, "", http.StatusForbidden) 115 } 116 } 117 118 hasReactions := true 119 if reactions, _ := a.GetReactionsForPost(post.Id); len(reactions) <= 1 { 120 hasReactions = false 121 } 122 123 if result := <-a.Srv.Store.Reaction().Delete(reaction); result.Err != nil { 124 return result.Err 125 } 126 127 // The post is always modified since the UpdateAt always changes 128 a.InvalidateCacheForChannelPosts(post.ChannelId) 129 130 a.Srv.Go(func() { 131 a.sendReactionEvent(model.WEBSOCKET_EVENT_REACTION_REMOVED, reaction, post, hasReactions) 132 }) 133 134 return nil 135 } 136 137 func (a *App) sendReactionEvent(event string, reaction *model.Reaction, post *model.Post, hasReactions bool) { 138 // send out that a reaction has been added/removed 139 message := model.NewWebSocketEvent(event, "", post.ChannelId, "", nil) 140 message.Add("reaction", reaction.ToJson()) 141 a.Publish(message) 142 143 post.HasReactions = hasReactions 144 post.UpdateAt = model.GetMillis() 145 146 clientPost := a.PreparePostForClient(post, false) 147 148 umessage := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_POST_EDITED, "", post.ChannelId, "", nil) 149 umessage.Add("post", clientPost.ToJson()) 150 a.Publish(umessage) 151 }