github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/store/sqlstore/webhook_store.go (about)

     1  // Copyright (c) 2015-present Xenia, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"database/sql"
     8  	"net/http"
     9  
    10  	"github.com/xzl8028/xenia-server/einterfaces"
    11  	"github.com/xzl8028/xenia-server/model"
    12  	"github.com/xzl8028/xenia-server/store"
    13  	"github.com/xzl8028/xenia-server/utils"
    14  )
    15  
    16  type SqlWebhookStore struct {
    17  	SqlStore
    18  	metrics einterfaces.MetricsInterface
    19  }
    20  
    21  const (
    22  	WEBHOOK_CACHE_SIZE = 25000
    23  	WEBHOOK_CACHE_SEC  = 900 // 15 minutes
    24  )
    25  
    26  var webhookCache = utils.NewLru(WEBHOOK_CACHE_SIZE)
    27  
    28  func (s SqlWebhookStore) ClearCaches() {
    29  	webhookCache.Purge()
    30  
    31  	if s.metrics != nil {
    32  		s.metrics.IncrementMemCacheInvalidationCounter("Webhook - Purge")
    33  	}
    34  }
    35  
    36  func NewSqlWebhookStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.WebhookStore {
    37  	s := &SqlWebhookStore{
    38  		SqlStore: sqlStore,
    39  		metrics:  metrics,
    40  	}
    41  
    42  	for _, db := range sqlStore.GetAllConns() {
    43  		table := db.AddTableWithName(model.IncomingWebhook{}, "IncomingWebhooks").SetKeys(false, "Id")
    44  		table.ColMap("Id").SetMaxSize(26)
    45  		table.ColMap("UserId").SetMaxSize(26)
    46  		table.ColMap("ChannelId").SetMaxSize(26)
    47  		table.ColMap("TeamId").SetMaxSize(26)
    48  		table.ColMap("DisplayName").SetMaxSize(64)
    49  		table.ColMap("Description").SetMaxSize(500)
    50  
    51  		tableo := db.AddTableWithName(model.OutgoingWebhook{}, "OutgoingWebhooks").SetKeys(false, "Id")
    52  		tableo.ColMap("Id").SetMaxSize(26)
    53  		tableo.ColMap("Token").SetMaxSize(26)
    54  		tableo.ColMap("CreatorId").SetMaxSize(26)
    55  		tableo.ColMap("ChannelId").SetMaxSize(26)
    56  		tableo.ColMap("TeamId").SetMaxSize(26)
    57  		tableo.ColMap("TriggerWords").SetMaxSize(1024)
    58  		tableo.ColMap("CallbackURLs").SetMaxSize(1024)
    59  		tableo.ColMap("DisplayName").SetMaxSize(64)
    60  		tableo.ColMap("Description").SetMaxSize(500)
    61  		tableo.ColMap("ContentType").SetMaxSize(128)
    62  		tableo.ColMap("TriggerWhen").SetMaxSize(1)
    63  		tableo.ColMap("Username").SetMaxSize(64)
    64  		tableo.ColMap("IconURL").SetMaxSize(1024)
    65  	}
    66  
    67  	return s
    68  }
    69  
    70  func (s SqlWebhookStore) CreateIndexesIfNotExists() {
    71  	s.CreateIndexIfNotExists("idx_incoming_webhook_user_id", "IncomingWebhooks", "UserId")
    72  	s.CreateIndexIfNotExists("idx_incoming_webhook_team_id", "IncomingWebhooks", "TeamId")
    73  	s.CreateIndexIfNotExists("idx_outgoing_webhook_team_id", "OutgoingWebhooks", "TeamId")
    74  
    75  	s.CreateIndexIfNotExists("idx_incoming_webhook_update_at", "IncomingWebhooks", "UpdateAt")
    76  	s.CreateIndexIfNotExists("idx_incoming_webhook_create_at", "IncomingWebhooks", "CreateAt")
    77  	s.CreateIndexIfNotExists("idx_incoming_webhook_delete_at", "IncomingWebhooks", "DeleteAt")
    78  
    79  	s.CreateIndexIfNotExists("idx_outgoing_webhook_update_at", "OutgoingWebhooks", "UpdateAt")
    80  	s.CreateIndexIfNotExists("idx_outgoing_webhook_create_at", "OutgoingWebhooks", "CreateAt")
    81  	s.CreateIndexIfNotExists("idx_outgoing_webhook_delete_at", "OutgoingWebhooks", "DeleteAt")
    82  }
    83  
    84  func (s SqlWebhookStore) InvalidateWebhookCache(webhookId string) {
    85  	webhookCache.Remove(webhookId)
    86  	if s.metrics != nil {
    87  		s.metrics.IncrementMemCacheInvalidationCounter("Webhook - Remove by WebhookId")
    88  	}
    89  }
    90  
    91  func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) (*model.IncomingWebhook, *model.AppError) {
    92  
    93  	if len(webhook.Id) > 0 {
    94  		return nil, model.NewAppError("SqlWebhookStore.SaveIncoming", "store.sql_webhooks.save_incoming.existing.app_error", nil, "id="+webhook.Id, http.StatusBadRequest)
    95  	}
    96  
    97  	webhook.PreSave()
    98  	if err := webhook.IsValid(); err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	if err := s.GetMaster().Insert(webhook); err != nil {
   103  		return nil, model.NewAppError("SqlWebhookStore.SaveIncoming", "store.sql_webhooks.save_incoming.app_error", nil, "id="+webhook.Id+", "+err.Error(), http.StatusInternalServerError)
   104  	}
   105  
   106  	return webhook, nil
   107  
   108  }
   109  
   110  func (s SqlWebhookStore) UpdateIncoming(hook *model.IncomingWebhook) (*model.IncomingWebhook, *model.AppError) {
   111  	hook.UpdateAt = model.GetMillis()
   112  
   113  	if _, err := s.GetMaster().Update(hook); err != nil {
   114  		return nil, model.NewAppError("SqlWebhookStore.UpdateIncoming", "store.sql_webhooks.update_incoming.app_error", nil, "id="+hook.Id+", "+err.Error(), http.StatusInternalServerError)
   115  	}
   116  	return hook, nil
   117  }
   118  
   119  func (s SqlWebhookStore) GetIncoming(id string, allowFromCache bool) (*model.IncomingWebhook, *model.AppError) {
   120  	if allowFromCache {
   121  		if cacheItem, ok := webhookCache.Get(id); ok {
   122  			if s.metrics != nil {
   123  				s.metrics.IncrementMemCacheHitCounter("Webhook")
   124  			}
   125  			return cacheItem.(*model.IncomingWebhook), nil
   126  		}
   127  		if s.metrics != nil {
   128  			s.metrics.IncrementMemCacheMissCounter("Webhook")
   129  		}
   130  	}
   131  
   132  	var webhook model.IncomingWebhook
   133  	if err := s.GetReplica().SelectOne(&webhook, "SELECT * FROM IncomingWebhooks WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}); err != nil {
   134  		if err == sql.ErrNoRows {
   135  			return nil, model.NewAppError("SqlWebhookStore.GetIncoming", "store.sql_webhooks.get_incoming.app_error", nil, "id="+id+", err="+err.Error(), http.StatusNotFound)
   136  		}
   137  		return nil, model.NewAppError("SqlWebhookStore.GetIncoming", "store.sql_webhooks.get_incoming.app_error", nil, "id="+id+", err="+err.Error(), http.StatusInternalServerError)
   138  	}
   139  
   140  	webhookCache.AddWithExpiresInSecs(id, &webhook, WEBHOOK_CACHE_SEC)
   141  
   142  	return &webhook, nil
   143  }
   144  
   145  func (s SqlWebhookStore) DeleteIncoming(webhookId string, time int64) *model.AppError {
   146  	_, err := s.GetMaster().Exec("Update IncomingWebhooks SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :Id", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": webhookId})
   147  	if err != nil {
   148  		return model.NewAppError("SqlWebhookStore.DeleteIncoming", "store.sql_webhooks.delete_incoming.app_error", nil, "id="+webhookId+", err="+err.Error(), http.StatusInternalServerError)
   149  	}
   150  
   151  	s.InvalidateWebhookCache(webhookId)
   152  	return nil
   153  }
   154  
   155  func (s SqlWebhookStore) PermanentDeleteIncomingByUser(userId string) *model.AppError {
   156  	_, err := s.GetMaster().Exec("DELETE FROM IncomingWebhooks WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
   157  	if err != nil {
   158  		return model.NewAppError("SqlWebhookStore.DeleteIncomingByUser", "store.sql_webhooks.permanent_delete_incoming_by_user.app_error", nil, "id="+userId+", err="+err.Error(), http.StatusInternalServerError)
   159  	}
   160  
   161  	s.ClearCaches()
   162  	return nil
   163  }
   164  
   165  func (s SqlWebhookStore) PermanentDeleteIncomingByChannel(channelId string) *model.AppError {
   166  	_, err := s.GetMaster().Exec("DELETE FROM IncomingWebhooks WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId})
   167  	if err != nil {
   168  		return model.NewAppError("SqlWebhookStore.DeleteIncomingByChannel", "store.sql_webhooks.permanent_delete_incoming_by_channel.app_error", nil, "id="+channelId+", err="+err.Error(), http.StatusInternalServerError)
   169  	}
   170  
   171  	s.ClearCaches()
   172  
   173  	return nil
   174  }
   175  
   176  func (s SqlWebhookStore) GetIncomingList(offset, limit int) ([]*model.IncomingWebhook, *model.AppError) {
   177  	var webhooks []*model.IncomingWebhook
   178  
   179  	if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Limit": limit, "Offset": offset}); err != nil {
   180  		return nil, model.NewAppError("SqlWebhookStore.GetIncomingList", "store.sql_webhooks.get_incoming_by_user.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
   181  	}
   182  
   183  	return webhooks, nil
   184  
   185  }
   186  
   187  func (s SqlWebhookStore) GetIncomingByTeam(teamId string, offset, limit int) ([]*model.IncomingWebhook, *model.AppError) {
   188  	var webhooks []*model.IncomingWebhook
   189  
   190  	if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE TeamId = :TeamId AND DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset}); err != nil {
   191  		return nil, model.NewAppError("SqlWebhookStore.GetIncomingByUser", "store.sql_webhooks.get_incoming_by_user.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError)
   192  	}
   193  
   194  	return webhooks, nil
   195  }
   196  
   197  func (s SqlWebhookStore) GetIncomingByChannel(channelId string) ([]*model.IncomingWebhook, *model.AppError) {
   198  	var webhooks []*model.IncomingWebhook
   199  
   200  	if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE ChannelId = :ChannelId AND DeleteAt = 0", map[string]interface{}{"ChannelId": channelId}); err != nil {
   201  		return nil, model.NewAppError("SqlWebhookStore.GetIncomingByChannel", "store.sql_webhooks.get_incoming_by_channel.app_error", nil, "channelId="+channelId+", err="+err.Error(), http.StatusInternalServerError)
   202  	}
   203  
   204  	return webhooks, nil
   205  }
   206  
   207  func (s SqlWebhookStore) SaveOutgoing(webhook *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.AppError) {
   208  	if len(webhook.Id) > 0 {
   209  		return nil, model.NewAppError("SqlWebhookStore.SaveOutgoing", "store.sql_webhooks.save_outgoing.override.app_error", nil, "id="+webhook.Id, http.StatusBadRequest)
   210  	}
   211  
   212  	webhook.PreSave()
   213  	if err := webhook.IsValid(); err != nil {
   214  		return nil, err
   215  	}
   216  
   217  	if err := s.GetMaster().Insert(webhook); err != nil {
   218  		return nil, model.NewAppError("SqlWebhookStore.SaveOutgoing", "store.sql_webhooks.save_outgoing.app_error", nil, "id="+webhook.Id+", "+err.Error(), http.StatusInternalServerError)
   219  	}
   220  
   221  	return webhook, nil
   222  }
   223  
   224  func (s SqlWebhookStore) GetOutgoing(id string) (*model.OutgoingWebhook, *model.AppError) {
   225  
   226  	var webhook model.OutgoingWebhook
   227  
   228  	if err := s.GetReplica().SelectOne(&webhook, "SELECT * FROM OutgoingWebhooks WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}); err != nil {
   229  		return nil, model.NewAppError("SqlWebhookStore.GetOutgoing", "store.sql_webhooks.get_outgoing.app_error", nil, "id="+id+", err="+err.Error(), http.StatusInternalServerError)
   230  	}
   231  
   232  	return &webhook, nil
   233  }
   234  
   235  func (s SqlWebhookStore) GetOutgoingList(offset, limit int) ([]*model.OutgoingWebhook, *model.AppError) {
   236  	var webhooks []*model.OutgoingWebhook
   237  
   238  	if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM OutgoingWebhooks WHERE DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
   239  		return nil, model.NewAppError("SqlWebhookStore.GetOutgoingList", "store.sql_webhooks.get_outgoing_by_channel.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
   240  	}
   241  
   242  	return webhooks, nil
   243  }
   244  
   245  func (s SqlWebhookStore) GetOutgoingByChannel(channelId string, offset, limit int) ([]*model.OutgoingWebhook, *model.AppError) {
   246  	var webhooks []*model.OutgoingWebhook
   247  
   248  	query := ""
   249  	if limit < 0 || offset < 0 {
   250  		query = "SELECT * FROM OutgoingWebhooks WHERE ChannelId = :ChannelId AND DeleteAt = 0"
   251  	} else {
   252  		query = "SELECT * FROM OutgoingWebhooks WHERE ChannelId = :ChannelId AND DeleteAt = 0 LIMIT :Limit OFFSET :Offset"
   253  	}
   254  
   255  	if _, err := s.GetReplica().Select(&webhooks, query, map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit}); err != nil {
   256  		return nil, model.NewAppError("SqlWebhookStore.GetOutgoingByChannel", "store.sql_webhooks.get_outgoing_by_channel.app_error", nil, "channelId="+channelId+", err="+err.Error(), http.StatusInternalServerError)
   257  	}
   258  
   259  	return webhooks, nil
   260  }
   261  
   262  func (s SqlWebhookStore) GetOutgoingByTeam(teamId string, offset, limit int) ([]*model.OutgoingWebhook, *model.AppError) {
   263  	var webhooks []*model.OutgoingWebhook
   264  
   265  	query := ""
   266  	if limit < 0 || offset < 0 {
   267  		query = "SELECT * FROM OutgoingWebhooks WHERE TeamId = :TeamId AND DeleteAt = 0"
   268  	} else {
   269  		query = "SELECT * FROM OutgoingWebhooks WHERE TeamId = :TeamId AND DeleteAt = 0 LIMIT :Limit OFFSET :Offset"
   270  	}
   271  
   272  	if _, err := s.GetReplica().Select(&webhooks, query, map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil {
   273  		return nil, model.NewAppError("SqlWebhookStore.GetOutgoingByTeam", "store.sql_webhooks.get_outgoing_by_team.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError)
   274  	}
   275  
   276  	return webhooks, nil
   277  }
   278  
   279  func (s SqlWebhookStore) DeleteOutgoing(webhookId string, time int64) *model.AppError {
   280  	_, err := s.GetMaster().Exec("Update OutgoingWebhooks SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :Id", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": webhookId})
   281  	if err != nil {
   282  		return model.NewAppError("SqlWebhookStore.DeleteOutgoing", "store.sql_webhooks.delete_outgoing.app_error", nil, "id="+webhookId+", err="+err.Error(), http.StatusInternalServerError)
   283  	}
   284  
   285  	return nil
   286  }
   287  
   288  func (s SqlWebhookStore) PermanentDeleteOutgoingByUser(userId string) *model.AppError {
   289  	_, err := s.GetMaster().Exec("DELETE FROM OutgoingWebhooks WHERE CreatorId = :UserId", map[string]interface{}{"UserId": userId})
   290  	if err != nil {
   291  		return model.NewAppError("SqlWebhookStore.DeleteOutgoingByUser", "store.sql_webhooks.permanent_delete_outgoing_by_user.app_error", nil, "id="+userId+", err="+err.Error(), http.StatusInternalServerError)
   292  	}
   293  
   294  	return nil
   295  }
   296  
   297  func (s SqlWebhookStore) PermanentDeleteOutgoingByChannel(channelId string) *model.AppError {
   298  	_, err := s.GetMaster().Exec("DELETE FROM OutgoingWebhooks WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId})
   299  	if err != nil {
   300  		return model.NewAppError("SqlWebhookStore.DeleteOutgoingByChannel", "store.sql_webhooks.permanent_delete_outgoing_by_channel.app_error", nil, "id="+channelId+", err="+err.Error(), http.StatusInternalServerError)
   301  	}
   302  
   303  	s.ClearCaches()
   304  
   305  	return nil
   306  }
   307  
   308  func (s SqlWebhookStore) UpdateOutgoing(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.AppError) {
   309  	hook.UpdateAt = model.GetMillis()
   310  
   311  	if _, err := s.GetMaster().Update(hook); err != nil {
   312  		return nil, model.NewAppError("SqlWebhookStore.UpdateOutgoing", "store.sql_webhooks.update_outgoing.app_error", nil, "id="+hook.Id+", "+err.Error(), http.StatusInternalServerError)
   313  	}
   314  
   315  	return hook, nil
   316  }
   317  
   318  func (s SqlWebhookStore) AnalyticsIncomingCount(teamId string) (int64, *model.AppError) {
   319  	query :=
   320  		`SELECT 
   321  			COUNT(*)
   322  		FROM
   323  			IncomingWebhooks
   324  		WHERE
   325  			DeleteAt = 0`
   326  
   327  	if len(teamId) > 0 {
   328  		query += " AND TeamId = :TeamId"
   329  	}
   330  
   331  	v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId})
   332  	if err != nil {
   333  		return 0, model.NewAppError("SqlWebhookStore.AnalyticsIncomingCount", "store.sql_webhooks.analytics_incoming_count.app_error", nil, "team_id="+teamId+", err="+err.Error(), http.StatusInternalServerError)
   334  	}
   335  
   336  	return v, nil
   337  }
   338  
   339  func (s SqlWebhookStore) AnalyticsOutgoingCount(teamId string) (int64, *model.AppError) {
   340  	query :=
   341  		`SELECT 
   342  			COUNT(*)
   343  		FROM
   344  			OutgoingWebhooks
   345  		WHERE
   346  			DeleteAt = 0`
   347  
   348  	if len(teamId) > 0 {
   349  		query += " AND TeamId = :TeamId"
   350  	}
   351  
   352  	v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId})
   353  	if err != nil {
   354  		return 0, model.NewAppError("SqlWebhookStore.AnalyticsOutgoingCount", "store.sql_webhooks.analytics_outgoing_count.app_error", nil, "team_id="+teamId+", err="+err.Error(), http.StatusInternalServerError)
   355  	}
   356  
   357  	return v, nil
   358  }