Compare commits

..

5 Commits

Author SHA1 Message Date
GiteaBot
ff7383e83a [skip ci] Updated translations via Crowdin 2023-12-26 00:24:05 +00:00
delvh
778ad795fd
Refactor deletion (#28610)
Introduce the new generic deletion methods
- `func DeleteByID[T any](ctx context.Context, id int64) (int64, error)`
- `func DeleteByIDs[T any](ctx context.Context, ids ...int64) error`
- `func Delete[T any](ctx context.Context, opts FindOptions) (int64,
error)`

So, we no longer need any specific deletion method and can just use
the generic ones instead.

Replacement of #28450

Closes #28450

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2023-12-25 21:25:29 +01:00
wxiaoguang
b41925cee3
Refactor CORS handler (#28587)
The CORS code has been unmaintained for long time, and the behavior is
not correct.

This PR tries to improve it. The key point is written as comment in
code. And add more tests.

Fix #28515
Fix #27642
Fix #17098
2023-12-25 20:13:18 +08:00
Jean-Baptiste Gomond
d0f24ff4ca
Added instance-level variables (#28115)
This PR adds instance-level variables, and so closes #27726



![gitea_instance_variables_1](https://github.com/go-gitea/gitea/assets/8344487/ad409cd4-ce36-4c84-a764-34451b0fb63a)

![gitea_instance_variables_2](https://github.com/go-gitea/gitea/assets/8344487/426f0965-dec6-4560-948c-067cdeddd720)

![gitea_instance_variables_3](https://github.com/go-gitea/gitea/assets/8344487/cf1d7776-4938-4825-922e-cbbbf28a5f33)
2023-12-25 07:28:59 +00:00
Lunny Xiao
0407a402bb
Revert "improve possible performance bottleneck (#28547)" (#28593)
This reverts commit b35d3fddfac389a7be401a63b4e1283dd74af681.

This is totally wrong. I think `Update join` hasn't been supported well
by xorm.

I just revert the PR and will try to send another one.
2023-12-25 06:52:17 +00:00
73 changed files with 278 additions and 313 deletions

View File

@ -1158,15 +1158,9 @@ LEVEL = Info
;; enable cors headers (disabled by default) ;; enable cors headers (disabled by default)
;ENABLED = false ;ENABLED = false
;; ;;
;; scheme of allowed requests ;; list of requesting origins that are allowed, eg: "https://*.example.com"
;SCHEME = http
;;
;; list of requesting domains that are allowed
;ALLOW_DOMAIN = * ;ALLOW_DOMAIN = *
;; ;;
;; allow subdomains of headers listed above to request
;ALLOW_SUBDOMAIN = false
;;
;; list of methods allowed to request ;; list of methods allowed to request
;METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS ;METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
;; ;;

View File

@ -196,9 +196,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
## CORS (`cors`) ## CORS (`cors`)
- `ENABLED`: **false**: enable cors headers (disabled by default) - `ENABLED`: **false**: enable cors headers (disabled by default)
- `SCHEME`: **http**: scheme of allowed requests - `ALLOW_DOMAIN`: **\***: list of requesting origins that are allowed, eg: "https://*.example.com"
- `ALLOW_DOMAIN`: **\***: list of requesting domains that are allowed
- `ALLOW_SUBDOMAIN`: **false**: allow subdomains of headers listed above to request
- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request - `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request
- `MAX_AGE`: **10m**: max time to cache response - `MAX_AGE`: **10m**: max time to cache response
- `ALLOW_CREDENTIALS`: **false**: allow request with credentials - `ALLOW_CREDENTIALS`: **false**: allow request with credentials

View File

@ -195,9 +195,7 @@ menu:
## 跨域 (`cors`) ## 跨域 (`cors`)
- `ENABLED`: **false**: 启用 CORS 头部(默认禁用) - `ENABLED`: **false**: 启用 CORS 头部(默认禁用)
- `SCHEME`: **http**: 允许请求的协议
- `ALLOW_DOMAIN`: **\***: 允许请求的域名列表 - `ALLOW_DOMAIN`: **\***: 允许请求的域名列表
- `ALLOW_SUBDOMAIN`: **false**: 允许上述列出的头部的子域名发出请求。
- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: 允许发起的请求方式列表 - `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: 允许发起的请求方式列表
- `MAX_AGE`: **10m**: 缓存响应的最大时间 - `MAX_AGE`: **10m**: 缓存响应的最大时间
- `ALLOW_CREDENTIALS`: **false**: 允许带有凭据的请求 - `ALLOW_CREDENTIALS`: **false**: 允许带有凭据的请求

View File

@ -90,19 +90,6 @@ func getArtifactByNameAndPath(ctx context.Context, runID int64, name, fpath stri
return &art, nil return &art, nil
} }
// GetArtifactByID returns an artifact by id
func GetArtifactByID(ctx context.Context, id int64) (*ActionArtifact, error) {
var art ActionArtifact
has, err := db.GetEngine(ctx).ID(id).Get(&art)
if err != nil {
return nil, err
} else if !has {
return nil, util.ErrNotExist
}
return &art, nil
}
// UpdateArtifactByID updates an artifact by id // UpdateArtifactByID updates an artifact by id
func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) error { func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) error {
art.ID = id art.ID = id

View File

@ -254,7 +254,7 @@ func DeleteRunner(ctx context.Context, id int64) error {
return err return err
} }
_, err := db.GetEngine(ctx).Delete(&ActionRunner{ID: id}) _, err := db.DeleteByID[ActionRunner](ctx, id)
return err return err
} }

View File

@ -31,8 +31,8 @@ func init() {
} }
func (v *ActionVariable) Validate() error { func (v *ActionVariable) Validate() error {
if v.OwnerID == 0 && v.RepoID == 0 { if v.OwnerID != 0 && v.RepoID != 0 {
return errors.New("the variable is not bound to any scope") return errors.New("a variable should not be bound to an owner and a repository at the same time")
} }
return nil return nil
} }
@ -58,12 +58,8 @@ type FindVariablesOpts struct {
func (opts FindVariablesOpts) ToConds() builder.Cond { func (opts FindVariablesOpts) ToConds() builder.Cond {
cond := builder.NewCond() cond := builder.NewCond()
if opts.OwnerID > 0 { cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
return cond return cond
} }

View File

@ -227,16 +227,6 @@ func UpdatePublicKeyUpdated(ctx context.Context, id int64) error {
return nil return nil
} }
// DeletePublicKeys does the actual key deletion but does not update authorized_keys file.
func DeletePublicKeys(ctx context.Context, keyIDs ...int64) error {
if len(keyIDs) == 0 {
return nil
}
_, err := db.GetEngine(ctx).In("id", keyIDs).Delete(new(PublicKey))
return err
}
// PublicKeysAreExternallyManaged returns whether the provided KeyID represents an externally managed Key // PublicKeysAreExternallyManaged returns whether the provided KeyID represents an externally managed Key
func PublicKeysAreExternallyManaged(ctx context.Context, keys []*PublicKey) ([]bool, error) { func PublicKeysAreExternallyManaged(ctx context.Context, keys []*PublicKey) ([]bool, error) {
sources := make([]*auth.Source, 0, 5) sources := make([]*auth.Source, 0, 5)
@ -322,8 +312,8 @@ func deleteKeysMarkedForDeletion(ctx context.Context, keys []string) (bool, erro
log.Error("SearchPublicKeyByContent: %v", err) log.Error("SearchPublicKeyByContent: %v", err)
continue continue
} }
if err = DeletePublicKeys(ctx, key.ID); err != nil { if _, err = db.DeleteByID[PublicKey](ctx, key.ID); err != nil {
log.Error("deletePublicKeys: %v", err) log.Error("DeleteByID[PublicKey]: %v", err)
continue continue
} }
sshKeysNeedUpdate = true sshKeysNeedUpdate = true

View File

@ -175,7 +175,7 @@ func Exec(ctx context.Context, sqlAndArgs ...any) (sql.Result, error) {
func Get[T any](ctx context.Context, cond builder.Cond) (object *T, exist bool, err error) { func Get[T any](ctx context.Context, cond builder.Cond) (object *T, exist bool, err error) {
if !cond.IsValid() { if !cond.IsValid() {
return nil, false, ErrConditionRequired{} panic("cond is invalid in db.Get(ctx, cond). This should not be possible.")
} }
var bean T var bean T
@ -201,7 +201,7 @@ func GetByID[T any](ctx context.Context, id int64) (object *T, exist bool, err e
func Exist[T any](ctx context.Context, cond builder.Cond) (bool, error) { func Exist[T any](ctx context.Context, cond builder.Cond) (bool, error) {
if !cond.IsValid() { if !cond.IsValid() {
return false, ErrConditionRequired{} panic("cond is invalid in db.Exist(ctx, cond). This should not be possible.")
} }
var bean T var bean T
@ -213,16 +213,36 @@ func ExistByID[T any](ctx context.Context, id int64) (bool, error) {
return GetEngine(ctx).ID(id).NoAutoCondition().Exist(&bean) return GetEngine(ctx).ID(id).NoAutoCondition().Exist(&bean)
} }
// DeleteByID deletes the given bean with the given ID
func DeleteByID[T any](ctx context.Context, id int64) (int64, error) {
var bean T
return GetEngine(ctx).ID(id).NoAutoCondition().NoAutoTime().Delete(&bean)
}
func DeleteByIDs[T any](ctx context.Context, ids ...int64) error {
if len(ids) == 0 {
return nil
}
var bean T
_, err := GetEngine(ctx).In("id", ids).NoAutoCondition().NoAutoTime().Delete(&bean)
return err
}
func Delete[T any](ctx context.Context, opts FindOptions) (int64, error) {
if opts == nil || !opts.ToConds().IsValid() {
panic("opts are empty or invalid in db.Delete(ctx, opts). This should not be possible.")
}
var bean T
return GetEngine(ctx).Where(opts.ToConds()).NoAutoCondition().NoAutoTime().Delete(&bean)
}
// DeleteByBean deletes all records according non-empty fields of the bean as conditions. // DeleteByBean deletes all records according non-empty fields of the bean as conditions.
func DeleteByBean(ctx context.Context, bean any) (int64, error) { func DeleteByBean(ctx context.Context, bean any) (int64, error) {
return GetEngine(ctx).Delete(bean) return GetEngine(ctx).Delete(bean)
} }
// DeleteByID deletes the given bean with the given ID
func DeleteByID(ctx context.Context, id int64, bean any) (int64, error) {
return GetEngine(ctx).ID(id).NoAutoCondition().NoAutoTime().Delete(bean)
}
// FindIDs finds the IDs for the given table name satisfying the given condition // FindIDs finds the IDs for the given table name satisfying the given condition
// By passing a different value than "id" for "idCol", you can query for foreign IDs, i.e. the repo IDs which satisfy the condition // By passing a different value than "id" for "idCol", you can query for foreign IDs, i.e. the repo IDs which satisfy the condition
func FindIDs(ctx context.Context, tableName, idCol string, cond builder.Cond) ([]int64, error) { func FindIDs(ctx context.Context, tableName, idCol string, cond builder.Cond) ([]int64, error) {

View File

@ -72,21 +72,3 @@ func (err ErrNotExist) Error() string {
func (err ErrNotExist) Unwrap() error { func (err ErrNotExist) Unwrap() error {
return util.ErrNotExist return util.ErrNotExist
} }
// ErrConditionRequired represents an error which require condition.
type ErrConditionRequired struct{}
// IsErrConditionRequired checks if an error is an ErrConditionRequired
func IsErrConditionRequired(err error) bool {
_, ok := err.(ErrConditionRequired)
return ok
}
func (err ErrConditionRequired) Error() string {
return "condition is required"
}
// Unwrap unwraps this as a ErrNotExist err
func (err ErrConditionRequired) Unwrap() error {
return util.ErrInvalidArgument
}

View File

@ -1161,9 +1161,14 @@ func DeleteComment(ctx context.Context, comment *Comment) error {
// UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id // UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id
func UpdateCommentsMigrationsByType(ctx context.Context, tp structs.GitServiceType, originalAuthorID string, posterID int64) error { func UpdateCommentsMigrationsByType(ctx context.Context, tp structs.GitServiceType, originalAuthorID string, posterID int64) error {
_, err := db.GetEngine(ctx).Table("comment"). _, err := db.GetEngine(ctx).Table("comment").
Join("INNER", "issue", "issue.id = comment.issue_id"). Where(builder.In("issue_id",
Join("INNER", "repository", "issue.repo_id = repository.id"). builder.Select("issue.id").
Where("repository.original_service_type = ?", tp). From("issue").
InnerJoin("repository", "issue.repo_id = repository.id").
Where(builder.Eq{
"repository.original_service_type": tp,
}),
)).
And("comment.original_author_id = ?", originalAuthorID). And("comment.original_author_id = ?", originalAuthorID).
Update(map[string]any{ Update(map[string]any{
"poster_id": posterID, "poster_id": posterID,

View File

@ -249,11 +249,11 @@ func TestIssue_InsertIssue(t *testing.T) {
// there are 5 issues and max index is 5 on repository 1, so this one should 6 // there are 5 issues and max index is 5 on repository 1, so this one should 6
issue := testInsertIssue(t, "my issue1", "special issue's comments?", 6) issue := testInsertIssue(t, "my issue1", "special issue's comments?", 6)
_, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Delete(new(issues_model.Issue)) _, err := db.DeleteByID[issues_model.Issue](db.DefaultContext, issue.ID)
assert.NoError(t, err) assert.NoError(t, err)
issue = testInsertIssue(t, `my issue2, this is my son's love \n \r \ `, "special issue's '' comments?", 7) issue = testInsertIssue(t, `my issue2, this is my son's love \n \r \ `, "special issue's '' comments?", 7)
_, err = db.GetEngine(db.DefaultContext).ID(issue.ID).Delete(new(issues_model.Issue)) _, err = db.DeleteByID[issues_model.Issue](db.DefaultContext, issue.ID)
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@ -256,7 +256,7 @@ func DeleteLabel(ctx context.Context, id, labelID int64) error {
return nil return nil
} }
if _, err = sess.ID(labelID).Delete(new(Label)); err != nil { if _, err = db.DeleteByID[Label](ctx, labelID); err != nil {
return err return err
} else if _, err = sess. } else if _, err = sess.
Where("label_id = ?", labelID). Where("label_id = ?", labelID).

View File

@ -289,9 +289,7 @@ func DeleteMilestoneByRepoID(ctx context.Context, repoID, id int64) error {
} }
defer committer.Close() defer committer.Close()
sess := db.GetEngine(ctx) if _, err = db.DeleteByID[Milestone](ctx, m.ID); err != nil {
if _, err = sess.ID(m.ID).Delete(new(Milestone)); err != nil {
return err return err
} }
@ -311,7 +309,7 @@ func DeleteMilestoneByRepoID(ctx context.Context, repoID, id int64) error {
repo.NumMilestones = int(numMilestones) repo.NumMilestones = int(numMilestones)
repo.NumClosedMilestones = int(numClosedMilestones) repo.NumClosedMilestones = int(numClosedMilestones)
if _, err = sess.ID(repo.ID).Cols("num_milestones, num_closed_milestones").Update(repo); err != nil { if _, err = db.GetEngine(ctx).ID(repo.ID).Cols("num_milestones, num_closed_milestones").Update(repo); err != nil {
return err return err
} }

View File

@ -446,7 +446,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, issue *Issue, revi
continue continue
} }
if _, err := sess.ID(teamReviewRequest.ID).NoAutoCondition().Delete(teamReviewRequest); err != nil { if _, err := db.DeleteByID[Review](ctx, teamReviewRequest.ID); err != nil {
return nil, nil, err return nil, nil, err
} }
} }
@ -869,7 +869,6 @@ func DeleteReview(ctx context.Context, r *Review) error {
return err return err
} }
defer committer.Close() defer committer.Close()
sess := db.GetEngine(ctx)
if r.ID == 0 { if r.ID == 0 {
return fmt.Errorf("review is not allowed to be 0") return fmt.Errorf("review is not allowed to be 0")
@ -885,7 +884,7 @@ func DeleteReview(ctx context.Context, r *Review) error {
ReviewID: r.ID, ReviewID: r.ID,
} }
if _, err := sess.Where(opts.ToConds()).Delete(new(Comment)); err != nil { if _, err := db.Delete[Comment](ctx, opts); err != nil {
return err return err
} }
@ -895,7 +894,7 @@ func DeleteReview(ctx context.Context, r *Review) error {
ReviewID: r.ID, ReviewID: r.ID,
} }
if _, err := sess.Where(opts.ToConds()).Delete(new(Comment)); err != nil { if _, err := db.Delete[Comment](ctx, opts); err != nil {
return err return err
} }
@ -905,11 +904,11 @@ func DeleteReview(ctx context.Context, r *Review) error {
ReviewID: r.ID, ReviewID: r.ID,
} }
if _, err := sess.Where(opts.ToConds()).Delete(new(Comment)); err != nil { if _, err := db.Delete[Comment](ctx, opts); err != nil {
return err return err
} }
if _, err := sess.ID(r.ID).Delete(new(Review)); err != nil { if _, err := db.DeleteByID[Review](ctx, r.ID); err != nil {
return err return err
} }

View File

@ -57,7 +57,7 @@ func RemoveOrgUser(ctx context.Context, orgID, userID int64) error {
} }
defer committer.Close() defer committer.Close()
if _, err := db.GetEngine(ctx).ID(ou.ID).Delete(ou); err != nil { if _, err := db.DeleteByID[organization.OrgUser](ctx, ou.ID); err != nil {
return err return err
} else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil { } else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil {
return err return err

View File

@ -344,9 +344,7 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error
} }
} }
if _, err := db.DeleteByBean(ctx, &asymkey_model.DeployKey{ if _, err := db.DeleteByID[asymkey_model.DeployKey](ctx, key.ID); err != nil {
ID: key.ID,
}); err != nil {
return fmt.Errorf("delete deploy key [%d]: %w", key.ID, err) return fmt.Errorf("delete deploy key [%d]: %w", key.ID, err)
} }
@ -355,7 +353,7 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error
if err != nil { if err != nil {
return err return err
} else if !has { } else if !has {
if err = asymkey_model.DeletePublicKeys(ctx, key.KeyID); err != nil { if _, err = db.DeleteByID[asymkey_model.PublicKey](ctx, key.KeyID); err != nil {
return err return err
} }
} }

View File

@ -68,14 +68,6 @@ func repoArchiverForRelativePath(relativePath string) (*RepoArchiver, error) {
}, nil }, nil
} }
var delRepoArchiver = new(RepoArchiver)
// DeleteRepoArchiver delete archiver
func DeleteRepoArchiver(ctx context.Context, archiver *RepoArchiver) error {
_, err := db.GetEngine(ctx).ID(archiver.ID).Delete(delRepoArchiver)
return err
}
// GetRepoArchiver get an archiver // GetRepoArchiver get an archiver
func GetRepoArchiver(ctx context.Context, repoID int64, tp git.ArchiveType, commitID string) (*RepoArchiver, error) { func GetRepoArchiver(ctx context.Context, repoID int64, tp git.ArchiveType, commitID string) (*RepoArchiver, error) {
var archiver RepoArchiver var archiver RepoArchiver
@ -100,12 +92,6 @@ func ExistsRepoArchiverWithStoragePath(ctx context.Context, storagePath string)
return db.GetEngine(ctx).Exist(archiver) return db.GetEngine(ctx).Exist(archiver)
} }
// AddRepoArchiver adds an archiver
func AddRepoArchiver(ctx context.Context, archiver *RepoArchiver) error {
_, err := db.GetEngine(ctx).Insert(archiver)
return err
}
// UpdateRepoArchiverStatus updates archiver's status // UpdateRepoArchiverStatus updates archiver's status
func UpdateRepoArchiverStatus(ctx context.Context, archiver *RepoArchiver) error { func UpdateRepoArchiverStatus(ctx context.Context, archiver *RepoArchiver) error {
_, err := db.GetEngine(ctx).ID(archiver.ID).Cols("status").Update(archiver) _, err := db.GetEngine(ctx).ID(archiver.ID).Cols("status").Update(archiver)
@ -114,6 +100,7 @@ func UpdateRepoArchiverStatus(ctx context.Context, archiver *RepoArchiver) error
// DeleteAllRepoArchives deletes all repo archives records // DeleteAllRepoArchives deletes all repo archives records
func DeleteAllRepoArchives(ctx context.Context) error { func DeleteAllRepoArchives(ctx context.Context) error {
// 1=1 to enforce delete all data, otherwise it will delete nothing
_, err := db.GetEngine(ctx).Where("1=1").Delete(new(RepoArchiver)) _, err := db.GetEngine(ctx).Where("1=1").Delete(new(RepoArchiver))
return err return err
} }

View File

@ -34,12 +34,13 @@ type PushMirror struct {
} }
type PushMirrorOptions struct { type PushMirrorOptions struct {
db.ListOptions
ID int64 ID int64
RepoID int64 RepoID int64
RemoteName string RemoteName string
} }
func (opts *PushMirrorOptions) toConds() builder.Cond { func (opts PushMirrorOptions) ToConds() builder.Cond {
cond := builder.NewCond() cond := builder.NewCond()
if opts.RepoID > 0 { if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
@ -75,12 +76,6 @@ func (m *PushMirror) GetRemoteName() string {
return m.RemoteName return m.RemoteName
} }
// InsertPushMirror inserts a push-mirror to database
func InsertPushMirror(ctx context.Context, m *PushMirror) error {
_, err := db.GetEngine(ctx).Insert(m)
return err
}
// UpdatePushMirror updates the push-mirror // UpdatePushMirror updates the push-mirror
func UpdatePushMirror(ctx context.Context, m *PushMirror) error { func UpdatePushMirror(ctx context.Context, m *PushMirror) error {
_, err := db.GetEngine(ctx).ID(m.ID).AllCols().Update(m) _, err := db.GetEngine(ctx).ID(m.ID).AllCols().Update(m)
@ -95,23 +90,12 @@ func UpdatePushMirrorInterval(ctx context.Context, m *PushMirror) error {
func DeletePushMirrors(ctx context.Context, opts PushMirrorOptions) error { func DeletePushMirrors(ctx context.Context, opts PushMirrorOptions) error {
if opts.RepoID > 0 { if opts.RepoID > 0 {
_, err := db.GetEngine(ctx).Where(opts.toConds()).Delete(&PushMirror{}) _, err := db.Delete[PushMirror](ctx, opts)
return err return err
} }
return util.NewInvalidArgumentErrorf("repoID required and must be set") return util.NewInvalidArgumentErrorf("repoID required and must be set")
} }
func GetPushMirror(ctx context.Context, opts PushMirrorOptions) (*PushMirror, error) {
mirror := &PushMirror{}
exist, err := db.GetEngine(ctx).Where(opts.toConds()).Get(mirror)
if err != nil {
return nil, err
} else if !exist {
return nil, ErrPushMirrorNotExist
}
return mirror, nil
}
// GetPushMirrorsByRepoID returns push-mirror information of a repository. // GetPushMirrorsByRepoID returns push-mirror information of a repository.
func GetPushMirrorsByRepoID(ctx context.Context, repoID int64, listOptions db.ListOptions) ([]*PushMirror, int64, error) { func GetPushMirrorsByRepoID(ctx context.Context, repoID int64, listOptions db.ListOptions) ([]*PushMirror, int64, error) {
sess := db.GetEngine(ctx).Where("repo_id = ?", repoID) sess := db.GetEngine(ctx).Where("repo_id = ?", repoID)

View File

@ -20,20 +20,20 @@ func TestPushMirrorsIterate(t *testing.T) {
now := timeutil.TimeStampNow() now := timeutil.TimeStampNow()
repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{ db.Insert(db.DefaultContext, &repo_model.PushMirror{
RemoteName: "test-1", RemoteName: "test-1",
LastUpdateUnix: now, LastUpdateUnix: now,
Interval: 1, Interval: 1,
}) })
long, _ := time.ParseDuration("24h") long, _ := time.ParseDuration("24h")
repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{ db.Insert(db.DefaultContext, &repo_model.PushMirror{
RemoteName: "test-2", RemoteName: "test-2",
LastUpdateUnix: now, LastUpdateUnix: now,
Interval: long, Interval: long,
}) })
repo_model.InsertPushMirror(db.DefaultContext, &repo_model.PushMirror{ db.Insert(db.DefaultContext, &repo_model.PushMirror{
RemoteName: "test-3", RemoteName: "test-3",
LastUpdateUnix: now, LastUpdateUnix: now,
Interval: 0, Interval: 0,

View File

@ -450,12 +450,6 @@ func SortReleases(rels []*Release) {
sort.Sort(sorter) sort.Sort(sorter)
} }
// DeleteReleaseByID deletes a release from database by given ID.
func DeleteReleaseByID(ctx context.Context, id int64) error {
_, err := db.GetEngine(ctx).ID(id).Delete(new(Release))
return err
}
// UpdateReleasesMigrationsByType updates all migrated repositories' releases from gitServiceType to replace originalAuthorID to posterID // UpdateReleasesMigrationsByType updates all migrated repositories' releases from gitServiceType to replace originalAuthorID to posterID
func UpdateReleasesMigrationsByType(ctx context.Context, gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error { func UpdateReleasesMigrationsByType(ctx context.Context, gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error {
_, err := db.GetEngine(ctx).Table("release"). _, err := db.GetEngine(ctx).Table("release").
@ -509,7 +503,7 @@ func PushUpdateDeleteTag(ctx context.Context, repo *Repository, tagName string)
return fmt.Errorf("GetRelease: %w", err) return fmt.Errorf("GetRelease: %w", err)
} }
if rel.IsTag { if rel.IsTag {
if _, err = db.GetEngine(ctx).ID(rel.ID).Delete(new(Release)); err != nil { if _, err = db.DeleteByID[Release](ctx, rel.ID); err != nil {
return fmt.Errorf("Delete: %w", err) return fmt.Errorf("Delete: %w", err)
} }
} else { } else {

View File

@ -131,9 +131,7 @@ func DeleteUploads(ctx context.Context, uploads ...*Upload) (err error) {
for i := 0; i < len(uploads); i++ { for i := 0; i < len(uploads); i++ {
ids[i] = uploads[i].ID ids[i] = uploads[i].ID
} }
if _, err = db.GetEngine(ctx). if err = db.DeleteByIDs[Upload](ctx, ids...); err != nil {
In("id", ids).
Delete(new(Upload)); err != nil {
return fmt.Errorf("delete uploads: %w", err) return fmt.Errorf("delete uploads: %w", err)
} }

View File

@ -85,23 +85,21 @@ func watchRepoMode(ctx context.Context, watch Watch, mode WatchMode) (err error)
watch.Mode = mode watch.Mode = mode
e := db.GetEngine(ctx)
if !hadrec && needsrec { if !hadrec && needsrec {
watch.Mode = mode watch.Mode = mode
if _, err = e.Insert(watch); err != nil { if err = db.Insert(ctx, watch); err != nil {
return err return err
} }
} else if needsrec { } else if needsrec {
watch.Mode = mode watch.Mode = mode
if _, err := e.ID(watch.ID).AllCols().Update(watch); err != nil { if _, err := db.GetEngine(ctx).ID(watch.ID).AllCols().Update(watch); err != nil {
return err return err
} }
} else if _, err = e.Delete(Watch{ID: watch.ID}); err != nil { } else if _, err = db.DeleteByID[Watch](ctx, watch.ID); err != nil {
return err return err
} }
if repodiff != 0 { if repodiff != 0 {
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + ? WHERE id = ?", repodiff, watch.RepoID) _, err = db.GetEngine(ctx).Exec("UPDATE `repository` SET num_watches = num_watches + ? WHERE id = ?", repodiff, watch.RepoID)
} }
return err return err
} }

View File

@ -102,12 +102,6 @@ func Notices(ctx context.Context, page, pageSize int) ([]*Notice, error) {
Find(&notices) Find(&notices)
} }
// DeleteNotice deletes a system notice by given ID.
func DeleteNotice(ctx context.Context, id int64) error {
_, err := db.GetEngine(ctx).ID(id).Delete(new(Notice))
return err
}
// DeleteNotices deletes all notices with ID from start to end (inclusive). // DeleteNotices deletes all notices with ID from start to end (inclusive).
func DeleteNotices(ctx context.Context, start, end int64) error { func DeleteNotices(ctx context.Context, start, end int64) error {
if start == 0 && end == 0 { if start == 0 && end == 0 {
@ -123,17 +117,6 @@ func DeleteNotices(ctx context.Context, start, end int64) error {
return err return err
} }
// DeleteNoticesByIDs deletes notices by given IDs.
func DeleteNoticesByIDs(ctx context.Context, ids []int64) error {
if len(ids) == 0 {
return nil
}
_, err := db.GetEngine(ctx).
In("id", ids).
Delete(new(Notice))
return err
}
// DeleteOldSystemNotices deletes all old system notices from database. // DeleteOldSystemNotices deletes all old system notices from database.
func DeleteOldSystemNotices(ctx context.Context, olderThan time.Duration) (err error) { func DeleteOldSystemNotices(ctx context.Context, olderThan time.Duration) (err error) {
if olderThan <= 0 { if olderThan <= 0 {

View File

@ -69,14 +69,6 @@ func TestNotices(t *testing.T) {
} }
} }
func TestDeleteNotice(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
assert.NoError(t, system.DeleteNotice(db.DefaultContext, 3))
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})
}
func TestDeleteNotices(t *testing.T) { func TestDeleteNotices(t *testing.T) {
// delete a non-empty range // delete a non-empty range
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
@ -109,7 +101,8 @@ func TestDeleteNoticesByIDs(t *testing.T) {
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1})
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3})
assert.NoError(t, system.DeleteNoticesByIDs(db.DefaultContext, []int64{1, 3})) err := db.DeleteByIDs[system.Notice](db.DefaultContext, 1, 3)
assert.NoError(t, err)
unittest.AssertNotExistsBean(t, &system.Notice{ID: 1}) unittest.AssertNotExistsBean(t, &system.Notice{ID: 1})
unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2})
unittest.AssertNotExistsBean(t, &system.Notice{ID: 3}) unittest.AssertNotExistsBean(t, &system.Notice{ID: 3})

View File

@ -471,7 +471,7 @@ func DeleteWebhookByID(ctx context.Context, id int64) (err error) {
} }
defer committer.Close() defer committer.Close()
if count, err := db.DeleteByID(ctx, id, new(Webhook)); err != nil { if count, err := db.DeleteByID[Webhook](ctx, id); err != nil {
return err return err
} else if count == 0 { } else if count == 0 {
return ErrWebhookNotExist{ID: id} return ErrWebhookNotExist{ID: id}

View File

@ -33,7 +33,7 @@ func FileHandlerFunc() http.HandlerFunc {
assetFS := AssetFS() assetFS := AssetFS()
return func(resp http.ResponseWriter, req *http.Request) { return func(resp http.ResponseWriter, req *http.Request) {
if req.Method != "GET" && req.Method != "HEAD" { if req.Method != "GET" && req.Method != "HEAD" {
resp.WriteHeader(http.StatusNotFound) resp.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
handleRequest(resp, req, assetFS, req.URL.Path) handleRequest(resp, req, assetFS, req.URL.Path)

View File

@ -12,9 +12,7 @@ import (
// CORSConfig defines CORS settings // CORSConfig defines CORS settings
var CORSConfig = struct { var CORSConfig = struct {
Enabled bool Enabled bool
Scheme string AllowDomain []string // FIXME: this option is from legacy code, it actually works as "AllowedOrigins". When refactoring in the future, the config option should also be renamed together.
AllowDomain []string
AllowSubdomain bool
Methods []string Methods []string
MaxAge time.Duration MaxAge time.Duration
AllowCredentials bool AllowCredentials bool

View File

@ -101,16 +101,18 @@ func (r *Route) wrapMiddlewareAndHandler(h []any) ([]func(http.Handler) http.Han
return middlewares, handlerFunc return middlewares, handlerFunc
} }
func (r *Route) Methods(method, pattern string, h ...any) { // Methods adds the same handlers for multiple http "methods" (separated by ",").
// If any method is invalid, the lower level router will panic.
func (r *Route) Methods(methods, pattern string, h ...any) {
middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h) middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h)
fullPattern := r.getPattern(pattern) fullPattern := r.getPattern(pattern)
if strings.Contains(method, ",") { if strings.Contains(methods, ",") {
methods := strings.Split(method, ",") methods := strings.Split(methods, ",")
for _, method := range methods { for _, method := range methods {
r.R.With(middlewares...).Method(strings.TrimSpace(method), fullPattern, handlerFunc) r.R.With(middlewares...).Method(strings.TrimSpace(method), fullPattern, handlerFunc)
} }
} else { } else {
r.R.With(middlewares...).Method(method, fullPattern, handlerFunc) r.R.With(middlewares...).Method(methods, fullPattern, handlerFunc)
} }
} }
@ -136,20 +138,6 @@ func (r *Route) Get(pattern string, h ...any) {
r.Methods("GET", pattern, h...) r.Methods("GET", pattern, h...)
} }
func (r *Route) Options(pattern string, h ...any) {
r.Methods("OPTIONS", pattern, h...)
}
// GetOptions delegate get and options method
func (r *Route) GetOptions(pattern string, h ...any) {
r.Methods("GET,OPTIONS", pattern, h...)
}
// PostOptions delegate post and options method
func (r *Route) PostOptions(pattern string, h ...any) {
r.Methods("POST,OPTIONS", pattern, h...)
}
// Head delegate head method // Head delegate head method
func (r *Route) Head(pattern string, h ...any) { func (r *Route) Head(pattern string, h ...any) {
r.Methods("HEAD", pattern, h...) r.Methods("HEAD", pattern, h...)

View File

@ -2767,7 +2767,6 @@ config.enable_openid_signin=Povolit přihlášení pomocí OpenID
config.show_registration_button=Ukázat tlačítko registrace config.show_registration_button=Ukázat tlačítko registrace
config.require_sign_in_view=Vyžadovat přihlášení k zobrazení stránek config.require_sign_in_view=Vyžadovat přihlášení k zobrazení stránek
config.mail_notify=Povolit e-mailová oznámení config.mail_notify=Povolit e-mailová oznámení
config.disable_key_size_check=Vypnout kontrolu minimální velikosti klíčů
config.enable_captcha=Povolit CAPTCHA config.enable_captcha=Povolit CAPTCHA
config.active_code_lives=Doba života aktivního kódu config.active_code_lives=Doba života aktivního kódu
config.reset_password_code_lives=Čas vypršení platnosti kódu pro obnovení účtu config.reset_password_code_lives=Čas vypršení platnosti kódu pro obnovení účtu
@ -3181,7 +3180,6 @@ runners.version=Verze
runs.all_workflows=Všechny pracovní postupy runs.all_workflows=Všechny pracovní postupy
runs.commit=Commit runs.commit=Commit
runs.no_matching_runner_helper=Žádný odpovídající runner: %s
runs.status=Status runs.status=Status

View File

@ -3063,7 +3063,6 @@ config.enable_openid_signin=OpenID-Anmeldung aktivieren
config.show_registration_button=Schaltfläche zum Registrieren anzeigen config.show_registration_button=Schaltfläche zum Registrieren anzeigen
config.require_sign_in_view=Seiten nur für angemeldete Benutzer zugänglich config.require_sign_in_view=Seiten nur für angemeldete Benutzer zugänglich
config.mail_notify=E-Mail-Benachrichtigungen aktivieren config.mail_notify=E-Mail-Benachrichtigungen aktivieren
config.disable_key_size_check=Prüfung der Mindestschlüssellänge deaktiveren
config.enable_captcha=CAPTCHA aktivieren config.enable_captcha=CAPTCHA aktivieren
config.active_code_lives=Aktivierungscode-Lebensdauer config.active_code_lives=Aktivierungscode-Lebensdauer
config.reset_password_code_lives=Kontowiederherstellungs-Code Ablaufzeit config.reset_password_code_lives=Kontowiederherstellungs-Code Ablaufzeit
@ -3509,7 +3508,6 @@ runs.commit=Commit
runs.scheduled=Geplant runs.scheduled=Geplant
runs.pushed_by=gepusht von runs.pushed_by=gepusht von
runs.invalid_workflow_helper=Die Workflow-Konfigurationsdatei ist ungültig. Bitte überprüfe Deine Konfigurationsdatei: %s runs.invalid_workflow_helper=Die Workflow-Konfigurationsdatei ist ungültig. Bitte überprüfe Deine Konfigurationsdatei: %s
runs.no_matching_runner_helper=Kein passender Runner: %s
runs.actor=Initiator runs.actor=Initiator
runs.status=Status runs.status=Status
runs.actors_no_select=Alle Initiatoren runs.actors_no_select=Alle Initiatoren

View File

@ -2889,7 +2889,6 @@ config.enable_openid_signin=Ενεργοποίηση Σύνδεσης μέσω O
config.show_registration_button=Εμφάνιση Κουμπιού Εγγραφής config.show_registration_button=Εμφάνιση Κουμπιού Εγγραφής
config.require_sign_in_view=Απαιτείται Είσοδος για Προβολή Σελίδων config.require_sign_in_view=Απαιτείται Είσοδος για Προβολή Σελίδων
config.mail_notify=Ενεργοποίηση Ειδοποιήσεων Email config.mail_notify=Ενεργοποίηση Ειδοποιήσεων Email
config.disable_key_size_check=Απενεργοποίηση Ελέγχου Ελάχιστου Μεγέθους Κλειδιού
config.enable_captcha=Ενεργοποίηση CAPTCHA config.enable_captcha=Ενεργοποίηση CAPTCHA
config.active_code_lives=Ζωή Ενεργού Κωδικού config.active_code_lives=Ζωή Ενεργού Κωδικού
config.reset_password_code_lives=Λήξη Χρόνου Κωδικού Ανάκτησης του Λογαριασμού config.reset_password_code_lives=Λήξη Χρόνου Κωδικού Ανάκτησης του Λογαριασμού
@ -3321,7 +3320,6 @@ runners.reset_registration_token_success=Επιτυχής επανέκδοση
runs.all_workflows=Όλες Οι Ροές Εργασίας runs.all_workflows=Όλες Οι Ροές Εργασίας
runs.commit=Υποβολή runs.commit=Υποβολή
runs.invalid_workflow_helper=Το αρχείο ροής εργασίας δεν είναι έγκυρο. Ελέγξτε το αρχείο σας: %s runs.invalid_workflow_helper=Το αρχείο ροής εργασίας δεν είναι έγκυρο. Ελέγξτε το αρχείο σας: %s
runs.no_matching_runner_helper=Δε ταιριάζει εκτελεστής: %s
runs.status=Κατάσταση runs.status=Κατάσταση

View File

@ -3063,7 +3063,6 @@ config.enable_openid_signin=Habilitar el inicio de sesión con OpenID
config.show_registration_button=Mostrar Botón de Registro config.show_registration_button=Mostrar Botón de Registro
config.require_sign_in_view=Requerir inicio de sesión obligatorio para ver páginas config.require_sign_in_view=Requerir inicio de sesión obligatorio para ver páginas
config.mail_notify=Habilitar las notificaciones por correo electrónico config.mail_notify=Habilitar las notificaciones por correo electrónico
config.disable_key_size_check=Deshabilitar la comprobación de Tamaño Mínimo de Clave
config.enable_captcha=Activar CAPTCHA config.enable_captcha=Activar CAPTCHA
config.active_code_lives=Habilitar Vida del Código config.active_code_lives=Habilitar Vida del Código
config.reset_password_code_lives=Caducidad del código de recuperación de cuenta config.reset_password_code_lives=Caducidad del código de recuperación de cuenta
@ -3509,7 +3508,6 @@ runs.commit=Commit
runs.scheduled=Programado runs.scheduled=Programado
runs.pushed_by=push enviado por runs.pushed_by=push enviado por
runs.invalid_workflow_helper=El archivo de configuración del trabajo no es válido. Revisa tu archivo de configuración: %s runs.invalid_workflow_helper=El archivo de configuración del trabajo no es válido. Revisa tu archivo de configuración: %s
runs.no_matching_runner_helper=No hay nodo coincidente: %s
runs.actor=Actor runs.actor=Actor
runs.status=Estado runs.status=Estado
runs.actors_no_select=Todos los actores runs.actors_no_select=Todos los actores

View File

@ -2388,7 +2388,6 @@ config.enable_openid_signin=فعال کردن ورود با OpenID
config.show_registration_button=نشان دادن دکمه ثبت نام config.show_registration_button=نشان دادن دکمه ثبت نام
config.require_sign_in_view=فعال‌سازی نیازمند به ورود در هنگام مشاهده صفحات config.require_sign_in_view=فعال‌سازی نیازمند به ورود در هنگام مشاهده صفحات
config.mail_notify=فعال‌سازی اعلان‌های ایمیل (رایانامه) config.mail_notify=فعال‌سازی اعلان‌های ایمیل (رایانامه)
config.disable_key_size_check=غیر فعال کردن بررسی حداقل اندازه کلید
config.enable_captcha=فعال کردن کپچا config.enable_captcha=فعال کردن کپچا
config.active_code_lives=عمر کد فعال سازی config.active_code_lives=عمر کد فعال سازی
config.reset_password_code_lives=مدت انقضای کد بازیابی حساب کاربری config.reset_password_code_lives=مدت انقضای کد بازیابی حساب کاربری

View File

@ -1586,7 +1586,6 @@ config.db_path=Polku
config.service_config=Palvelu asetukset config.service_config=Palvelu asetukset
config.show_registration_button=Näytä rekisteröidy painike config.show_registration_button=Näytä rekisteröidy painike
config.disable_key_size_check=Poista käytöstä avaimen vähimmäiskoko tarkistus
config.enable_captcha=Ota CAPTCHA käyttöön config.enable_captcha=Ota CAPTCHA käyttöön
config.active_code_lives=Aktiivinen koodi elämät ennen vanhenemista config.active_code_lives=Aktiivinen koodi elämät ennen vanhenemista
config.default_keep_email_private=Piilota sähköpostiosoitteet oletuksena config.default_keep_email_private=Piilota sähköpostiosoitteet oletuksena

View File

@ -3069,7 +3069,6 @@ config.enable_openid_signin=Activer la connexion avec OpenID
config.show_registration_button=Afficher le bouton d'enregistrement config.show_registration_button=Afficher le bouton d'enregistrement
config.require_sign_in_view=Exiger la connexion pour afficher les pages config.require_sign_in_view=Exiger la connexion pour afficher les pages
config.mail_notify=Activer les notifications par e-mail config.mail_notify=Activer les notifications par e-mail
config.disable_key_size_check=Désactiver la vérification de la taille de clé minimale
config.enable_captcha=Activer le CAPTCHA config.enable_captcha=Activer le CAPTCHA
config.active_code_lives=Limites de Code Actif config.active_code_lives=Limites de Code Actif
config.reset_password_code_lives=Durée d'expiration du code de récupération de compte config.reset_password_code_lives=Durée d'expiration du code de récupération de compte
@ -3515,7 +3514,6 @@ runs.commit=Révision
runs.scheduled=Planifié runs.scheduled=Planifié
runs.pushed_by=soumis par runs.pushed_by=soumis par
runs.invalid_workflow_helper=La configuration du flux de travail est invalide. Veuillez vérifier votre fichier %s. runs.invalid_workflow_helper=La configuration du flux de travail est invalide. Veuillez vérifier votre fichier %s.
runs.no_matching_runner_helper=Aucun exécuteur correspondant : %s
runs.actor=Acteur runs.actor=Acteur
runs.status=Statut runs.status=Statut
runs.actors_no_select=Tous les acteurs runs.actors_no_select=Tous les acteurs

View File

@ -1476,7 +1476,6 @@ config.enable_openid_signin=OpenID bejelentkezés engedélyezése
config.show_registration_button=Regisztráció gomb megjelenítése config.show_registration_button=Regisztráció gomb megjelenítése
config.require_sign_in_view=Bejelentkezés megkövetelése az oldalak megtekintéséhez config.require_sign_in_view=Bejelentkezés megkövetelése az oldalak megtekintéséhez
config.mail_notify=E-mail értesítés engedélyezése config.mail_notify=E-mail értesítés engedélyezése
config.disable_key_size_check=Minimális kulcsméret ellenőrzés letiltása
config.enable_captcha=CAPTCHA engedélyezése config.enable_captcha=CAPTCHA engedélyezése
config.active_code_lives=Aktív kód élettartam config.active_code_lives=Aktív kód élettartam
config.reset_password_code_lives=Fiók visszaállítási kód lejárati idő config.reset_password_code_lives=Fiók visszaállítási kód lejárati idő

View File

@ -1167,7 +1167,6 @@ config.enable_openid_signin=Aktifkan Login OpenID
config.show_registration_button=Tampilkan tombol mendaftar config.show_registration_button=Tampilkan tombol mendaftar
config.require_sign_in_view=Harus Login Untuk Melihat Halaman config.require_sign_in_view=Harus Login Untuk Melihat Halaman
config.mail_notify=Aktifkan Notifikasi Email config.mail_notify=Aktifkan Notifikasi Email
config.disable_key_size_check=Menonaktifkan memeriksa ukuran kunci minimum
config.enable_captcha=Aktifkan CAPTCHA config.enable_captcha=Aktifkan CAPTCHA
config.active_code_lives=Kode aktif hidup config.active_code_lives=Kode aktif hidup

View File

@ -2582,7 +2582,6 @@ config.enable_openid_signin=Attiva l'accesso tramite OpenID
config.show_registration_button=Mostra Pulsane Registrazione config.show_registration_button=Mostra Pulsane Registrazione
config.require_sign_in_view=Richiedi l'accesso per visualizzare le pagine config.require_sign_in_view=Richiedi l'accesso per visualizzare le pagine
config.mail_notify=Attila le notifiche Email config.mail_notify=Attila le notifiche Email
config.disable_key_size_check=Disabilita controllo sulle dimensioni minime della chiave
config.enable_captcha=Attiva CAPTCHA config.enable_captcha=Attiva CAPTCHA
config.active_code_lives=Attiva Vita del Codice config.active_code_lives=Attiva Vita del Codice
config.reset_password_code_lives=Recupera il codice di scadenza del tempo del tuo account config.reset_password_code_lives=Recupera il codice di scadenza del tempo del tuo account

View File

@ -3080,7 +3080,6 @@ config.enable_openid_signin=OpenIDを使ったサインイン有効
config.show_registration_button=登録ボタンを表示 config.show_registration_button=登録ボタンを表示
config.require_sign_in_view=ページ閲覧にサインインが必要 config.require_sign_in_view=ページ閲覧にサインインが必要
config.mail_notify=メール通知有効 config.mail_notify=メール通知有効
config.disable_key_size_check=最小キー長のチェックが無効
config.enable_captcha=CAPTCHA有効 config.enable_captcha=CAPTCHA有効
config.active_code_lives=アカウント確認リンクの有効時間 config.active_code_lives=アカウント確認リンクの有効時間
config.reset_password_code_lives=アカウント回復リンクの有効時間 config.reset_password_code_lives=アカウント回復リンクの有効時間
@ -3526,7 +3525,6 @@ runs.commit=コミット
runs.scheduled=スケジュール済み runs.scheduled=スケジュール済み
runs.pushed_by=pushed by runs.pushed_by=pushed by
runs.invalid_workflow_helper=ワークフロー設定ファイルは無効です。あなたの設定ファイルを確認してください: %s runs.invalid_workflow_helper=ワークフロー設定ファイルは無効です。あなたの設定ファイルを確認してください: %s
runs.no_matching_runner_helper=一致するランナーがありません: %s
runs.actor=アクター runs.actor=アクター
runs.status=ステータス runs.status=ステータス
runs.actors_no_select=すべてのアクター runs.actors_no_select=すべてのアクター

View File

@ -1431,7 +1431,6 @@ config.enable_openid_signin=OpenID 로그인 활성화
config.show_registration_button=등록 버튼을 표시 config.show_registration_button=등록 버튼을 표시
config.require_sign_in_view=페이지를 보려면 로그인 필수 config.require_sign_in_view=페이지를 보려면 로그인 필수
config.mail_notify=이메일 알림 활성화 config.mail_notify=이메일 알림 활성화
config.disable_key_size_check=최소 키 크기 검사를 비활성화
config.enable_captcha=CAPTCHA 활성화 config.enable_captcha=CAPTCHA 활성화
config.active_code_lives=코드 만료 기한 config.active_code_lives=코드 만료 기한
config.default_keep_email_private=기본적으로 이메일 주소를 숨김 config.default_keep_email_private=기본적으로 이메일 주소를 숨김

View File

@ -2898,7 +2898,6 @@ config.enable_openid_signin=Iespējot pieteikšanos ar OpenID
config.show_registration_button=Rādīt reģistrēšanās pogu config.show_registration_button=Rādīt reģistrēšanās pogu
config.require_sign_in_view=Pieprasīt pieteikšanos, lai aplūkotu lapas config.require_sign_in_view=Pieprasīt pieteikšanos, lai aplūkotu lapas
config.mail_notify=Iespējot e-pasta paziņojumus config.mail_notify=Iespējot e-pasta paziņojumus
config.disable_key_size_check=Atspējot atslēgas minimālā garuma pārbaudi
config.enable_captcha=Iespējot drošības kodu config.enable_captcha=Iespējot drošības kodu
config.active_code_lives=Aktīvā koda ilgums config.active_code_lives=Aktīvā koda ilgums
config.reset_password_code_lives=Konta atjaunošanas koda beigšanās laiks config.reset_password_code_lives=Konta atjaunošanas koda beigšanās laiks
@ -3330,7 +3329,6 @@ runners.reset_registration_token_success=Izpildītāja reģistrācijas pilnvara
runs.all_workflows=Visas darbaplūsmas runs.all_workflows=Visas darbaplūsmas
runs.commit=Revīzija runs.commit=Revīzija
runs.invalid_workflow_helper=Darbaplūsmas konfigurācijas fails ir kļūdains. Pārbaudiet konfiugrācijas failu: %s runs.invalid_workflow_helper=Darbaplūsmas konfigurācijas fails ir kļūdains. Pārbaudiet konfiugrācijas failu: %s
runs.no_matching_runner_helper=Nav atbilstošu izpildītāju: %s
runs.status=Statuss runs.status=Statuss

View File

@ -2424,7 +2424,6 @@ config.enable_openid_signin=OpenID-inloggen inschakelen
config.show_registration_button=Registeren knop weergeven config.show_registration_button=Registeren knop weergeven
config.require_sign_in_view=Vereis inloggen om pagina's te kunnen bekijken config.require_sign_in_view=Vereis inloggen om pagina's te kunnen bekijken
config.mail_notify=Activeer e-mailnotificaties config.mail_notify=Activeer e-mailnotificaties
config.disable_key_size_check=Controle op key-lengte uitschakelen
config.enable_captcha=CAPTCHA inschakelen config.enable_captcha=CAPTCHA inschakelen
config.active_code_lives=Actieve Code leven config.active_code_lives=Actieve Code leven
config.reset_password_code_lives=Herstel accountcode vervaltijd config.reset_password_code_lives=Herstel accountcode vervaltijd

View File

@ -2313,7 +2313,6 @@ config.enable_openid_signin=Włącz logowanie za pomocą OpenID
config.show_registration_button=Pokazuj przycisk rejestracji config.show_registration_button=Pokazuj przycisk rejestracji
config.require_sign_in_view=Wymagaj zalogowania w celu wyświetlania stron config.require_sign_in_view=Wymagaj zalogowania w celu wyświetlania stron
config.mail_notify=Włącz powiadomienia e-mail config.mail_notify=Włącz powiadomienia e-mail
config.disable_key_size_check=Wyłącz sprawdzanie minimalnego rozmiaru klucza
config.enable_captcha=Włącz CAPTCHA config.enable_captcha=Włącz CAPTCHA
config.active_code_lives=Ważność kodów aktywacyjnych config.active_code_lives=Ważność kodów aktywacyjnych
config.reset_password_code_lives=Czas wygaśnięcia kodu przywracania konta config.reset_password_code_lives=Czas wygaśnięcia kodu przywracania konta

View File

@ -2977,7 +2977,6 @@ config.enable_openid_signin=Habilitar acesso via OpenID
config.show_registration_button=Mostrar botão de cadastro config.show_registration_button=Mostrar botão de cadastro
config.require_sign_in_view=Exigir acesso do usuário para a visualização de páginas config.require_sign_in_view=Exigir acesso do usuário para a visualização de páginas
config.mail_notify=Habilitar notificações de e-mail config.mail_notify=Habilitar notificações de e-mail
config.disable_key_size_check=Desabilitar verificação de tamanho mínimo da chave
config.enable_captcha=Habilitar o CAPTCHA config.enable_captcha=Habilitar o CAPTCHA
config.active_code_lives=Ativar Code Lives config.active_code_lives=Ativar Code Lives
config.reset_password_code_lives=Tempo de expiração do código de recuperação de conta config.reset_password_code_lives=Tempo de expiração do código de recuperação de conta
@ -3413,7 +3412,6 @@ runs.all_workflows=Todos os Workflows
runs.commit=Commit runs.commit=Commit
runs.pushed_by=push feito por runs.pushed_by=push feito por
runs.invalid_workflow_helper=O arquivo de configuração do workflow é inválido. Por favor, verifique seu arquivo de configuração: %s runs.invalid_workflow_helper=O arquivo de configuração do workflow é inválido. Por favor, verifique seu arquivo de configuração: %s
runs.no_matching_runner_helper=Nenhum runner correspondente: %s
runs.status=Status runs.status=Status

View File

@ -1997,7 +1997,7 @@ settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=Neste mom
settings.mirror_settings.docs.disabled_push_mirror.info=As réplicas foram desabilitadas pelo administrador deste sítio. settings.mirror_settings.docs.disabled_push_mirror.info=As réplicas foram desabilitadas pelo administrador deste sítio.
settings.mirror_settings.docs.no_new_mirrors=O seu repositório está a replicar modificações para, ou a partir, de outro repositório. Tenha em mente que não pode criar novas réplicas neste momento. settings.mirror_settings.docs.no_new_mirrors=O seu repositório está a replicar modificações para, ou a partir, de outro repositório. Tenha em mente que não pode criar novas réplicas neste momento.
settings.mirror_settings.docs.can_still_use=Embora não possa modificar réplicas existentes ou criar novas, ainda pode usar a sua réplica existente. settings.mirror_settings.docs.can_still_use=Embora não possa modificar réplicas existentes ou criar novas, ainda pode usar a sua réplica existente.
settings.mirror_settings.docs.pull_mirror_instructions=Para configurar uma réplica de outro repositório, consulte: settings.mirror_settings.docs.pull_mirror_instructions=Para configurar uma réplica de outro repositório, consulte
settings.mirror_settings.docs.more_information_if_disabled=Pode aprender mais sobre réplicas de envios e de puxadas aqui: settings.mirror_settings.docs.more_information_if_disabled=Pode aprender mais sobre réplicas de envios e de puxadas aqui:
settings.mirror_settings.docs.doc_link_title=Como é que eu replico repositórios? settings.mirror_settings.docs.doc_link_title=Como é que eu replico repositórios?
settings.mirror_settings.docs.doc_link_pull_section=a parte "Puxar de um repositório remoto" da documentação. settings.mirror_settings.docs.doc_link_pull_section=a parte "Puxar de um repositório remoto" da documentação.
@ -2054,7 +2054,7 @@ settings.pulls.default_allow_edits_from_maintainers=Permitir, por norma, que os
settings.releases_desc=Habilitar lançamentos no repositório settings.releases_desc=Habilitar lançamentos no repositório
settings.packages_desc=Habilitar o registo de pacotes do repositório settings.packages_desc=Habilitar o registo de pacotes do repositório
settings.projects_desc=Habilitar planeamentos no repositório settings.projects_desc=Habilitar planeamentos no repositório
settings.actions_desc=Habilitar operações no repositório settings.actions_desc=Habilitar operações no repositório (Gitea Actions)
settings.admin_settings=Configurações do administrador settings.admin_settings=Configurações do administrador
settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório
settings.admin_code_indexer=Indexador de código settings.admin_code_indexer=Indexador de código
@ -2117,7 +2117,7 @@ settings.delete_notices_2=- Esta operação eliminará permanentemente o reposit
settings.delete_notices_fork_1=- Derivações deste repositório tornar-se-ão independentes, após a eliminação. settings.delete_notices_fork_1=- Derivações deste repositório tornar-se-ão independentes, após a eliminação.
settings.deletion_success=O repositório foi eliminado. settings.deletion_success=O repositório foi eliminado.
settings.update_settings_success=As configurações do repositório foram modificadas. settings.update_settings_success=As configurações do repositório foram modificadas.
settings.update_settings_no_unit=O repositório deverá, ao menos, permitir algum tipo de interacção. settings.update_settings_no_unit=O repositório deve permitir pelo menos algum tipo de interoperabilidade.
settings.confirm_delete=Eliminar repositório settings.confirm_delete=Eliminar repositório
settings.add_collaborator=Adicionar colaborador settings.add_collaborator=Adicionar colaborador
settings.add_collaborator_success=O colaborador foi adicionado. settings.add_collaborator_success=O colaborador foi adicionado.
@ -2643,7 +2643,7 @@ teams.leave.detail=Sair de %s?
teams.can_create_org_repo=Criar repositórios teams.can_create_org_repo=Criar repositórios
teams.can_create_org_repo_helper=Os membros podem criar novos repositórios na organização. O criador terá acesso de administrador ao novo repositório. teams.can_create_org_repo_helper=Os membros podem criar novos repositórios na organização. O criador terá acesso de administrador ao novo repositório.
teams.none_access=Sem acesso teams.none_access=Sem acesso
teams.none_access_helper=Os membros não podem ver nem fazer qualquer outra operação nesta unidade. teams.none_access_helper=Os membros não podem ver nem fazer qualquer outra operação nesta unidade. Não tem qualquer efeito nos repositórios públicos.
teams.general_access=Acesso geral teams.general_access=Acesso geral
teams.general_access_helper=As permissões dos membros serão decididas pela tabela de permissões abaixo. teams.general_access_helper=As permissões dos membros serão decididas pela tabela de permissões abaixo.
teams.read_access=Ler teams.read_access=Ler
@ -2750,7 +2750,7 @@ dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git em falta
dashboard.sync_external_users=Sincronizar dados externos do utilizador dashboard.sync_external_users=Sincronizar dados externos do utilizador
dashboard.cleanup_hook_task_table=Limpar tabela hook_task dashboard.cleanup_hook_task_table=Limpar tabela hook_task
dashboard.cleanup_packages=Limpar pacotes expirados dashboard.cleanup_packages=Limpar pacotes expirados
dashboard.cleanup_actions=Registos expirados e artefactos das operações de limpeza dashboard.cleanup_actions=Limpar registos e artefactos expirados das operações
dashboard.server_uptime=Tempo em funcionamento contínuo do servidor dashboard.server_uptime=Tempo em funcionamento contínuo do servidor
dashboard.current_goroutine=Goroutines em execução dashboard.current_goroutine=Goroutines em execução
dashboard.current_memory_usage=Utilização de memória corrente dashboard.current_memory_usage=Utilização de memória corrente
@ -3080,7 +3080,6 @@ config.enable_openid_signin=Habilitar início de sessão com OpenID
config.show_registration_button=Mostrar botão de registo config.show_registration_button=Mostrar botão de registo
config.require_sign_in_view=Exigir sessão iniciada para visualizar páginas config.require_sign_in_view=Exigir sessão iniciada para visualizar páginas
config.mail_notify=Habilitar notificações por email config.mail_notify=Habilitar notificações por email
config.disable_key_size_check=Desabilitar verificação de tamanho mínimo da chave
config.enable_captcha=Habilitar o CAPTCHA config.enable_captcha=Habilitar o CAPTCHA
config.active_code_lives=Duração do código que está em uso config.active_code_lives=Duração do código que está em uso
config.reset_password_code_lives=Prazo do código de recuperação da conta config.reset_password_code_lives=Prazo do código de recuperação da conta
@ -3460,7 +3459,7 @@ secrets=Segredos
description=Os segredos serão transmitidos a certas operações e não poderão ser lidos de outra forma. description=Os segredos serão transmitidos a certas operações e não poderão ser lidos de outra forma.
none=Ainda não há segredos. none=Ainda não há segredos.
creation=Adicionar segredo creation=Adicionar segredo
creation.name_placeholder=apenas caracteres sem distinção de maiúsculas, alfanuméricos ou sublinhados, não podem começar com GITEA_ nem com GITHUB_ creation.name_placeholder=Só sublinhados ou alfanuméricos sem distinguir maiúsculas, sem começar com GITEA_ nem GITHUB_
creation.value_placeholder=Insira um conteúdo qualquer. Espaços em branco no início ou no fim serão omitidos. creation.value_placeholder=Insira um conteúdo qualquer. Espaços em branco no início ou no fim serão omitidos.
creation.success=O segredo "%s" foi adicionado. creation.success=O segredo "%s" foi adicionado.
creation.failed=Falhou ao adicionar o segredo. creation.failed=Falhou ao adicionar o segredo.
@ -3494,7 +3493,7 @@ runners.name=Nome
runners.owner_type=Tipo runners.owner_type=Tipo
runners.description=Descrição runners.description=Descrição
runners.labels=Rótulos runners.labels=Rótulos
runners.last_online=Última vez ligado runners.last_online=Última vez que esteve ligado
runners.runner_title=Executor runners.runner_title=Executor
runners.task_list=Tarefas recentes deste executor runners.task_list=Tarefas recentes deste executor
runners.task_list.no_tasks=Ainda não há tarefas. runners.task_list.no_tasks=Ainda não há tarefas.
@ -3526,7 +3525,7 @@ runs.commit=Cometimento
runs.scheduled=Agendadas runs.scheduled=Agendadas
runs.pushed_by=enviado por runs.pushed_by=enviado por
runs.invalid_workflow_helper=O ficheiro de configuração da sequência de trabalho é inválido. Verifique o seu ficheiro de configuração: %s runs.invalid_workflow_helper=O ficheiro de configuração da sequência de trabalho é inválido. Verifique o seu ficheiro de configuração: %s
runs.no_matching_runner_helper=Não há qualquer executor que corresponda: %s runs.no_matching_online_runner_helper=Não existem executores ligados que tenham o rótulo %s
runs.actor=Interveniente runs.actor=Interveniente
runs.status=Estado runs.status=Estado
runs.actors_no_select=Todos os intervenientes runs.actors_no_select=Todos os intervenientes

View File

@ -2979,7 +2979,6 @@ config.enable_openid_signin=Включение входа через OpenID
config.show_registration_button=Показать кнопку регистрации config.show_registration_button=Показать кнопку регистрации
config.require_sign_in_view=Для просмотра необходима авторизация config.require_sign_in_view=Для просмотра необходима авторизация
config.mail_notify=Почтовые уведомления config.mail_notify=Почтовые уведомления
config.disable_key_size_check=Отключить проверку на минимальный размер ключа
config.enable_captcha=Включить CAPTCHA config.enable_captcha=Включить CAPTCHA
config.active_code_lives=Время жизни кода для активации config.active_code_lives=Время жизни кода для активации
config.reset_password_code_lives=Время действия кода восстановления аккаунта config.reset_password_code_lives=Время действия кода восстановления аккаунта
@ -3418,7 +3417,6 @@ runs.all_workflows=Все рабочие потоки
runs.commit=коммит runs.commit=коммит
runs.pushed_by=отправлено runs.pushed_by=отправлено
runs.invalid_workflow_helper=Файл конфигурации рабочего потока некорректен. Пожалуйста, проверьте конфигурационный файл: %s runs.invalid_workflow_helper=Файл конфигурации рабочего потока некорректен. Пожалуйста, проверьте конфигурационный файл: %s
runs.no_matching_runner_helper=Нет подходящего раннера: %s
runs.actor=Актор runs.actor=Актор
runs.status=Статус runs.status=Статус
runs.actors_no_select=Все акторы runs.actors_no_select=Все акторы

View File

@ -2344,7 +2344,6 @@ config.enable_openid_signin=OpenID සංඥා සක්රීය කරන්
config.show_registration_button=ලියාපදිංචි බොත්තම පෙන්වන්න config.show_registration_button=ලියාපදිංචි බොත්තම පෙන්වන්න
config.require_sign_in_view=පිටු බැලීම සඳහා සිග්න්-දී අවශ්ය config.require_sign_in_view=පිටු බැලීම සඳහා සිග්න්-දී අවශ්ය
config.mail_notify=වි-තැපැල් දැනුම්දීම් සබල කරන්න config.mail_notify=වි-තැපැල් දැනුම්දීම් සබල කරන්න
config.disable_key_size_check=අවම කී තරම පරීක්ෂා කරන්න අක්රීය
config.enable_captcha=කැප්චා සක්රීය කරන්න config.enable_captcha=කැප්චා සක්රීය කරන්න
config.active_code_lives=ක්රියාකාරී කේතය Lives config.active_code_lives=ක්රියාකාරී කේතය Lives
config.reset_password_code_lives=ගිණුම් කේත කල් ඉකුත් වීමේ වේලාව නැවත ලබා ගන්න config.reset_password_code_lives=ගිණුම් කේත කල් ඉකුත් වීමේ වේලාව නැවත ලබා ගන්න

View File

@ -1874,7 +1874,6 @@ config.enable_openid_signin=Aktivera OpenID-inloggning
config.show_registration_button=Visa registreringsknapp config.show_registration_button=Visa registreringsknapp
config.require_sign_in_view=Kräv inloggning för att visa sidor config.require_sign_in_view=Kräv inloggning för att visa sidor
config.mail_notify=Aktivera Mejlnotifikationer config.mail_notify=Aktivera Mejlnotifikationer
config.disable_key_size_check=Avaktivera kontroll av minsta tillåtna nyckelstorlek
config.enable_captcha=Aktivera CAPTCHA config.enable_captcha=Aktivera CAPTCHA
config.active_code_lives=Aktivera livstid för koder config.active_code_lives=Aktivera livstid för koder
config.default_keep_email_private=Dölj mejladresser som standard config.default_keep_email_private=Dölj mejladresser som standard

View File

@ -3019,7 +3019,6 @@ config.enable_openid_signin=OpenID Oturum Açmayı Etkinleştiriniz
config.show_registration_button=Kaydolma Düğmesini Göster config.show_registration_button=Kaydolma Düğmesini Göster
config.require_sign_in_view=Sayfaları Görüntülemek için Giriş Yapmaya Zorla config.require_sign_in_view=Sayfaları Görüntülemek için Giriş Yapmaya Zorla
config.mail_notify=E-Posta Bildirimlerini Etkinleştir config.mail_notify=E-Posta Bildirimlerini Etkinleştir
config.disable_key_size_check=Minimum Anahtar Uzunluğu Kontrolünü Devre Dışı Bırak
config.enable_captcha=CAPTCHA'yı Etkinleştir config.enable_captcha=CAPTCHA'yı Etkinleştir
config.active_code_lives=Kod Yaşamlarını Aktifleştir config.active_code_lives=Kod Yaşamlarını Aktifleştir
config.reset_password_code_lives=Hesap Kodunun Sona Erme Zamanını Kurtar config.reset_password_code_lives=Hesap Kodunun Sona Erme Zamanını Kurtar
@ -3461,7 +3460,6 @@ runs.all_workflows=Tüm İş Akışları
runs.commit=İşle runs.commit=İşle
runs.pushed_by=iten runs.pushed_by=iten
runs.invalid_workflow_helper=İş akışı yapılandırma dosyası geçersiz. Lütfen yapılandırma dosyanızı denetleyin: %s runs.invalid_workflow_helper=İş akışı yapılandırma dosyası geçersiz. Lütfen yapılandırma dosyanızı denetleyin: %s
runs.no_matching_runner_helper=Eşleşen çalıştırıcı yok: %s
runs.actor=Aktör runs.actor=Aktör
runs.status=Durum runs.status=Durum
runs.actors_no_select=Tüm aktörler runs.actors_no_select=Tüm aktörler

View File

@ -2397,7 +2397,6 @@ config.enable_openid_signin=Увімкнути реєстрацію за доп
config.show_registration_button=`Показувати кнопку "Реєстрація"` config.show_registration_button=`Показувати кнопку "Реєстрація"`
config.require_sign_in_view=Вимагати авторизації для перегляду сторінок config.require_sign_in_view=Вимагати авторизації для перегляду сторінок
config.mail_notify=Увімкнути сповіщення електронною поштою config.mail_notify=Увімкнути сповіщення електронною поштою
config.disable_key_size_check=Вимкнути перевірку мінімального розміру ключа
config.enable_captcha=Увімкнути CAPTCHA config.enable_captcha=Увімкнути CAPTCHA
config.active_code_lives=Час актуальності кода підтвердження config.active_code_lives=Час актуальності кода підтвердження
config.reset_password_code_lives=Відновлення часу закінчення терміну дії коду облікового запису config.reset_password_code_lives=Відновлення часу закінчення терміну дії коду облікового запису

View File

@ -3063,7 +3063,6 @@ config.enable_openid_signin=启用 OpenID 登录
config.show_registration_button=显示注册按钮 config.show_registration_button=显示注册按钮
config.require_sign_in_view=启用登录访问限制 config.require_sign_in_view=启用登录访问限制
config.mail_notify=启用邮件通知 config.mail_notify=启用邮件通知
config.disable_key_size_check=禁用密钥最小长度检查
config.enable_captcha=启用登录验证码 config.enable_captcha=启用登录验证码
config.active_code_lives=激活用户链接有效期 config.active_code_lives=激活用户链接有效期
config.reset_password_code_lives=恢复账户验证码过期时间 config.reset_password_code_lives=恢复账户验证码过期时间
@ -3509,7 +3508,6 @@ runs.commit=提交
runs.scheduled=已计划的 runs.scheduled=已计划的
runs.pushed_by=推送者 runs.pushed_by=推送者
runs.invalid_workflow_helper=工作流配置文件无效。请检查您的配置文件: %s runs.invalid_workflow_helper=工作流配置文件无效。请检查您的配置文件: %s
runs.no_matching_runner_helper=没有匹配的runner%s
runs.actor=操作者 runs.actor=操作者
runs.status=状态 runs.status=状态
runs.actors_no_select=所有操作者 runs.actors_no_select=所有操作者

View File

@ -839,7 +839,6 @@ config.db_path=資料庫路徑
config.service_config=服務設定 config.service_config=服務設定
config.show_registration_button=顯示註冊按鈕 config.show_registration_button=顯示註冊按鈕
config.disable_key_size_check=禁用金鑰最小長度檢查
config.active_code_lives=啟用用戶連結有效期 config.active_code_lives=啟用用戶連結有效期
config.webhook_config=Webhook 設定 config.webhook_config=Webhook 設定

View File

@ -2808,7 +2808,6 @@ config.enable_openid_signin=啟用 OpenID 登入
config.show_registration_button=顯示註冊按鈕 config.show_registration_button=顯示註冊按鈕
config.require_sign_in_view=需要登入才能瀏覽頁面 config.require_sign_in_view=需要登入才能瀏覽頁面
config.mail_notify=啟用郵件通知 config.mail_notify=啟用郵件通知
config.disable_key_size_check=停用金鑰最小長度檢查
config.enable_captcha=啟用驗證碼 config.enable_captcha=啟用驗證碼
config.active_code_lives=啟用用戶連結有效期 config.active_code_lives=啟用用戶連結有效期
config.reset_password_code_lives=帳戶救援碼有效時間 config.reset_password_code_lives=帳戶救援碼有效時間
@ -3225,7 +3224,6 @@ runners.reset_registration_token_success=成功重設了 Runner 註冊 Token
runs.all_workflows=所有工作流程 runs.all_workflows=所有工作流程
runs.commit=提交 runs.commit=提交
runs.invalid_workflow_helper=工作流程設定檔無效。請檢查您的設定檔: %s runs.invalid_workflow_helper=工作流程設定檔無效。請檢查您的設定檔: %s
runs.no_matching_runner_helper=找不到符合的 Runner: %s
runs.status=狀態 runs.status=狀態
runs.no_runs=工作流程沒有執行過。 runs.no_runs=工作流程沒有執行過。

View File

@ -63,7 +63,6 @@ package actions
import ( import (
"crypto/md5" "crypto/md5"
"errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
@ -423,15 +422,15 @@ func (ar artifactRoutes) downloadArtifact(ctx *ArtifactContext) {
} }
artifactID := ctx.ParamsInt64("artifact_id") artifactID := ctx.ParamsInt64("artifact_id")
artifact, err := actions.GetArtifactByID(ctx, artifactID) artifact, exist, err := db.GetByID[actions.ActionArtifact](ctx, artifactID)
if errors.Is(err, util.ErrNotExist) { if err != nil {
log.Error("Error getting artifact: %v", err)
ctx.Error(http.StatusNotFound, err.Error())
return
} else if err != nil {
log.Error("Error getting artifact: %v", err) log.Error("Error getting artifact: %v", err)
ctx.Error(http.StatusInternalServerError, err.Error()) ctx.Error(http.StatusInternalServerError, err.Error())
return return
} else if !exist {
log.Error("artifact with ID %d does not exist", artifactID)
ctx.Error(http.StatusNotFound, fmt.Sprintf("artifact with ID %d does not exist", artifactID))
return
} }
if artifact.RunID != runID { if artifact.RunID != runID {
log.Error("Error dismatch runID and artifactID, task: %v, artifact: %v", runID, artifactID) log.Error("Error dismatch runID and artifactID, task: %v, artifact: %v", runID, artifactID)

View File

@ -94,6 +94,12 @@ func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[s
func getVariablesOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string { func getVariablesOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string {
variables := map[string]string{} variables := map[string]string{}
// Global
globalVariables, err := db.Find[actions_model.ActionVariable](ctx, actions_model.FindVariablesOpts{})
if err != nil {
log.Error("find global variables: %v", err)
}
// Org / User level // Org / User level
ownerVariables, err := db.Find[actions_model.ActionVariable](ctx, actions_model.FindVariablesOpts{OwnerID: task.Job.Run.Repo.OwnerID}) ownerVariables, err := db.Find[actions_model.ActionVariable](ctx, actions_model.FindVariablesOpts{OwnerID: task.Job.Run.Repo.OwnerID})
if err != nil { if err != nil {
@ -106,8 +112,8 @@ func getVariablesOfTask(ctx context.Context, task *actions_model.ActionTask) map
log.Error("find variables of repo: %d, error: %v", task.Job.Run.RepoID, err) log.Error("find variables of repo: %d, error: %v", task.Job.Run.RepoID, err)
} }
// Level precedence: Repo > Org / User // Level precedence: Repo > Org / User > Global
for _, v := range append(ownerVariables, repoVariables...) { for _, v := range append(globalVariables, append(ownerVariables, repoVariables...)...) {
variables[v.Name] = v.Data variables[v.Name] = v.Data
} }

View File

@ -822,9 +822,7 @@ func Routes() *web.Route {
m.Use(securityHeaders()) m.Use(securityHeaders())
if setting.CORSConfig.Enabled { if setting.CORSConfig.Enabled {
m.Use(cors.Handler(cors.Options{ m.Use(cors.Handler(cors.Options{
// Scheme: setting.CORSConfig.Scheme, // FIXME: the cors middleware needs scheme option AllowedOrigins: setting.CORSConfig.AllowDomain,
AllowedOrigins: setting.CORSConfig.AllowDomain,
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
AllowedMethods: setting.CORSConfig.Methods, AllowedMethods: setting.CORSConfig.Methods,
AllowCredentials: setting.CORSConfig.AllowCredentials, AllowCredentials: setting.CORSConfig.AllowCredentials,
AllowedHeaders: append([]string{"Authorization", "X-Gitea-OTP"}, setting.CORSConfig.Headers...), AllowedHeaders: append([]string{"Authorization", "X-Gitea-OTP"}, setting.CORSConfig.Headers...),

View File

@ -227,11 +227,18 @@ func GetPushMirrorByName(ctx *context.APIContext) {
mirrorName := ctx.Params(":name") mirrorName := ctx.Params(":name")
// Get push mirror of a specific repo by remoteName // Get push mirror of a specific repo by remoteName
pushMirror, err := repo_model.GetPushMirror(ctx, repo_model.PushMirrorOptions{RepoID: ctx.Repo.Repository.ID, RemoteName: mirrorName}) pushMirror, exist, err := db.Get[repo_model.PushMirror](ctx, repo_model.PushMirrorOptions{
RepoID: ctx.Repo.Repository.ID,
RemoteName: mirrorName,
}.ToConds())
if err != nil { if err != nil {
ctx.Error(http.StatusNotFound, "GetPushMirrors", err) ctx.Error(http.StatusInternalServerError, "GetPushMirrors", err)
return
} else if !exist {
ctx.Error(http.StatusNotFound, "GetPushMirrors", nil)
return return
} }
m, err := convert.ToPushMirror(ctx, pushMirror) m, err := convert.ToPushMirror(ctx, pushMirror)
if err != nil { if err != nil {
ctx.ServerError("GetPushMirrorByRemoteName", err) ctx.ServerError("GetPushMirrorByRemoteName", err)
@ -368,7 +375,7 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro
RemoteAddress: remoteAddress, RemoteAddress: remoteAddress,
} }
if err = repo_model.InsertPushMirror(ctx, pushMirror); err != nil { if err = db.Insert(ctx, pushMirror); err != nil {
ctx.ServerError("InsertPushMirror", err) ctx.ServerError("InsertPushMirror", err)
return return
} }

View File

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"code.gitea.io/gitea/models/db"
system_model "code.gitea.io/gitea/models/system" system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -55,7 +56,7 @@ func DeleteNotices(ctx *context.Context) {
} }
} }
if err := system_model.DeleteNoticesByIDs(ctx, ids); err != nil { if err := db.DeleteByIDs[system_model.Notice](ctx, ids...); err != nil {
ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error()) ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error())
ctx.Status(http.StatusInternalServerError) ctx.Status(http.StatusInternalServerError)
} else { } else {

View File

@ -28,16 +28,16 @@ func requireSignIn(ctx *context.Context) {
func gitHTTPRouters(m *web.Route) { func gitHTTPRouters(m *web.Route) {
m.Group("", func() { m.Group("", func() {
m.PostOptions("/git-upload-pack", repo.ServiceUploadPack) m.Methods("POST,OPTIONS", "/git-upload-pack", repo.ServiceUploadPack)
m.PostOptions("/git-receive-pack", repo.ServiceReceivePack) m.Methods("POST,OPTIONS", "/git-receive-pack", repo.ServiceReceivePack)
m.GetOptions("/info/refs", repo.GetInfoRefs) m.Methods("GET,OPTIONS", "/info/refs", repo.GetInfoRefs)
m.GetOptions("/HEAD", repo.GetTextFile("HEAD")) m.Methods("GET,OPTIONS", "/HEAD", repo.GetTextFile("HEAD"))
m.GetOptions("/objects/info/alternates", repo.GetTextFile("objects/info/alternates")) m.Methods("GET,OPTIONS", "/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
m.GetOptions("/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates")) m.Methods("GET,OPTIONS", "/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
m.GetOptions("/objects/info/packs", repo.GetInfoPacks) m.Methods("GET,OPTIONS", "/objects/info/packs", repo.GetInfoPacks)
m.GetOptions("/objects/info/{file:[^/]*}", repo.GetTextFile("")) m.Methods("GET,OPTIONS", "/objects/info/{file:[^/]*}", repo.GetTextFile(""))
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject) m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile) m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile) m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
}, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb()) }, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
} }

View File

@ -33,10 +33,6 @@ func DummyOK(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
func DummyBadRequest(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusBadRequest)
}
func RobotsTxt(w http.ResponseWriter, req *http.Request) { func RobotsTxt(w http.ResponseWriter, req *http.Request) {
robotsTxt := util.FilePathJoinAbs(setting.CustomPath, "public/robots.txt") robotsTxt := util.FilePathJoinAbs(setting.CustomPath, "public/robots.txt")
if ok, _ := util.IsExist(robotsTxt); !ok { if ok, _ := util.IsExist(robotsTxt); !ok {

View File

@ -418,7 +418,7 @@ func SettingsPost(ctx *context.Context) {
Interval: interval, Interval: interval,
RemoteAddress: remoteAddress, RemoteAddress: remoteAddress,
} }
if err := repo_model.InsertPushMirror(ctx, m); err != nil { if err := db.Insert(ctx, m); err != nil {
ctx.ServerError("InsertPushMirror", err) ctx.ServerError("InsertPushMirror", err)
return return
} }

View File

@ -15,9 +15,10 @@ import (
) )
const ( const (
tplRepoVariables base.TplName = "repo/settings/actions" tplRepoVariables base.TplName = "repo/settings/actions"
tplOrgVariables base.TplName = "org/settings/actions" tplOrgVariables base.TplName = "org/settings/actions"
tplUserVariables base.TplName = "user/settings/actions" tplUserVariables base.TplName = "user/settings/actions"
tplAdminVariables base.TplName = "admin/actions"
) )
type variablesCtx struct { type variablesCtx struct {
@ -26,6 +27,7 @@ type variablesCtx struct {
IsRepo bool IsRepo bool
IsOrg bool IsOrg bool
IsUser bool IsUser bool
IsGlobal bool
VariablesTemplate base.TplName VariablesTemplate base.TplName
RedirectLink string RedirectLink string
} }
@ -33,6 +35,7 @@ type variablesCtx struct {
func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) { func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
if ctx.Data["PageIsRepoSettings"] == true { if ctx.Data["PageIsRepoSettings"] == true {
return &variablesCtx{ return &variablesCtx{
OwnerID: 0,
RepoID: ctx.Repo.Repository.ID, RepoID: ctx.Repo.Repository.ID,
IsRepo: true, IsRepo: true,
VariablesTemplate: tplRepoVariables, VariablesTemplate: tplRepoVariables,
@ -48,6 +51,7 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
} }
return &variablesCtx{ return &variablesCtx{
OwnerID: ctx.ContextUser.ID, OwnerID: ctx.ContextUser.ID,
RepoID: 0,
IsOrg: true, IsOrg: true,
VariablesTemplate: tplOrgVariables, VariablesTemplate: tplOrgVariables,
RedirectLink: ctx.Org.OrgLink + "/settings/actions/variables", RedirectLink: ctx.Org.OrgLink + "/settings/actions/variables",
@ -57,12 +61,23 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
if ctx.Data["PageIsUserSettings"] == true { if ctx.Data["PageIsUserSettings"] == true {
return &variablesCtx{ return &variablesCtx{
OwnerID: ctx.Doer.ID, OwnerID: ctx.Doer.ID,
RepoID: 0,
IsUser: true, IsUser: true,
VariablesTemplate: tplUserVariables, VariablesTemplate: tplUserVariables,
RedirectLink: setting.AppSubURL + "/user/settings/actions/variables", RedirectLink: setting.AppSubURL + "/user/settings/actions/variables",
}, nil }, nil
} }
if ctx.Data["PageIsAdmin"] == true {
return &variablesCtx{
OwnerID: 0,
RepoID: 0,
IsGlobal: true,
VariablesTemplate: tplAdminVariables,
RedirectLink: setting.AppSubURL + "/admin/actions/variables",
}, nil
}
return nil, errors.New("unable to set Variables context") return nil, errors.New("unable to set Variables context")
} }

View File

@ -60,13 +60,12 @@ const (
GzipMinSize = 1400 GzipMinSize = 1400
) )
// CorsHandler return a http handler who set CORS options if enabled by config // optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests.
func CorsHandler() func(next http.Handler) http.Handler { func optionsCorsHandler() func(next http.Handler) http.Handler {
var corsHandler func(next http.Handler) http.Handler
if setting.CORSConfig.Enabled { if setting.CORSConfig.Enabled {
return cors.Handler(cors.Options{ corsHandler = cors.Handler(cors.Options{
// Scheme: setting.CORSConfig.Scheme, // FIXME: the cors middleware needs scheme option AllowedOrigins: setting.CORSConfig.AllowDomain,
AllowedOrigins: setting.CORSConfig.AllowDomain,
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
AllowedMethods: setting.CORSConfig.Methods, AllowedMethods: setting.CORSConfig.Methods,
AllowCredentials: setting.CORSConfig.AllowCredentials, AllowCredentials: setting.CORSConfig.AllowCredentials,
AllowedHeaders: setting.CORSConfig.Headers, AllowedHeaders: setting.CORSConfig.Headers,
@ -75,7 +74,23 @@ func CorsHandler() func(next http.Handler) http.Handler {
} }
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return next return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodOptions {
if corsHandler != nil && r.Header.Get("Access-Control-Request-Method") != "" {
corsHandler(next).ServeHTTP(w, r)
} else {
// it should explicitly deny OPTIONS requests if CORS handler is not executed, to avoid the next GET/POST handler being incorrectly called by the OPTIONS request
w.WriteHeader(http.StatusMethodNotAllowed)
}
return
}
// for non-OPTIONS requests, call the CORS handler to add some related headers like "Vary"
if corsHandler != nil {
corsHandler(next).ServeHTTP(w, r)
} else {
next.ServeHTTP(w, r)
}
})
} }
} }
@ -218,7 +233,7 @@ func Routes() *web.Route {
routes := web.NewRoute() routes := web.NewRoute()
routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler
routes.Methods("GET, HEAD", "/assets/*", CorsHandler(), public.FileHandlerFunc()) routes.Methods("GET, HEAD, OPTIONS", "/assets/*", optionsCorsHandler(), public.FileHandlerFunc())
routes.Methods("GET, HEAD", "/avatars/*", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars)) routes.Methods("GET, HEAD", "/avatars/*", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
routes.Methods("GET, HEAD", "/repo-avatars/*", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars)) routes.Methods("GET, HEAD", "/repo-avatars/*", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
routes.Methods("GET, HEAD", "/apple-touch-icon.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png")) routes.Methods("GET, HEAD", "/apple-touch-icon.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
@ -417,7 +432,7 @@ func registerRoutes(m *web.Route) {
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo_setting.PackagistHooksEditPost) m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo_setting.PackagistHooksEditPost)
} }
addSettingVariablesRoutes := func() { addSettingsVariablesRoutes := func() {
m.Group("/variables", func() { m.Group("/variables", func() {
m.Get("", repo_setting.Variables) m.Get("", repo_setting.Variables)
m.Post("/new", web.Bind(forms.EditVariableForm{}), repo_setting.VariableCreate) m.Post("/new", web.Bind(forms.EditVariableForm{}), repo_setting.VariableCreate)
@ -458,8 +473,8 @@ func registerRoutes(m *web.Route) {
m.Get("/change-password", func(ctx *context.Context) { m.Get("/change-password", func(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/account") ctx.Redirect(setting.AppSubURL + "/user/settings/account")
}) })
m.Any("/*", CorsHandler(), public.FileHandlerFunc()) m.Methods("GET, HEAD", "/*", public.FileHandlerFunc())
}, CorsHandler()) }, optionsCorsHandler())
m.Group("/explore", func() { m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) { m.Get("", func(ctx *context.Context) {
@ -532,14 +547,11 @@ func registerRoutes(m *web.Route) {
// TODO manage redirection // TODO manage redirection
m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth) m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
}, ignSignInAndCsrf, reqSignIn) }, ignSignInAndCsrf, reqSignIn)
m.Options("/login/oauth/userinfo", CorsHandler(), misc.DummyBadRequest)
m.Get("/login/oauth/userinfo", ignSignInAndCsrf, auth.InfoOAuth) m.Methods("GET, OPTIONS", "/login/oauth/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth)
m.Options("/login/oauth/access_token", CorsHandler(), misc.DummyBadRequest) m.Methods("POST, OPTIONS", "/login/oauth/access_token", optionsCorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
m.Post("/login/oauth/access_token", CorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth) m.Methods("GET, OPTIONS", "/login/oauth/keys", optionsCorsHandler(), ignSignInAndCsrf, auth.OIDCKeys)
m.Options("/login/oauth/keys", CorsHandler(), misc.DummyBadRequest) m.Methods("POST, OPTIONS", "/login/oauth/introspect", optionsCorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
m.Get("/login/oauth/keys", ignSignInAndCsrf, auth.OIDCKeys)
m.Options("/login/oauth/introspect", CorsHandler(), misc.DummyBadRequest)
m.Post("/login/oauth/introspect", CorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
m.Group("/user/settings", func() { m.Group("/user/settings", func() {
m.Get("", user_setting.Profile) m.Get("", user_setting.Profile)
@ -618,7 +630,7 @@ func registerRoutes(m *web.Route) {
m.Get("", user_setting.RedirectToDefaultSetting) m.Get("", user_setting.RedirectToDefaultSetting)
addSettingsRunnersRoutes() addSettingsRunnersRoutes()
addSettingsSecretsRoutes() addSettingsSecretsRoutes()
addSettingVariablesRoutes() addSettingsVariablesRoutes()
}, actions.MustEnableActions) }, actions.MustEnableActions)
m.Get("/organization", user_setting.Organization) m.Get("/organization", user_setting.Organization)
@ -763,13 +775,14 @@ func registerRoutes(m *web.Route) {
m.Group("/actions", func() { m.Group("/actions", func() {
m.Get("", admin.RedirectToDefaultSetting) m.Get("", admin.RedirectToDefaultSetting)
addSettingsRunnersRoutes() addSettingsRunnersRoutes()
addSettingsVariablesRoutes()
}) })
}, adminReq, ctxDataSet("EnableOAuth2", setting.OAuth2.Enable, "EnablePackages", setting.Packages.Enabled)) }, adminReq, ctxDataSet("EnableOAuth2", setting.OAuth2.Enable, "EnablePackages", setting.Packages.Enabled))
// ***** END: Admin ***** // ***** END: Admin *****
m.Group("", func() { m.Group("", func() {
m.Get("/{username}", user.UsernameSubRoute) m.Get("/{username}", user.UsernameSubRoute)
m.Get("/attachments/{uuid}", repo.GetAttachment) m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), repo.GetAttachment)
}, ignSignIn) }, ignSignIn)
m.Post("/{username}", reqSignIn, context_service.UserAssignmentWeb(), user.Action) m.Post("/{username}", reqSignIn, context_service.UserAssignmentWeb(), user.Action)
@ -905,7 +918,7 @@ func registerRoutes(m *web.Route) {
m.Get("", org_setting.RedirectToDefaultSetting) m.Get("", org_setting.RedirectToDefaultSetting)
addSettingsRunnersRoutes() addSettingsRunnersRoutes()
addSettingsSecretsRoutes() addSettingsSecretsRoutes()
addSettingVariablesRoutes() addSettingsVariablesRoutes()
}, actions.MustEnableActions) }, actions.MustEnableActions)
m.Methods("GET,POST", "/delete", org.SettingsDelete) m.Methods("GET,POST", "/delete", org.SettingsDelete)
@ -1084,7 +1097,7 @@ func registerRoutes(m *web.Route) {
m.Get("", repo_setting.RedirectToDefaultSetting) m.Get("", repo_setting.RedirectToDefaultSetting)
addSettingsRunnersRoutes() addSettingsRunnersRoutes()
addSettingsSecretsRoutes() addSettingsSecretsRoutes()
addSettingVariablesRoutes() addSettingsVariablesRoutes()
}, actions.MustEnableActions) }, actions.MustEnableActions)
// the follow handler must be under "settings", otherwise this incomplete repo can't be accessed // the follow handler must be under "settings", otherwise this incomplete repo can't be accessed
m.Group("/migrate", func() { m.Group("/migrate", func() {

View File

@ -33,7 +33,7 @@ func DeletePublicKey(ctx context.Context, doer *user_model.User, id int64) (err
} }
defer committer.Close() defer committer.Close()
if err = asymkey_model.DeletePublicKeys(dbCtx, id); err != nil { if _, err = db.DeleteByID[asymkey_model.PublicKey](dbCtx, id); err != nil {
return err return err
} }

View File

@ -12,6 +12,7 @@ import (
"strings" "strings"
"time" "time"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/lfs"
@ -93,8 +94,9 @@ func SyncPushMirror(ctx context.Context, mirrorID int64) bool {
log.Error("PANIC whilst syncPushMirror[%d] Panic: %v\nStacktrace: %s", mirrorID, err, log.Stack(2)) log.Error("PANIC whilst syncPushMirror[%d] Panic: %v\nStacktrace: %s", mirrorID, err, log.Stack(2))
}() }()
m, err := repo_model.GetPushMirror(ctx, repo_model.PushMirrorOptions{ID: mirrorID}) // TODO: Handle "!exist" better
if err != nil { m, exist, err := db.GetByID[repo_model.PushMirror](ctx, mirrorID)
if err != nil || !exist {
log.Error("GetPushMirrorByID [%d]: %v", mirrorID, err) log.Error("GetPushMirrorByID [%d]: %v", mirrorID, err)
return false return false
} }

View File

@ -339,7 +339,7 @@ func DeleteReleaseByID(ctx context.Context, repo *repo_model.Repository, rel *re
}, repository.NewPushCommits()) }, repository.NewPushCommits())
notify_service.DeleteRef(ctx, doer, repo, refName) notify_service.DeleteRef(ctx, doer, repo, refName)
if err := repo_model.DeleteReleaseByID(ctx, rel.ID); err != nil { if _, err := db.DeleteByID[repo_model.Release](ctx, rel.ID); err != nil {
return fmt.Errorf("DeleteReleaseByID: %w", err) return fmt.Errorf("DeleteReleaseByID: %w", err)
} }
} else { } else {

View File

@ -177,7 +177,7 @@ func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver
CommitID: r.CommitID, CommitID: r.CommitID,
Status: repo_model.ArchiverGenerating, Status: repo_model.ArchiverGenerating,
} }
if err := repo_model.AddRepoArchiver(ctx, archiver); err != nil { if err := db.Insert(ctx, archiver); err != nil {
return nil, err return nil, err
} }
} }
@ -309,7 +309,7 @@ func StartArchive(request *ArchiveRequest) error {
} }
func deleteOldRepoArchiver(ctx context.Context, archiver *repo_model.RepoArchiver) error { func deleteOldRepoArchiver(ctx context.Context, archiver *repo_model.RepoArchiver) error {
if err := repo_model.DeleteRepoArchiver(ctx, archiver); err != nil { if _, err := db.DeleteByID[repo_model.RepoArchiver](ctx, archiver.ID); err != nil {
return err return err
} }
p := archiver.RelativePath() p := archiver.RelativePath()

View File

@ -76,7 +76,7 @@ func DeleteSecretByName(ctx context.Context, ownerID, repoID int64, name string)
} }
func deleteSecret(ctx context.Context, s *secret_model.Secret) error { func deleteSecret(ctx context.Context, s *secret_model.Secret) error {
if _, err := db.DeleteByID(ctx, s.ID, s); err != nil { if _, err := db.DeleteByID[secret_model.Secret](ctx, s.ID); err != nil {
return err return err
} }
return nil return nil

View File

@ -185,7 +185,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
} }
// ***** END: ExternalLoginUser ***** // ***** END: ExternalLoginUser *****
if _, err = db.DeleteByID(ctx, u.ID, new(user_model.User)); err != nil { if _, err = db.DeleteByID[user_model.User](ctx, u.ID); err != nil {
return fmt.Errorf("delete: %w", err) return fmt.Errorf("delete: %w", err)
} }

View File

@ -3,5 +3,8 @@
{{if eq .PageType "runners"}} {{if eq .PageType "runners"}}
{{template "shared/actions/runner_list" .}} {{template "shared/actions/runner_list" .}}
{{end}} {{end}}
{{if eq .PageType "variables"}}
{{template "shared/variables/variable_list" .}}
{{end}}
</div> </div>
{{template "admin/layout_footer" .}} {{template "admin/layout_footer" .}}

View File

@ -60,12 +60,15 @@
{{end}} {{end}}
{{end}} {{end}}
{{if .EnableActions}} {{if .EnableActions}}
<details class="item toggleable-item" {{if .PageIsSharedSettingsRunners}}open{{end}}> <details class="item toggleable-item" {{if or .PageIsSharedSettingsRunners .PageIsSharedSettingsVariables}}open{{end}}>
<summary>{{ctx.Locale.Tr "actions.actions"}}</summary> <summary>{{ctx.Locale.Tr "actions.actions"}}</summary>
<div class="menu"> <div class="menu">
<a class="{{if .PageIsSharedSettingsRunners}}active {{end}}item" href="{{AppSubUrl}}/admin/actions/runners"> <a class="{{if .PageIsSharedSettingsRunners}}active {{end}}item" href="{{AppSubUrl}}/admin/actions/runners">
{{ctx.Locale.Tr "actions.runners"}} {{ctx.Locale.Tr "actions.runners"}}
</a> </a>
<a class="{{if .PageIsSharedSettingsVariables}}active {{end}}item" href="{{AppSubUrl}}/admin/actions/variables">
{{ctx.Locale.Tr "actions.variables"}}
</a>
</div> </div>
</details> </details>
{{end}} {{end}}

View File

@ -7,17 +7,88 @@ import (
"net/http" "net/http"
"testing" "testing"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/tests" "code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestCORSNotSet(t *testing.T) { func TestCORS(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()
req := NewRequest(t, "GET", "/api/v1/version") t.Run("CORS enabled", func(t *testing.T) {
session := loginUser(t, "user2") defer test.MockVariableValue(&setting.CORSConfig.Enabled, true)()
resp := session.MakeRequest(t, req, http.StatusOK) defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
assert.Equal(t, resp.Code, http.StatusOK)
corsHeader := resp.Header().Get("Access-Control-Allow-Origin") t.Run("API with CORS", func(t *testing.T) {
assert.Empty(t, corsHeader, "Access-Control-Allow-Origin: generated header should match") // header not set // GET api with no CORS header
req := NewRequest(t, "GET", "/api/v1/version")
resp := MakeRequest(t, req, http.StatusOK)
assert.Empty(t, resp.Header().Get("Access-Control-Allow-Origin"))
assert.Contains(t, resp.Header().Values("Vary"), "Origin")
// OPTIONS api for CORS
req = NewRequest(t, "OPTIONS", "/api/v1/version").
SetHeader("Origin", "https://example.com").
SetHeader("Access-Control-Request-Method", "GET")
resp = MakeRequest(t, req, http.StatusOK)
assert.NotEmpty(t, resp.Header().Get("Access-Control-Allow-Origin"))
assert.Contains(t, resp.Header().Values("Vary"), "Origin")
})
t.Run("Web with CORS", func(t *testing.T) {
// GET userinfo with no CORS header
req := NewRequest(t, "GET", "/login/oauth/userinfo")
resp := MakeRequest(t, req, http.StatusUnauthorized)
assert.Empty(t, resp.Header().Get("Access-Control-Allow-Origin"))
assert.Contains(t, resp.Header().Values("Vary"), "Origin")
// OPTIONS userinfo for CORS
req = NewRequest(t, "OPTIONS", "/login/oauth/userinfo").
SetHeader("Origin", "https://example.com").
SetHeader("Access-Control-Request-Method", "GET")
resp = MakeRequest(t, req, http.StatusOK)
assert.NotEmpty(t, resp.Header().Get("Access-Control-Allow-Origin"))
assert.Contains(t, resp.Header().Values("Vary"), "Origin")
// OPTIONS userinfo for non-CORS
req = NewRequest(t, "OPTIONS", "/login/oauth/userinfo")
resp = MakeRequest(t, req, http.StatusMethodNotAllowed)
assert.NotContains(t, resp.Header().Values("Vary"), "Origin")
})
})
t.Run("CORS disabled", func(t *testing.T) {
defer test.MockVariableValue(&setting.CORSConfig.Enabled, false)()
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
t.Run("API without CORS", func(t *testing.T) {
req := NewRequest(t, "GET", "/api/v1/version")
resp := MakeRequest(t, req, http.StatusOK)
assert.Empty(t, resp.Header().Get("Access-Control-Allow-Origin"))
assert.Empty(t, resp.Header().Values("Vary"))
req = NewRequest(t, "OPTIONS", "/api/v1/version").
SetHeader("Origin", "https://example.com").
SetHeader("Access-Control-Request-Method", "GET")
resp = MakeRequest(t, req, http.StatusMethodNotAllowed)
assert.Empty(t, resp.Header().Get("Access-Control-Allow-Origin"))
assert.Empty(t, resp.Header().Values("Vary"))
})
t.Run("Web without CORS", func(t *testing.T) {
req := NewRequest(t, "GET", "/login/oauth/userinfo")
resp := MakeRequest(t, req, http.StatusUnauthorized)
assert.Empty(t, resp.Header().Get("Access-Control-Allow-Origin"))
assert.NotContains(t, resp.Header().Values("Vary"), "Origin")
req = NewRequest(t, "OPTIONS", "/login/oauth/userinfo").
SetHeader("Origin", "https://example.com").
SetHeader("Access-Control-Request-Method", "GET")
resp = MakeRequest(t, req, http.StatusMethodNotAllowed)
assert.Empty(t, resp.Header().Get("Access-Control-Allow-Origin"))
assert.NotContains(t, resp.Header().Values("Vary"), "Origin")
})
})
} }

View File

@ -81,7 +81,7 @@ func TestCreateNewTagProtected(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
for _, release := range releases { for _, release := range releases {
err = repo_model.DeleteReleaseByID(db.DefaultContext, release.ID) _, err = db.DeleteByID[repo_model.Release](db.DefaultContext, release.ID)
assert.NoError(t, err) assert.NoError(t, err)
} }