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 }