code.gitea.io/gitea@v1.22.3/models/migrations/v1_22/v293.go (about)

     1  // Copyright 2024 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package v1_22 //nolint
     5  
     6  import (
     7  	"code.gitea.io/gitea/modules/setting"
     8  	"code.gitea.io/gitea/modules/timeutil"
     9  
    10  	"xorm.io/xorm"
    11  )
    12  
    13  // CheckProjectColumnsConsistency ensures there is exactly one default board per project present
    14  func CheckProjectColumnsConsistency(x *xorm.Engine) error {
    15  	sess := x.NewSession()
    16  	defer sess.Close()
    17  
    18  	limit := setting.Database.IterateBufferSize
    19  	if limit <= 0 {
    20  		limit = 50
    21  	}
    22  
    23  	type Project struct {
    24  		ID        int64
    25  		CreatorID int64
    26  		BoardID   int64
    27  	}
    28  
    29  	type ProjectBoard struct {
    30  		ID      int64 `xorm:"pk autoincr"`
    31  		Title   string
    32  		Default bool   `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific board will be assigned to this board
    33  		Sorting int8   `xorm:"NOT NULL DEFAULT 0"`
    34  		Color   string `xorm:"VARCHAR(7)"`
    35  
    36  		ProjectID int64 `xorm:"INDEX NOT NULL"`
    37  		CreatorID int64 `xorm:"NOT NULL"`
    38  
    39  		CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
    40  		UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
    41  	}
    42  
    43  	for {
    44  		if err := sess.Begin(); err != nil {
    45  			return err
    46  		}
    47  
    48  		// all these projects without defaults will be fixed in the same loop, so
    49  		// we just need to always get projects without defaults until no such project
    50  		var projects []*Project
    51  		if err := sess.Select("project.id as id, project.creator_id, project_board.id as board_id").
    52  			Join("LEFT", "project_board", "project_board.project_id = project.id AND project_board.`default`=?", true).
    53  			Where("project_board.id is NULL OR project_board.id = 0").
    54  			Limit(limit).
    55  			Find(&projects); err != nil {
    56  			return err
    57  		}
    58  
    59  		for _, p := range projects {
    60  			if _, err := sess.Insert(ProjectBoard{
    61  				ProjectID: p.ID,
    62  				Default:   true,
    63  				Title:     "Uncategorized",
    64  				CreatorID: p.CreatorID,
    65  			}); err != nil {
    66  				return err
    67  			}
    68  		}
    69  		if err := sess.Commit(); err != nil {
    70  			return err
    71  		}
    72  
    73  		if len(projects) == 0 {
    74  			break
    75  		}
    76  	}
    77  	sess.Close()
    78  
    79  	return removeDuplicatedBoardDefault(x)
    80  }
    81  
    82  func removeDuplicatedBoardDefault(x *xorm.Engine) error {
    83  	type ProjectInfo struct {
    84  		ProjectID  int64
    85  		DefaultNum int
    86  	}
    87  	var projects []ProjectInfo
    88  	if err := x.Select("project_id, count(*) AS default_num").
    89  		Table("project_board").
    90  		Where("`default` = ?", true).
    91  		GroupBy("project_id").
    92  		Having("count(*) > 1").
    93  		Find(&projects); err != nil {
    94  		return err
    95  	}
    96  
    97  	for _, project := range projects {
    98  		if _, err := x.Where("project_id=?", project.ProjectID).
    99  			Table("project_board").
   100  			Limit(project.DefaultNum - 1).
   101  			Update(map[string]bool{
   102  				"`default`": false,
   103  			}); err != nil {
   104  			return err
   105  		}
   106  	}
   107  	return nil
   108  }