repos.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright 2020 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package db
  5. import (
  6. "context"
  7. "fmt"
  8. "strings"
  9. "time"
  10. "gorm.io/gorm"
  11. "gogs.io/gogs/internal/errutil"
  12. )
  13. // ReposStore is the persistent interface for repositories.
  14. //
  15. // NOTE: All methods are sorted in alphabetical order.
  16. type ReposStore interface {
  17. // GetByName returns the repository with given owner and name. It returns
  18. // ErrRepoNotExist when not found.
  19. GetByName(ctx context.Context, ownerID int64, name string) (*Repository, error)
  20. }
  21. var Repos ReposStore
  22. // BeforeCreate implements the GORM create hook.
  23. func (r *Repository) BeforeCreate(tx *gorm.DB) error {
  24. if r.CreatedUnix == 0 {
  25. r.CreatedUnix = tx.NowFunc().Unix()
  26. }
  27. return nil
  28. }
  29. // BeforeUpdate implements the GORM update hook.
  30. func (r *Repository) BeforeUpdate(tx *gorm.DB) error {
  31. r.UpdatedUnix = tx.NowFunc().Unix()
  32. return nil
  33. }
  34. // AfterFind implements the GORM query hook.
  35. func (r *Repository) AfterFind(_ *gorm.DB) error {
  36. r.Created = time.Unix(r.CreatedUnix, 0).Local()
  37. r.Updated = time.Unix(r.UpdatedUnix, 0).Local()
  38. return nil
  39. }
  40. var _ ReposStore = (*repos)(nil)
  41. type repos struct {
  42. *gorm.DB
  43. }
  44. type ErrRepoAlreadyExist struct {
  45. args errutil.Args
  46. }
  47. func IsErrRepoAlreadyExist(err error) bool {
  48. _, ok := err.(ErrRepoAlreadyExist)
  49. return ok
  50. }
  51. func (err ErrRepoAlreadyExist) Error() string {
  52. return fmt.Sprintf("repository already exists: %v", err.args)
  53. }
  54. type createRepoOpts struct {
  55. Name string
  56. Description string
  57. DefaultBranch string
  58. Private bool
  59. Mirror bool
  60. EnableWiki bool
  61. EnableIssues bool
  62. EnablePulls bool
  63. Fork bool
  64. ForkID int64
  65. }
  66. // create creates a new repository record in the database. Fields of "repo" will be updated
  67. // in place upon insertion. It returns ErrNameNotAllowed when the repository name is not allowed,
  68. // or ErrRepoAlreadyExist when a repository with same name already exists for the owner.
  69. func (db *repos) create(ctx context.Context, ownerID int64, opts createRepoOpts) (*Repository, error) {
  70. err := isRepoNameAllowed(opts.Name)
  71. if err != nil {
  72. return nil, err
  73. }
  74. _, err = db.GetByName(ctx, ownerID, opts.Name)
  75. if err == nil {
  76. return nil, ErrRepoAlreadyExist{args: errutil.Args{"ownerID": ownerID, "name": opts.Name}}
  77. } else if !IsErrRepoNotExist(err) {
  78. return nil, err
  79. }
  80. repo := &Repository{
  81. OwnerID: ownerID,
  82. LowerName: strings.ToLower(opts.Name),
  83. Name: opts.Name,
  84. Description: opts.Description,
  85. DefaultBranch: opts.DefaultBranch,
  86. IsPrivate: opts.Private,
  87. IsMirror: opts.Mirror,
  88. EnableWiki: opts.EnableWiki,
  89. EnableIssues: opts.EnableIssues,
  90. EnablePulls: opts.EnablePulls,
  91. IsFork: opts.Fork,
  92. ForkID: opts.ForkID,
  93. }
  94. return repo, db.WithContext(ctx).Create(repo).Error
  95. }
  96. var _ errutil.NotFound = (*ErrRepoNotExist)(nil)
  97. type ErrRepoNotExist struct {
  98. args map[string]interface{}
  99. }
  100. func IsErrRepoNotExist(err error) bool {
  101. _, ok := err.(ErrRepoNotExist)
  102. return ok
  103. }
  104. func (err ErrRepoNotExist) Error() string {
  105. return fmt.Sprintf("repository does not exist: %v", err.args)
  106. }
  107. func (ErrRepoNotExist) NotFound() bool {
  108. return true
  109. }
  110. func (db *repos) GetByName(ctx context.Context, ownerID int64, name string) (*Repository, error) {
  111. repo := new(Repository)
  112. err := db.WithContext(ctx).
  113. Where("owner_id = ? AND lower_name = ?", ownerID, strings.ToLower(name)).
  114. First(repo).
  115. Error
  116. if err != nil {
  117. if err == gorm.ErrRecordNotFound {
  118. return nil, ErrRepoNotExist{args: map[string]interface{}{"ownerID": ownerID, "name": name}}
  119. }
  120. return nil, err
  121. }
  122. return repo, nil
  123. }