github.com/adacta-ru/mattermost-server/v6@v6.0.0/app/reaction.go (about)

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