github.com/mad-app/mattermost-server@v5.11.1+incompatible/store/sqlstore/supplier_reactions.go (about)

     1  // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"net/http"
    10  
    11  	"github.com/mattermost/gorp"
    12  	"github.com/mattermost/mattermost-server/mlog"
    13  	"github.com/mattermost/mattermost-server/model"
    14  	"github.com/mattermost/mattermost-server/store"
    15  )
    16  
    17  func initSqlSupplierReactions(sqlStore SqlStore) {
    18  	for _, db := range sqlStore.GetAllConns() {
    19  		table := db.AddTableWithName(model.Reaction{}, "Reactions").SetKeys(false, "UserId", "PostId", "EmojiName")
    20  		table.ColMap("UserId").SetMaxSize(26)
    21  		table.ColMap("PostId").SetMaxSize(26)
    22  		table.ColMap("EmojiName").SetMaxSize(64)
    23  	}
    24  }
    25  
    26  func (s *SqlSupplier) ReactionSave(ctx context.Context, reaction *model.Reaction, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
    27  	result := store.NewSupplierResult()
    28  
    29  	reaction.PreSave()
    30  	if result.Err = reaction.IsValid(); result.Err != nil {
    31  		return result
    32  	}
    33  
    34  	if transaction, err := s.GetMaster().Begin(); err != nil {
    35  		result.Err = model.NewAppError("SqlReactionStore.Save", "store.sql_reaction.save.begin.app_error", nil, err.Error(), http.StatusInternalServerError)
    36  	} else {
    37  		defer finalizeTransaction(transaction)
    38  		err := saveReactionAndUpdatePost(transaction, reaction)
    39  
    40  		if err != nil {
    41  			// We don't consider duplicated save calls as an error
    42  			if !IsUniqueConstraintError(err, []string{"reactions_pkey", "PRIMARY"}) {
    43  				result.Err = model.NewAppError("SqlPreferenceStore.Save", "store.sql_reaction.save.save.app_error", nil, err.Error(), http.StatusBadRequest)
    44  			}
    45  		} else {
    46  			if err := transaction.Commit(); err != nil {
    47  				result.Err = model.NewAppError("SqlPreferenceStore.Save", "store.sql_reaction.save.commit.app_error", nil, err.Error(), http.StatusInternalServerError)
    48  			}
    49  		}
    50  
    51  		if result.Err == nil {
    52  			result.Data = reaction
    53  		}
    54  	}
    55  
    56  	return result
    57  }
    58  
    59  func (s *SqlSupplier) ReactionDelete(ctx context.Context, reaction *model.Reaction, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
    60  	result := store.NewSupplierResult()
    61  
    62  	if transaction, err := s.GetMaster().Begin(); err != nil {
    63  		result.Err = model.NewAppError("SqlReactionStore.Delete", "store.sql_reaction.delete.begin.app_error", nil, err.Error(), http.StatusInternalServerError)
    64  	} else {
    65  		defer finalizeTransaction(transaction)
    66  		err := deleteReactionAndUpdatePost(transaction, reaction)
    67  
    68  		if err != nil {
    69  			result.Err = model.NewAppError("SqlPreferenceStore.Delete", "store.sql_reaction.delete.app_error", nil, err.Error(), http.StatusInternalServerError)
    70  		} else if err := transaction.Commit(); err != nil {
    71  			result.Err = model.NewAppError("SqlPreferenceStore.Delete", "store.sql_reaction.delete.commit.app_error", nil, err.Error(), http.StatusInternalServerError)
    72  		} else {
    73  			result.Data = reaction
    74  		}
    75  	}
    76  
    77  	return result
    78  }
    79  
    80  func (s *SqlSupplier) ReactionGetForPost(ctx context.Context, postId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
    81  	result := store.NewSupplierResult()
    82  
    83  	var reactions []*model.Reaction
    84  
    85  	if _, err := s.GetReplica().Select(&reactions,
    86  		`SELECT
    87  				*
    88  			FROM
    89  				Reactions
    90  			WHERE
    91  				PostId = :PostId
    92  			ORDER BY
    93  				CreateAt`, map[string]interface{}{"PostId": postId}); err != nil {
    94  		result.Err = model.NewAppError("SqlReactionStore.GetForPost", "store.sql_reaction.get_for_post.app_error", nil, "", http.StatusInternalServerError)
    95  	} else {
    96  		result.Data = reactions
    97  	}
    98  
    99  	return result
   100  }
   101  
   102  func (s *SqlSupplier) ReactionsBulkGetForPosts(ctx context.Context, postIds []string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   103  	result := store.NewSupplierResult()
   104  
   105  	keys, params := MapStringsToQueryParams(postIds, "postId")
   106  	var reactions []*model.Reaction
   107  
   108  	if _, err := s.GetReplica().Select(&reactions, `SELECT
   109  				*
   110  			FROM
   111  				Reactions
   112  			WHERE
   113  				PostId IN `+keys+`
   114  			ORDER BY
   115  				CreateAt`, params); err != nil {
   116  		result.Err = model.NewAppError("SqlReactionStore.GetForPost", "store.sql_reaction.bulk_get_for_post_ids.app_error", nil, "", http.StatusInternalServerError)
   117  	} else {
   118  		result.Data = reactions
   119  	}
   120  
   121  	return result
   122  }
   123  
   124  func (s *SqlSupplier) ReactionDeleteAllWithEmojiName(ctx context.Context, emojiName string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   125  	result := store.NewSupplierResult()
   126  
   127  	var reactions []*model.Reaction
   128  
   129  	if _, err := s.GetReplica().Select(&reactions,
   130  		`SELECT
   131  				*
   132  			FROM
   133  				Reactions
   134  			WHERE
   135  				EmojiName = :EmojiName`, map[string]interface{}{"EmojiName": emojiName}); err != nil {
   136  		result.Err = model.NewAppError("SqlReactionStore.DeleteAllWithEmojiName",
   137  			"store.sql_reaction.delete_all_with_emoji_name.get_reactions.app_error", nil,
   138  			"emoji_name="+emojiName+", error="+err.Error(), http.StatusInternalServerError)
   139  		return result
   140  	}
   141  
   142  	if _, err := s.GetMaster().Exec(
   143  		`DELETE FROM
   144  				Reactions
   145  			WHERE
   146  				EmojiName = :EmojiName`, map[string]interface{}{"EmojiName": emojiName}); err != nil {
   147  		result.Err = model.NewAppError("SqlReactionStore.DeleteAllWithEmojiName",
   148  			"store.sql_reaction.delete_all_with_emoji_name.delete_reactions.app_error", nil,
   149  			"emoji_name="+emojiName+", error="+err.Error(), http.StatusInternalServerError)
   150  		return result
   151  	}
   152  
   153  	for _, reaction := range reactions {
   154  		if _, err := s.GetMaster().Exec(UPDATE_POST_HAS_REACTIONS_ON_DELETE_QUERY,
   155  			map[string]interface{}{"PostId": reaction.PostId, "UpdateAt": model.GetMillis()}); err != nil {
   156  			mlog.Warn(fmt.Sprintf("Unable to update Post.HasReactions while removing reactions post_id=%v, error=%v", reaction.PostId, err.Error()))
   157  		}
   158  	}
   159  
   160  	return result
   161  }
   162  
   163  func (s *SqlSupplier) ReactionPermanentDeleteBatch(ctx context.Context, endTime int64, limit int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   164  	result := store.NewSupplierResult()
   165  
   166  	var query string
   167  	if s.DriverName() == "postgres" {
   168  		query = "DELETE from Reactions WHERE CreateAt = any (array (SELECT CreateAt FROM Reactions WHERE CreateAt < :EndTime LIMIT :Limit))"
   169  	} else {
   170  		query = "DELETE from Reactions WHERE CreateAt < :EndTime LIMIT :Limit"
   171  	}
   172  
   173  	sqlResult, err := s.GetMaster().Exec(query, map[string]interface{}{"EndTime": endTime, "Limit": limit})
   174  	if err != nil {
   175  		result.Err = model.NewAppError("SqlReactionStore.PermanentDeleteBatch", "store.sql_reaction.permanent_delete_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError)
   176  	} else {
   177  		rowsAffected, err1 := sqlResult.RowsAffected()
   178  		if err1 != nil {
   179  			result.Err = model.NewAppError("SqlReactionStore.PermanentDeleteBatch", "store.sql_reaction.permanent_delete_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError)
   180  			result.Data = int64(0)
   181  		} else {
   182  			result.Data = rowsAffected
   183  		}
   184  	}
   185  
   186  	return result
   187  }
   188  
   189  func saveReactionAndUpdatePost(transaction *gorp.Transaction, reaction *model.Reaction) error {
   190  	if err := transaction.Insert(reaction); err != nil {
   191  		return err
   192  	}
   193  
   194  	return updatePostForReactionsOnInsert(transaction, reaction.PostId)
   195  }
   196  
   197  func deleteReactionAndUpdatePost(transaction *gorp.Transaction, reaction *model.Reaction) error {
   198  	if _, err := transaction.Exec(
   199  		`DELETE FROM
   200  			Reactions
   201  		WHERE
   202  			PostId = :PostId AND
   203  			UserId = :UserId AND
   204  			EmojiName = :EmojiName`,
   205  		map[string]interface{}{"PostId": reaction.PostId, "UserId": reaction.UserId, "EmojiName": reaction.EmojiName}); err != nil {
   206  		return err
   207  	}
   208  
   209  	return updatePostForReactionsOnDelete(transaction, reaction.PostId)
   210  }
   211  
   212  const (
   213  	UPDATE_POST_HAS_REACTIONS_ON_DELETE_QUERY = `UPDATE
   214  			Posts
   215  		SET
   216  			UpdateAt = :UpdateAt,
   217  			HasReactions = (SELECT count(0) > 0 FROM Reactions WHERE PostId = :PostId)
   218  		WHERE
   219  			Id = :PostId`
   220  )
   221  
   222  func updatePostForReactionsOnDelete(transaction *gorp.Transaction, postId string) error {
   223  	updateAt := model.GetMillis()
   224  	_, err := transaction.Exec(UPDATE_POST_HAS_REACTIONS_ON_DELETE_QUERY, map[string]interface{}{"PostId": postId, "UpdateAt": updateAt})
   225  	return err
   226  }
   227  
   228  func updatePostForReactionsOnInsert(transaction *gorp.Transaction, postId string) error {
   229  	_, err := transaction.Exec(
   230  		`UPDATE
   231  			Posts
   232  		SET
   233  			HasReactions = True,
   234  			UpdateAt = :UpdateAt
   235  		WHERE
   236  			Id = :PostId`,
   237  		map[string]interface{}{"PostId": postId, "UpdateAt": model.GetMillis()})
   238  
   239  	return err
   240  }