github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/store/sqlstore/integrity.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	sq "github.com/Masterminds/squirrel"
     8  
     9  	"github.com/mattermost/mattermost-server/v5/mlog"
    10  	"github.com/mattermost/mattermost-server/v5/model"
    11  )
    12  
    13  type relationalCheckConfig struct {
    14  	parentName         string
    15  	parentIdAttr       string
    16  	childName          string
    17  	childIdAttr        string
    18  	canParentIdBeEmpty bool
    19  	sortRecords        bool
    20  	filter             interface{}
    21  }
    22  
    23  func getOrphanedRecords(ss *SqlStore, cfg relationalCheckConfig) ([]model.OrphanedRecord, error) {
    24  	var records []model.OrphanedRecord
    25  
    26  	sub := ss.getQueryBuilder().
    27  		Select("TRUE").
    28  		From(cfg.parentName + " AS PT").
    29  		Prefix("NOT EXISTS (").
    30  		Suffix(")").
    31  		Where("PT.id = CT." + cfg.parentIdAttr)
    32  
    33  	main := ss.getQueryBuilder().
    34  		Select().
    35  		Column("CT." + cfg.parentIdAttr + " AS ParentId").
    36  		From(cfg.childName + " AS CT").
    37  		Where(sub)
    38  
    39  	if cfg.childIdAttr != "" {
    40  		main = main.Column("CT." + cfg.childIdAttr + " AS ChildId")
    41  	}
    42  
    43  	if cfg.canParentIdBeEmpty {
    44  		main = main.Where(sq.NotEq{"CT." + cfg.parentIdAttr: ""})
    45  	}
    46  
    47  	if cfg.filter != nil {
    48  		main = main.Where(cfg.filter)
    49  	}
    50  
    51  	if cfg.sortRecords {
    52  		main = main.OrderBy("CT." + cfg.parentIdAttr)
    53  	}
    54  
    55  	query, args, _ := main.ToSql()
    56  
    57  	_, err := ss.GetMaster().Select(&records, query, args...)
    58  
    59  	return records, err
    60  }
    61  
    62  func checkParentChildIntegrity(ss *SqlStore, config relationalCheckConfig) model.IntegrityCheckResult {
    63  	var result model.IntegrityCheckResult
    64  	var data model.RelationalIntegrityCheckData
    65  
    66  	config.sortRecords = true
    67  	data.Records, result.Err = getOrphanedRecords(ss, config)
    68  	if result.Err != nil {
    69  		mlog.Error("Error while getting orphaned records", mlog.Err(result.Err))
    70  		return result
    71  	}
    72  	data.ParentName = config.parentName
    73  	data.ChildName = config.childName
    74  	data.ParentIdAttr = config.parentIdAttr
    75  	data.ChildIdAttr = config.childIdAttr
    76  	result.Data = data
    77  
    78  	return result
    79  }
    80  
    81  func checkChannelsCommandWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
    82  	return checkParentChildIntegrity(ss, relationalCheckConfig{
    83  		parentName:   "Channels",
    84  		parentIdAttr: "ChannelId",
    85  		childName:    "CommandWebhooks",
    86  		childIdAttr:  "Id",
    87  	})
    88  }
    89  
    90  func checkChannelsChannelMemberHistoryIntegrity(ss *SqlStore) model.IntegrityCheckResult {
    91  	return checkParentChildIntegrity(ss, relationalCheckConfig{
    92  		parentName:   "Channels",
    93  		parentIdAttr: "ChannelId",
    94  		childName:    "ChannelMemberHistory",
    95  		childIdAttr:  "",
    96  	})
    97  }
    98  
    99  func checkChannelsChannelMembersIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   100  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   101  		parentName:   "Channels",
   102  		parentIdAttr: "ChannelId",
   103  		childName:    "ChannelMembers",
   104  		childIdAttr:  "",
   105  	})
   106  }
   107  
   108  func checkChannelsIncomingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   109  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   110  		parentName:   "Channels",
   111  		parentIdAttr: "ChannelId",
   112  		childName:    "IncomingWebhooks",
   113  		childIdAttr:  "Id",
   114  	})
   115  }
   116  
   117  func checkChannelsOutgoingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   118  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   119  		parentName:   "Channels",
   120  		parentIdAttr: "ChannelId",
   121  		childName:    "OutgoingWebhooks",
   122  		childIdAttr:  "Id",
   123  	})
   124  }
   125  
   126  func checkChannelsPostsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   127  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   128  		parentName:   "Channels",
   129  		parentIdAttr: "ChannelId",
   130  		childName:    "Posts",
   131  		childIdAttr:  "Id",
   132  	})
   133  }
   134  
   135  func checkCommandsCommandWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   136  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   137  		parentName:   "Commands",
   138  		parentIdAttr: "CommandId",
   139  		childName:    "CommandWebhooks",
   140  		childIdAttr:  "Id",
   141  	})
   142  }
   143  
   144  func checkPostsFileInfoIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   145  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   146  		parentName:   "Posts",
   147  		parentIdAttr: "PostId",
   148  		childName:    "FileInfo",
   149  		childIdAttr:  "Id",
   150  	})
   151  }
   152  
   153  func checkPostsPostsParentIdIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   154  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   155  		parentName:         "Posts",
   156  		parentIdAttr:       "ParentId",
   157  		childName:          "Posts",
   158  		childIdAttr:        "Id",
   159  		canParentIdBeEmpty: true,
   160  	})
   161  }
   162  
   163  func checkPostsPostsRootIdIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   164  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   165  		parentName:         "Posts",
   166  		parentIdAttr:       "RootId",
   167  		childName:          "Posts",
   168  		childIdAttr:        "Id",
   169  		canParentIdBeEmpty: true,
   170  	})
   171  }
   172  
   173  func checkPostsReactionsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   174  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   175  		parentName:   "Posts",
   176  		parentIdAttr: "PostId",
   177  		childName:    "Reactions",
   178  		childIdAttr:  "",
   179  	})
   180  }
   181  
   182  func checkSchemesChannelsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   183  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   184  		parentName:         "Schemes",
   185  		parentIdAttr:       "SchemeId",
   186  		childName:          "Channels",
   187  		childIdAttr:        "Id",
   188  		canParentIdBeEmpty: true,
   189  	})
   190  }
   191  
   192  func checkSchemesTeamsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   193  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   194  		parentName:         "Schemes",
   195  		parentIdAttr:       "SchemeId",
   196  		childName:          "Teams",
   197  		childIdAttr:        "Id",
   198  		canParentIdBeEmpty: true,
   199  	})
   200  }
   201  
   202  func checkSessionsAuditsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   203  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   204  		parentName:         "Sessions",
   205  		parentIdAttr:       "SessionId",
   206  		childName:          "Audits",
   207  		childIdAttr:        "Id",
   208  		canParentIdBeEmpty: true,
   209  	})
   210  }
   211  
   212  func checkTeamsChannelsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   213  	res1 := checkParentChildIntegrity(ss, relationalCheckConfig{
   214  		parentName:   "Teams",
   215  		parentIdAttr: "TeamId",
   216  		childName:    "Channels",
   217  		childIdAttr:  "Id",
   218  		filter:       sq.NotEq{"CT.Type": []string{model.CHANNEL_DIRECT, model.CHANNEL_GROUP}},
   219  	})
   220  	res2 := checkParentChildIntegrity(ss, relationalCheckConfig{
   221  		parentName:         "Teams",
   222  		parentIdAttr:       "TeamId",
   223  		childName:          "Channels",
   224  		childIdAttr:        "Id",
   225  		canParentIdBeEmpty: true,
   226  		filter:             sq.Eq{"CT.Type": []string{model.CHANNEL_DIRECT, model.CHANNEL_GROUP}},
   227  	})
   228  	data1 := res1.Data.(model.RelationalIntegrityCheckData)
   229  	data2 := res2.Data.(model.RelationalIntegrityCheckData)
   230  	data1.Records = append(data1.Records, data2.Records...)
   231  	res1.Data = data1
   232  	return res1
   233  }
   234  
   235  func checkTeamsCommandsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   236  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   237  		parentName:   "Teams",
   238  		parentIdAttr: "TeamId",
   239  		childName:    "Commands",
   240  		childIdAttr:  "Id",
   241  	})
   242  }
   243  
   244  func checkTeamsIncomingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   245  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   246  		parentName:   "Teams",
   247  		parentIdAttr: "TeamId",
   248  		childName:    "IncomingWebhooks",
   249  		childIdAttr:  "Id",
   250  	})
   251  }
   252  
   253  func checkTeamsOutgoingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   254  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   255  		parentName:   "Teams",
   256  		parentIdAttr: "TeamId",
   257  		childName:    "OutgoingWebhooks",
   258  		childIdAttr:  "Id",
   259  	})
   260  }
   261  
   262  func checkTeamsTeamMembersIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   263  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   264  		parentName:   "Teams",
   265  		parentIdAttr: "TeamId",
   266  		childName:    "TeamMembers",
   267  		childIdAttr:  "",
   268  	})
   269  }
   270  
   271  func checkUsersAuditsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   272  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   273  		parentName:         "Users",
   274  		parentIdAttr:       "UserId",
   275  		childName:          "Audits",
   276  		childIdAttr:        "Id",
   277  		canParentIdBeEmpty: true,
   278  	})
   279  }
   280  
   281  func checkUsersCommandWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   282  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   283  		parentName:   "Users",
   284  		parentIdAttr: "UserId",
   285  		childName:    "CommandWebhooks",
   286  		childIdAttr:  "Id",
   287  	})
   288  }
   289  
   290  func checkUsersChannelMemberHistoryIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   291  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   292  		parentName:   "Users",
   293  		parentIdAttr: "UserId",
   294  		childName:    "ChannelMemberHistory",
   295  		childIdAttr:  "",
   296  	})
   297  }
   298  
   299  func checkUsersChannelMembersIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   300  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   301  		parentName:   "Users",
   302  		parentIdAttr: "UserId",
   303  		childName:    "ChannelMembers",
   304  		childIdAttr:  "",
   305  	})
   306  }
   307  
   308  func checkUsersChannelsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   309  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   310  		parentName:         "Users",
   311  		parentIdAttr:       "CreatorId",
   312  		childName:          "Channels",
   313  		childIdAttr:        "Id",
   314  		canParentIdBeEmpty: true,
   315  	})
   316  }
   317  
   318  func checkUsersCommandsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   319  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   320  		parentName:   "Users",
   321  		parentIdAttr: "CreatorId",
   322  		childName:    "Commands",
   323  		childIdAttr:  "Id",
   324  	})
   325  }
   326  
   327  func checkUsersCompliancesIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   328  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   329  		parentName:   "Users",
   330  		parentIdAttr: "UserId",
   331  		childName:    "Compliances",
   332  		childIdAttr:  "Id",
   333  	})
   334  }
   335  
   336  func checkUsersEmojiIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   337  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   338  		parentName:   "Users",
   339  		parentIdAttr: "CreatorId",
   340  		childName:    "Emoji",
   341  		childIdAttr:  "Id",
   342  	})
   343  }
   344  
   345  func checkUsersFileInfoIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   346  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   347  		parentName:   "Users",
   348  		parentIdAttr: "CreatorId",
   349  		childName:    "FileInfo",
   350  		childIdAttr:  "Id",
   351  	})
   352  }
   353  
   354  func checkUsersIncomingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   355  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   356  		parentName:   "Users",
   357  		parentIdAttr: "UserId",
   358  		childName:    "IncomingWebhooks",
   359  		childIdAttr:  "Id",
   360  	})
   361  }
   362  
   363  func checkUsersOAuthAccessDataIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   364  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   365  		parentName:   "Users",
   366  		parentIdAttr: "UserId",
   367  		childName:    "OAuthAccessData",
   368  		childIdAttr:  "Token",
   369  	})
   370  }
   371  
   372  func checkUsersOAuthAppsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   373  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   374  		parentName:   "Users",
   375  		parentIdAttr: "CreatorId",
   376  		childName:    "OAuthApps",
   377  		childIdAttr:  "Id",
   378  	})
   379  }
   380  
   381  func checkUsersOAuthAuthDataIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   382  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   383  		parentName:   "Users",
   384  		parentIdAttr: "UserId",
   385  		childName:    "OAuthAuthData",
   386  		childIdAttr:  "Code",
   387  	})
   388  }
   389  
   390  func checkUsersOutgoingWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   391  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   392  		parentName:   "Users",
   393  		parentIdAttr: "CreatorId",
   394  		childName:    "OutgoingWebhooks",
   395  		childIdAttr:  "Id",
   396  	})
   397  }
   398  
   399  func checkUsersPostsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   400  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   401  		parentName:   "Users",
   402  		parentIdAttr: "UserId",
   403  		childName:    "Posts",
   404  		childIdAttr:  "Id",
   405  	})
   406  }
   407  
   408  func checkUsersPreferencesIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   409  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   410  		parentName:   "Users",
   411  		parentIdAttr: "UserId",
   412  		childName:    "Preferences",
   413  		childIdAttr:  "",
   414  	})
   415  }
   416  
   417  func checkUsersReactionsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   418  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   419  		parentName:   "Users",
   420  		parentIdAttr: "UserId",
   421  		childName:    "Reactions",
   422  		childIdAttr:  "",
   423  	})
   424  }
   425  
   426  func checkUsersSessionsIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   427  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   428  		parentName:   "Users",
   429  		parentIdAttr: "UserId",
   430  		childName:    "Sessions",
   431  		childIdAttr:  "Id",
   432  	})
   433  }
   434  
   435  func checkUsersStatusIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   436  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   437  		parentName:   "Users",
   438  		parentIdAttr: "UserId",
   439  		childName:    "Status",
   440  		childIdAttr:  "",
   441  	})
   442  }
   443  
   444  func checkUsersTeamMembersIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   445  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   446  		parentName:   "Users",
   447  		parentIdAttr: "UserId",
   448  		childName:    "TeamMembers",
   449  		childIdAttr:  "",
   450  	})
   451  }
   452  
   453  func checkUsersUserAccessTokensIntegrity(ss *SqlStore) model.IntegrityCheckResult {
   454  	return checkParentChildIntegrity(ss, relationalCheckConfig{
   455  		parentName:   "Users",
   456  		parentIdAttr: "UserId",
   457  		childName:    "UserAccessTokens",
   458  		childIdAttr:  "Id",
   459  	})
   460  }
   461  
   462  func checkChannelsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {
   463  	results <- checkChannelsCommandWebhooksIntegrity(ss)
   464  	results <- checkChannelsChannelMemberHistoryIntegrity(ss)
   465  	results <- checkChannelsChannelMembersIntegrity(ss)
   466  	results <- checkChannelsIncomingWebhooksIntegrity(ss)
   467  	results <- checkChannelsOutgoingWebhooksIntegrity(ss)
   468  	results <- checkChannelsPostsIntegrity(ss)
   469  }
   470  
   471  func checkCommandsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {
   472  	results <- checkCommandsCommandWebhooksIntegrity(ss)
   473  }
   474  
   475  func checkPostsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {
   476  	results <- checkPostsFileInfoIntegrity(ss)
   477  	results <- checkPostsPostsParentIdIntegrity(ss)
   478  	results <- checkPostsPostsRootIdIntegrity(ss)
   479  	results <- checkPostsReactionsIntegrity(ss)
   480  }
   481  
   482  func checkSchemesIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {
   483  	results <- checkSchemesChannelsIntegrity(ss)
   484  	results <- checkSchemesTeamsIntegrity(ss)
   485  }
   486  
   487  func checkSessionsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {
   488  	results <- checkSessionsAuditsIntegrity(ss)
   489  }
   490  
   491  func checkTeamsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {
   492  	results <- checkTeamsChannelsIntegrity(ss)
   493  	results <- checkTeamsCommandsIntegrity(ss)
   494  	results <- checkTeamsIncomingWebhooksIntegrity(ss)
   495  	results <- checkTeamsOutgoingWebhooksIntegrity(ss)
   496  	results <- checkTeamsTeamMembersIntegrity(ss)
   497  }
   498  
   499  func checkUsersIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {
   500  	results <- checkUsersAuditsIntegrity(ss)
   501  	results <- checkUsersCommandWebhooksIntegrity(ss)
   502  	results <- checkUsersChannelMemberHistoryIntegrity(ss)
   503  	results <- checkUsersChannelMembersIntegrity(ss)
   504  	results <- checkUsersChannelsIntegrity(ss)
   505  	results <- checkUsersCommandsIntegrity(ss)
   506  	results <- checkUsersCompliancesIntegrity(ss)
   507  	results <- checkUsersEmojiIntegrity(ss)
   508  	results <- checkUsersFileInfoIntegrity(ss)
   509  	results <- checkUsersIncomingWebhooksIntegrity(ss)
   510  	results <- checkUsersOAuthAccessDataIntegrity(ss)
   511  	results <- checkUsersOAuthAppsIntegrity(ss)
   512  	results <- checkUsersOAuthAuthDataIntegrity(ss)
   513  	results <- checkUsersOutgoingWebhooksIntegrity(ss)
   514  	results <- checkUsersPostsIntegrity(ss)
   515  	results <- checkUsersPreferencesIntegrity(ss)
   516  	results <- checkUsersReactionsIntegrity(ss)
   517  	results <- checkUsersSessionsIntegrity(ss)
   518  	results <- checkUsersStatusIntegrity(ss)
   519  	results <- checkUsersTeamMembersIntegrity(ss)
   520  	results <- checkUsersUserAccessTokensIntegrity(ss)
   521  }
   522  
   523  func CheckRelationalIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {
   524  	mlog.Info("Starting relational integrity checks...")
   525  	checkChannelsIntegrity(ss, results)
   526  	checkCommandsIntegrity(ss, results)
   527  	checkPostsIntegrity(ss, results)
   528  	checkSchemesIntegrity(ss, results)
   529  	checkSessionsIntegrity(ss, results)
   530  	checkTeamsIntegrity(ss, results)
   531  	checkUsersIntegrity(ss, results)
   532  	mlog.Info("Done with relational integrity checks")
   533  	close(results)
   534  }