1
0
mirror of https://github.com/mattermost/focalboard.git synced 2024-12-24 13:43:12 +02:00
focalboard/server/services/store/sqlstore/compliance.go
Doug Lauder 81b0fd8453
Cherry-pick 4285 Compliance export into release-7.8 (#4558)
* fix merge conflicts

* fix linter

---------

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>
2023-02-08 16:12:06 -05:00

242 lines
6.5 KiB
Go

package sqlstore
import (
"database/sql"
sq "github.com/Masterminds/squirrel"
"github.com/mattermost/focalboard/server/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
func (s *SQLStore) getBoardsForCompliance(db sq.BaseRunner, opts model.QueryBoardsForComplianceOptions) ([]*model.Board, bool, error) {
query := s.getQueryBuilder(db).
Select(boardFields("b.")...).
From(s.tablePrefix + "boards as b")
if opts.TeamID != "" {
query = query.Where(sq.Eq{"b.team_id": opts.TeamID})
}
if opts.Page != 0 {
query = query.Offset(uint64(opts.Page * opts.PerPage))
}
if opts.PerPage > 0 {
// N+1 to check if there's a next page for pagination
query = query.Limit(uint64(opts.PerPage) + 1)
}
rows, err := query.Query()
if err != nil {
s.logger.Error(`GetBoardsForCompliance ERROR`, mlog.Err(err))
return nil, false, err
}
defer s.CloseRows(rows)
boards, err := s.boardsFromRows(rows)
if err != nil {
return nil, false, err
}
var hasMore bool
if opts.PerPage > 0 && len(boards) > opts.PerPage {
boards = boards[0:opts.PerPage]
hasMore = true
}
return boards, hasMore, nil
}
func (s *SQLStore) getBoardsComplianceHistory(db sq.BaseRunner, opts model.QueryBoardsComplianceHistoryOptions) ([]*model.BoardHistory, bool, error) {
queryDescendentLastUpdate := s.getQueryBuilder(db).
Select("MAX(blk1.update_at)").
From(s.tablePrefix + "blocks_history as blk1").
Where("blk1.board_id=bh.id")
if !opts.IncludeDeleted {
queryDescendentLastUpdate.Where(sq.Eq{"blk1.delete_at": 0})
}
sqlDescendentLastUpdate, _, _ := queryDescendentLastUpdate.ToSql()
queryDescendentFirstUpdate := s.getQueryBuilder(db).
Select("MIN(blk2.update_at)").
From(s.tablePrefix + "blocks_history as blk2").
Where("blk2.board_id=bh.id")
if !opts.IncludeDeleted {
queryDescendentFirstUpdate.Where(sq.Eq{"blk2.delete_at": 0})
}
sqlDescendentFirstUpdate, _, _ := queryDescendentFirstUpdate.ToSql()
query := s.getQueryBuilder(db).
Select(
"bh.id",
"bh.team_id",
"CASE WHEN bh.delete_at=0 THEN false ELSE true END AS isDeleted",
"COALESCE(("+sqlDescendentLastUpdate+"),0) as decendentLastUpdateAt",
"COALESCE(("+sqlDescendentFirstUpdate+"),0) as decendentFirstUpdateAt",
"bh.created_by",
"bh.modified_by",
).
From(s.tablePrefix + "boards_history as bh")
if !opts.IncludeDeleted {
// filtering out deleted boards; join with boards table to ensure no history
// for deleted boards are returned. Deleted boards won't exist in boards table.
query = query.Join(s.tablePrefix + "boards as b ON b.id=bh.id")
}
query = query.Where(sq.Gt{"bh.update_at": opts.ModifiedSince}).
GroupBy("bh.id", "bh.team_id", "bh.delete_at", "bh.created_by", "bh.modified_by").
OrderBy("decendentLastUpdateAt desc", "bh.id")
if opts.TeamID != "" {
query = query.Where(sq.Eq{"bh.team_id": opts.TeamID})
}
if opts.Page != 0 {
query = query.Offset(uint64(opts.Page * opts.PerPage))
}
if opts.PerPage > 0 {
// N+1 to check if there's a next page for pagination
query = query.Limit(uint64(opts.PerPage) + 1)
}
rows, err := query.Query()
if err != nil {
s.logger.Error(`GetBoardsComplianceHistory ERROR`, mlog.Err(err))
return nil, false, err
}
defer s.CloseRows(rows)
history, err := s.boardsHistoryFromRows(rows)
if err != nil {
return nil, false, err
}
var hasMore bool
if opts.PerPage > 0 && len(history) > opts.PerPage {
history = history[0:opts.PerPage]
hasMore = true
}
return history, hasMore, nil
}
func (s *SQLStore) getBlocksComplianceHistory(db sq.BaseRunner, opts model.QueryBlocksComplianceHistoryOptions) ([]*model.BlockHistory, bool, error) {
query := s.getQueryBuilder(db).
Select(
"bh.id",
"brd.team_id",
"bh.board_id",
"bh.type",
"CASE WHEN bh.delete_at=0 THEN false ELSE true END AS isDeleted",
"max(bh.update_at) as lastUpdateAt",
"min(bh.update_at) as firstUpdateAt",
"bh.created_by",
"bh.modified_by",
).
From(s.tablePrefix + "blocks_history as bh").
Join(s.tablePrefix + "boards_history as brd on brd.id=bh.board_id")
if !opts.IncludeDeleted {
// filtering out deleted blocks; join with blocks table to ensure no history
// for deleted blocks are returned. Deleted blocks won't exist in blocks table.
query = query.Join(s.tablePrefix + "blocks as b ON b.id=bh.id")
}
query = query.Where(sq.Gt{"bh.update_at": opts.ModifiedSince}).
GroupBy("bh.id", "brd.team_id", "bh.board_id", "bh.type", "bh.delete_at", "bh.created_by", "bh.modified_by").
OrderBy("lastUpdateAt desc", "bh.id")
if opts.TeamID != "" {
query = query.Where(sq.Eq{"brd.team_id": opts.TeamID})
}
if opts.BoardID != "" {
query = query.Where(sq.Eq{"bh.board_id": opts.BoardID})
}
if opts.Page != 0 {
query = query.Offset(uint64(opts.Page * opts.PerPage))
}
if opts.PerPage > 0 {
// N+1 to check if there's a next page for pagination
query = query.Limit(uint64(opts.PerPage) + 1)
}
rows, err := query.Query()
if err != nil {
s.logger.Error(`GetBlocksComplianceHistory ERROR`, mlog.Err(err))
return nil, false, err
}
defer s.CloseRows(rows)
history, err := s.blocksHistoryFromRows(rows)
if err != nil {
return nil, false, err
}
var hasMore bool
if opts.PerPage > 0 && len(history) > opts.PerPage {
history = history[0:opts.PerPage]
hasMore = true
}
return history, hasMore, nil
}
func (s *SQLStore) boardsHistoryFromRows(rows *sql.Rows) ([]*model.BoardHistory, error) {
history := []*model.BoardHistory{}
for rows.Next() {
boardHistory := &model.BoardHistory{}
err := rows.Scan(
&boardHistory.ID,
&boardHistory.TeamID,
&boardHistory.IsDeleted,
&boardHistory.DescendantLastUpdateAt,
&boardHistory.DescendantFirstUpdateAt,
&boardHistory.CreatedBy,
&boardHistory.LastModifiedBy,
)
if err != nil {
s.logger.Error("boardsHistoryFromRows scan error", mlog.Err(err))
return nil, err
}
history = append(history, boardHistory)
}
return history, nil
}
func (s *SQLStore) blocksHistoryFromRows(rows *sql.Rows) ([]*model.BlockHistory, error) {
history := []*model.BlockHistory{}
for rows.Next() {
blockHistory := &model.BlockHistory{}
err := rows.Scan(
&blockHistory.ID,
&blockHistory.TeamID,
&blockHistory.BoardID,
&blockHistory.Type,
&blockHistory.IsDeleted,
&blockHistory.LastUpdateAt,
&blockHistory.FirstUpdateAt,
&blockHistory.CreatedBy,
&blockHistory.LastModifiedBy,
)
if err != nil {
s.logger.Error("blocksHistoryFromRows scan error", mlog.Err(err))
return nil, err
}
history = append(history, blockHistory)
}
return history, nil
}